目录
如何配置数据源
Spring Boot 做了哪些配置
DataSourceAutoConfiguration 配置 DataSource
DataSourceTransactionManagerAutoConfiguration 配置 DataSourceTransactionManager
JdbcTemplateAutoConfiguration 配置 JdbcTemplate
数据源相关配置属性
通⽤
- spring.datasource.url=jdbc:mysql://localhost/test
- spring.datasource.username=dbuser
- spring.datasource.password=dbpass
- spring.datasource.driver-class-name=com.mysql.jdbc.Driver(可选)
初始化内嵌数据库
- spring.datasource.initialization-mode=embedded|always|never
- spring.datasource.schema与spring.datasource.data确定初始化SQL⽂文件
- spring.datasource.platform=hsqldb | h2 | oracle | mysql | postgresql(与前者对应)
配置多数据源的注意事项
- 不同数据源的配置要分开
- 关注每次使⽤用的数据源
- 有多个DataSource时系统如何判断
- 对应的设施(事务、ORM等)如何选择DataSource
Spring Boot中的多数据源配置
⼿工配置两组 DataSource 及相关内容
与Spring Boot协同工作(二选⼀)
- 配置@Primary类型的Bean
- 排除Spring Boot的⾃动配置
- DataSourceAutoConfiguration
- DataSourceTransactionManagerAutoConfiguration
- JdbcTemplateAutoConfiguration
数据库连接池
连接池选择时的考量量点
- 可靠性
- 性能
- 功能
- 可运维性
- 可扩展性
- 其他
HikariCP
HikariCP 为什么快
1. 字节码级别优化(很多方法通过 JavaAssist 生成)
2. ⼤量小改进
- 用 FastStatementList 代替 ArrayList
- 无锁集合 ConcurrentBag
- 代理类的优化(⽐如,用 invokestatic 代替了 invokevirtual)
在 Spring Boot 2.x 中 默认使⽤用 HikariCP
spring.datasource.hikari.*
Spring Boot 1.x 默认使用 Tomcat 连接池,需要移除 tomcat-jdbc 依赖
- spring.datasource.type=com.zaxxer.hikari.HikariDataSource
常用 HikariCP 配置参数
常用配置
- spring.datasource.hikari.maximumPoolSize=10
- spring.datasource.hikari.minimumIdle=10
- spring.datasource.hikari.idleTimeout=600000
- spring.datasource.hikari.connectionTimeout=30000
- spring.datasource.hikari.maxLifetime=1800000
其他配置详见 HikariCP 官⽹网
https://github.com/brettwooldridge/HikariCP
Alibaba Druid
“Druid连接池是阿⾥巴巴开源的数据库连接池项目。Druid连接池为监控⽽生, 内置强⼤的监控功能,监控特性不影响性能。功能强⼤大,能防SQL注⼊入,内置 Logging能诊断Hack应⽤行为。” –Alibaba Druid 官⽅方介绍
实⽤的功能
- 详细的监控(真的是全面)
- ExceptionSorter,针对主流数据库的返回码都有支持
- SQL 防注⼊
- 内置加密配置 众多扩展点,⽅便进行定制
数据源配置
直接配置 DruidDataSource
通过 druid-spring-boot-starter
- spring.datasource.druid.*
Filter 配置
- spring.datasource.druid.filters=stat,config,wall,log4j (全部使⽤用默认值)
密码加密
- spring.datasource.password=<加密密码>
- spring.datasource.druid.filter.config.enabled=true
- spring.datasource.druid.connection-properties=config.decrypt=true;config.decrypt.key=<public-key>
SQL 防注入
- spring.datasource.druid.filter.wall.enabled=true
- spring.datasource.druid.filter.wall.db-type=h2
- spring.datasource.druid.filter.wall.config.delete-allow=false
- spring.datasource.druid.filter.wall.config.drop-table-allow=false
Druid Filter
- 用于定制连接池操作的各种环节
- 可以继承 FilterEventAdapter 以便便⽅方便便地实现 Filter
- 修改 META-INF/druid-filter.properties 增加 Filter 配置
通过 Spring JDBC 访问数据库
Spring 的 JDBC 操作类
spring-jdbc
- core,JdbcTemplate 等相关核心接⼝和类
- datasource,数据源相关的辅助类
- object,将基本的 JDBC 操作封装成对象
- support,错误码等其他辅助工具
简单的 JDBC 操作
JdbcTemplate
- query
- queryForObject
- queryForList
- update
- execute
SQL 批处理
JdbcTemplate
batchUpdate
- BatchPreparedStatementSetter
NamedParameterJdbcTemplate
batchUpdate
- SqlParameterSourceUtils.createBatch
了解 Spring 的抽象
Spring 的事务抽象
一致的事务模型
- JDBC/Hibernate/myBatis
- DataSource/JTA
事务抽象的核⼼接口
PlatformTransactionManager
• DataSourceTransactionManager
• HibernateTransactionManager
• JtaTransactionManager
TransactionDefinition
• Propagation
• Isolation
• Timeout
• Read-only status
事务传播特性
传播性 |
值 |
描述 |
PROPAGATION_REQUIRED |
0 |
当前有事务就⽤当前的,没有就⽤新的 |
PROPAGATION_SUPPORTS |
1 |
事务可有可无,不是必须的 |
PROPAGATION_MANDATORY |
2 |
当前一定要有事务,不然就抛异常 |
PROPAGATION_REQUIRES_NEW |
3 |
⽆论是否有事务,都起个新的事务 |
PROPAGATION_NOT_SUPPORTED |
4 |
不支持事务,按非事务⽅式运行 |
PROPAGATION_NEVER |
5 |
不支持事务,如果有事务则抛异常 |
PROPAGATION_NESTED |
6 |
当前有事务就在当前事务里里再起⼀个事务 |
事务隔离特性
隔离性 |
值 |
脏读 |
不可重复读 |
幻读 |
ISOLATION_READ_UNCOMMITTED |
1 |
√ |
√ |
√ |
ISOLATION_READ_COMMITTED |
2 |
× |
√ |
√ |
ISOLATION_REPEATABLE_READ |
3 |
× |
× |
√ |
ISOLATION_SERIALIZABLE |
4 |
× |
× |
× |
编程式事务
TransactionTemplate
- TransactionCallback
- TransactionCallbackWithoutResult
PlatformTransactionManager 可以传⼊TransactionDefinition进行定义
声明式事务
基于注解的配置⽅方式
开启事务注解的⽅方式
- @EnableTransactionManagement
- <tx:annotation-driven/>
一些配置
- proxyTargetClass
- mode
- order
@Transactional
- transactionManager
- propagation
- isolation
- timeout
- readOnly
- 怎么判断回滚
Spring 的 JDBC 异常抽象
Spring 会将数据操作的异常转换为 DataAccessException ,无论使用何种数据访问⽅方式,都能使⽤一样的异常
Spring 通过 SQLErrorCodeSQLExceptionTranslator 解析错误码
ErrorCode 定义
- org/springframework/jdbc/support/sql-error-codes.xml
- Classpath 下的 sql-error-codes.xml
错误码解析逻辑可定制
O/R Mapping 实践
常⽤的 Bean 注解
通过注解定义 Bean
@Component
@Repository
@Service
@Controller
- @RestController
认识 Spring Data JPA
对象与关系的范式不匹配
|
Object |
RDBMS |
粒度 |
类 |
表 |
继承 |
有 |
没有 |
唯⼀性 |
a == b a.equals(b) |
主键 |
关联 |
引⽤用 |
外键 |
数据访问 |
逐级访问 |
SQL 数量要少 |
Hibernate
一款开源的对象关系映射(Object / Relational Mapping)框架
将开发者从 95% 的常⻅数据持久化⼯作中解放出来
屏蔽了底层数据库的各种细节
Hibernate 发展历程
2001年,Gavin King 发布第⼀个版本
2003年,Hibernate 开发团队加入 JBoss
2006年,Hibernate 3.2 成为 JPA 实现
Java Persistence API
JPA 为对象关系映射提供了⼀种基于 POJO 的持久化模型
- 简化数据持久化代码的开发工作
- 为 Java 社区屏蔽不不同持久化 API 的差异
2006 年,JPA 1.0 作为 JSR 220 的⼀部分正式发布
Spring Data
在保留底层存储特性的同时,提供相对⼀致的、基于 Spring 的编程模型
主要模块
- Spring Data Commons
- Spring Data JDBC
- Spring Data JPA
- Spring Data Redis ……
常⽤ JPA 注解
实体
- @Entity、@MappedSuperclass
- @Table(name)
主键
@Id
- @GeneratedValue(strategy, generator)
- @SequenceGenerator(name, sequenceName)
映射
- @Column(name, nullable, length, insertable, updatable)
- @JoinTable(name)、@JoinColumn(name)
关系
- @OneToOne、@OneToMany、@ManyToOne、@ManyToMany
- @OrderBy
Project Lombok
Project Lombok 能够⾃动嵌入 IDE 和构建工具,提升开发效率
常用功能
- @Getter / @Setter
- @ToString
- @NoArgsConstructor / @RequiredArgsConstructor / @AllArgsConstructor
- @Data
- @Builder
- @Slf4j / @CommonsLog / @Log4j2
Spring Data JPA 的基本用法
Repository
@EnableJpaRepositories
Repository<T, ID> 接口
- CrudRepository<T, ID>
- PagingAndSortingRepository<T, ID>
- JpaRepository<T, ID>
定义查询
根据方法名
- find…By… / read…By… / query…By… / get…By…
- count…By…
- …OrderBy…[Asc / Desc]
- And / Or / IgnoreCase
- Top / First / Distinct
分页查询
- PagingAndSortingRepository<T, ID>
- Pageable / Sort
- Slice<T> / Page<T>
Repository 是怎么从接口变成 Bean 的
Repository Bean 是如何创建的
JpaRepositoriesRegistrar
- 激活了 @EnableJpaRepositories
- 返回了 JpaRepositoryConfigExtension
RepositoryBeanDefinitionRegistrarSupport.registerBeanDefinitions
- 注册 Repository Bean(类型是 JpaRepositoryFactoryBean )
RepositoryConfigurationExtensionSupport.getRepositoryConfigurations
- 取得 Repository 配置
JpaRepositoryFactory.getTargetRepository
- 创建了 Repository
接⼝中的⽅法是如何被解释的
RepositoryFactorySupport.getRepository 添加了Advice
- DefaultMethodInvokingMethodInterceptor
- QueryExecutorMethodInterceptor
AbstractJpaQuery.execute 执行具体的查询
语法解析在 Part 中
通过 MyBatis 操作数据库
认识 MyBatis
MyBatis(https://github.com/mybatis/mybatis-3)
- 一款优秀的持久层框架
- 支持定制化 SQL、存储过程和高级映射
在 Spring 中使⽤用 MyBatis
- MyBatis Spring Adapter(https://github.com/mybatis/spring)
- MyBatis Spring-Boot-Starter(https://github.com/mybatis/spring-boot-starter)
简单配置
- mybatis.mapper-locations = classpath*:mapper/**/*.xml
- mybatis.type-aliases-package = 类型别名的包名
- mybatis.type-handlers-package = TypeHandler扫描包名
- mybatis.configuration.map-underscore-to-camel-case = true
Mapper 的定义与扫描
@MapperScan 配置扫描位置
@Mapper 定义接⼝ 映射的定义—— XML 与注解
让 MyBatis 更好用的那些⼯具 MyBatis Generator
认识 MyBatis Generator
MyBatis Generator(http://www.mybatis.org/generator/)
MyBatis 代码生成器
根据数据库表生成相关代码
- POJO
- Mapper 接⼝
- SQL Map XML
运⾏ MyBatis Generator
命令⾏
java -jar mybatis-generator-core-x.x.x.jar -configfile generatorConfig.xml
Maven Plugin(mybatis-generator-maven-plugin)
mvn mybatis-generator:generate
${basedir}/src/main/resources/generatorConfig.xml
Eclipse Plugin
Java 程序
Ant Task
配置 MyBatis Generator
generatorConfiguration
context
- jdbcConnection
- javaModelGenerator
- sqlMapGenerator
- javaClientGenerator (ANNOTATEDMAPPER / XMLMAPPER / MIXEDMAPPER)
- table
⽣成时可以使用的插件
内置插件都在 org.mybatis.generator.plugins 包中
- FluentBuilderMethodsPlugin
- ToStringPlugin
- SerializablePlugin
- RowBoundsPlugin
- ……
使用⽣成的对象
- 简单操作,直接使⽤生成的 xxxMapper 的⽅法
- 复杂查询,使⽤生成的 xxxExample 对象
让 MyBatis 更好用的那些⼯具 —MyBatis PageHelper
认识 MyBatis PageHelper
MyBatis PageHepler(https://pagehelper.github.io)
- 支持多种数据库
- 支持多种分⻚方式
- SpringBoot 支持(https://github.com/pagehelper/pagehelper-spring-boot )
- pagehelper-spring-boot-starter
NoSQL 实践
Docker 容器辅助开发
优点:简化了重复搭建开发环境的工作、交付系统更更为流畅、伸缩性更更好。
在本地的基本⽤法:
镜像相关
• docker pull <image>
• docker search <image>
容器相关
• docker run
• docker start/stop <容器器名>
• docker ps <容器器名>
• docker logs <容器器名>
docker run 的常⽤用选项
docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
选项说明
- -d,后台运行容器
- -e,设置环境变量量
- –expose / -p 宿主端口:容器端口
- –name,指定容器名称
- –link,链接不同容器
- -v 宿主目录:容器⽬录,挂载磁盘卷
国内 Docker 镜像配置
官⽅ Docker Hub
• https://hub.docker.com
官⽅方镜像
• 镜像 https://www.docker-cn.com/registry-mirror
• 下载 https://www.docker-cn.com/get-docker
阿⾥里里云镜像
https://dev.aliyun.com
Docker 常⽤命令
通过 Docker 启动 MongoDB
官⽅指引
• https://hub.docker.com/_/mongo
获取镜像
• docker pull mongo
运行 MongoDB 镜像
• docker run –name mongo -p 27017:27017 -v ~/docker-
data/mongo:/data/db -e MONGO_INITDB_ROOT_USERNAME=admin
-e MONGO_INITDB_ROOT_PASSWORD=admin -d mongo
通过 Docker 启动 MongoDB
登录到 MongoDB 容器中
• docker exec -it mongo bash
通过 Shell 连接 MongoDB
• mongo -u admin -p admin
Spring Data MongoDB 的基本⽤法
在 Spring 中访问 MongoDB
Spring 对 MongoDB 的支持
MongoDB 是一款开源的文档型数据库
• https://www.mongodb.com
Spring 对 MongoDB 的支持
Spring Data MongoDB
- MongoTemplate
- Repository ⽀持
Spring Data MongoDB 的基本⽤用法
注解
- @Document
- @Id
MongoTemplate
- save / remove
- Criteria / Query / Update
初始化 MongoDB 的库及权限 创建库
use springTest;
创建⽤用户
db.createUser(
{
user: “test”,
pwd: “test”,
roles: [
{ role: “readWrite”, db: “springTest” }
]
} )
Spring Data MongoDB 的 Repository
@EnableMongoRepositories
对应接口
- MongoRepository<T, ID>
- PagingAndSortingRepository<T, ID>
- CrudRepository<T, ID>
Spring Data Redis 的基本⽤法
在 Spring 中访问 Redis
Spring 对 Redis 的⽀持 Redis 是⼀一款开源的内存 KV 存储,⽀支持多种数据结构
• https://redis.io
Spring 对 Redis 的支持
• Spring Data Redis
- 支持的客户端 Jedis / Lettuce
- RedisTemplate
- Repository ⽀支持
Jedis 客户端的简单使⽤
- Jedis 不是线程安全的
- 通过 JedisPool 获得 Jedis 实例
- 直接使⽤用 Jedis 中的⽅方法
Jedis 客户端的简单使用
通过 Docker 启动 Redis
官⽅指引
• https://hub.docker.com/_/redis
获取镜像
• docker pull redis
启动 Redis
• docker run –name redis -d -p 6379:6379 redis
Redis 的几种运⾏模式
Redis 的哨兵与集群模式
Redis 的哨兵模式 Redis Sentinel 是 Redis 的一种⾼可用方案
• 监控、通知、⾃自动故障转移、服务发现
JedisSentinelPool
Redis 的集群模式
Redis Cluster
- 数据自动分片(分成16384个 Hash Slot )
- 在部分节点失效时有⼀一定可⽤用性
JedisCluster
• Jedis 只从 Master 读数据,如果想要⾃自动读写分离,可以定制
Spring 的缓存抽象
为不同的缓存提供一层抽象
• 为 Java ⽅法增加缓存,缓存执行结果
• 支持ConcurrentMap、EhCache、Caffeine、JCache(JSR-107)
• 接⼝
- org.springframework.cache.Cache
- org.springframework.cache.CacheManager
基于注解的缓存
@EnableCaching
- @Cacheable
- @CacheEvict
- @CachePut
- @Caching
- @CacheConfig
通过 Spring Boot 配置 Redis 缓存
Redis 在 Spring 中的其他用法
与 Redis 建立连接
配置连接⼯厂
• LettuceConnectionFactory 与 JedisConnectionFactory
- RedisStandaloneConfiguration
- RedisSentinelConfiguration
- RedisClusterConfiguration
读写分离
Lettuce 内置支持读写分离
- 只读主、只读从
- 优先读主、优先读从
LettuceClientConfiguration
LettucePoolingClientConfiguration
LettuceClientConfigurationBuilderCustomizer
RedisTemplate
RedisTemplate<K, V>
• opsForXxx()
StringRedisTemplate
一定注意设置过期时间!!!
Redis Repository
实体注解
- @RedisHash
- @Id
- @Indexed
处理不同类型数据源的 Repository
如何区分这些 Repository
- 根据实体的注解
- 根据继承的接⼝类型
- 扫描不同的包
Project Reactor
Project Reactor 介绍
“在计算机中,响应式编程或反应式编程(英语:Reactive Programming)是一种面向数据流和变化传播的编程范式。这意味着可以在编程语⾔中很⽅便地表达静态或动态的数据流, ⽽相关的计算模型会自动将变化的值通过数据流进⾏传播。”
——维基百科
Project Reactor ⼀些核⼼的概念
Operators – Publisher / Subscriber
• Nothing Happens Until You subscribe()
• Flux [ 0..N ] – onNext()、onComplete()、onError()
• Mono [ 0..1 ] – onNext()、onComplete()、onError()
Backpressure
• Subscription
• onRequest()、onCancel()、onDispose()
线程调度 Schedulers
• immediate() / single() / newSingle()
• elastic() / parallel() / newParallel()
错误处理
• onError / onErrorReturn / onErrorResume
• doOnError / doFinally
通过 Reactive 的⽅式访问 NoSQL
通过 Reactive 的⽅式访问数据 Redis
Spring Data Redis
Lettuce 能够支持 Reactive ⽅式
Spring Data Redis 中主要的支持
• ReactiveRedisConnection
• ReactiveRedisConnectionFactory
• ReactiveRedisTemplate
- opsForXxx()
通过 Reactive 的⽅式访问数据 MongoDB
Spring Data MongoDB
MongoDB 官⽅提供了⽀持 Reactive 的驱动
• mongodb-driver-reactivestreams
Spring Data MongoDB 中主要的⽀支持
• ReactiveMongoClientFactoryBean
• ReactiveMongoDatabaseFactory
• ReactiveMongoTemplate
通过 Reactive 的⽅式访问数据 RDBMS
Spring Data R2DBC
R2DBC (https://spring.io/projects/spring-data-r2dbc)
• Reactive Relational Database Connectivity
支持的数据库
• Postgres(io.r2dbc:r2dbc-postgresql)
• H2(io.r2dbc:r2dbc-h2)
• Microsoft SQL Server(io.r2dbc:r2dbc-mssql)
Spring Data R2DBC
一些主要的类
• ConnectionFactory
• DatabaseClient
- execute().sql(SQL)
- inTransaction(db -> {})
• R2dbcExceptionTranslator
- SqlErrorCodeR2dbcExceptionTranslator
R2DBC Repository 支持
一些主要的类
• @EnableR2dbcRepositories
• ReactiveCrudRepository<T, ID>
- @Table / @Id
- 其中的方法返回都是 Mono 或者 Flux
- 自定义查询需要⾃己写 @Query
Spring AOP 的基本概念
通过 AOP 打印数据访问层摘要
Spring AOP 的⼀些核心概念
概念 |
含义 |
Aspect |
切面 |
Join Point |
连接点,Spring AOP里总是代表一次⽅法行行 |
Advice |
通知,在连接点执行的动作 |
Pointcut |
切入点,说明如何匹配连接点 |
Introduction |
引入,为现有类型声明额外的⽅法和属性 |
Target object |
⽬标对象 |
AOP proxy |
AOP 代理对象,可以是 JDK 动态代理,也可以是 CGLIB 代理 |
Weaving |
织入,连接切面与⽬标对象或类型创建代理的过程 |
常用注解
- @EnableAspectJAutoProxy
- @Aspect
- @Pointcut
- @Before
- @After / @AfterReturning / @AfterThrowing
- @Around
- @Order
监控 DAO 层的简单方案
- 如何打印 SQL
HikariCP
• P6SQL,https://github.com/p6spy/p6spy
Alibaba Druid
• 内置 SQL 输出
• https://github.com/alibaba/druid/wiki/Druid中使用log4j2进⾏日志输出