简概
数据库连接所需的bean
-
数据源相关
- DataSource(根据选择的连接池实现决定)
- 事务相关(可选)
- PlatformTransactionManager(DataSourceTransactionManager)
- TransactionTemplate
-
操作相关(可选)
- JdbcTemplate
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(可选)
配置多数据源
注意事项
-
不同数据源的配置要分开
-
关注每次使⽤的数据源
- 有多个DataSource时系统如何判断
- 对应的设施(事务、ORM等)如何选择DataSource
Spring Boot中的多数据源配置
-
配置@Primary类型的Bean
-
排除Spring Boot的⾃动配置
DataSourceAutoConfiguration
DataSourceTransactionManagerAutoConfiguration
JdbcTemplateAutoConfiguration
- 示例代码
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class})
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
@ConfigurationProperties("demo01.datasource")
public DataSourceProperties demo01DataSourceProperties(){
return new DataSourceProperties();
}
@Bean
public DataSource demo01DataSource(){
DataSourceProperties dataSourceProperties=demo01DataSourceProperties();
return dataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean
@Resource // 表明这个方法的参数要按照名字来注入其他的Bean
public PlatformTransactionManager demo01Manager(DataSource demo01DataSource){
return new DataSourceTransactionManager(demo01DataSource);
}
@Bean
@ConfigurationProperties("demo02.datasource")
public DataSourceProperties demo02DataSourceProperties(){
return new DataSourceProperties();
}
@Bean
public DataSource demo02DataSource(){
DataSourceProperties dataSourceProperties=demo02DataSourceProperties();
return dataSourceProperties.initializeDataSourceBuilder().build();
}
@Bean
@Resource
public PlatformTransactionManager demo02Manager(DataSource demo02DataSource){
return new DataSourceTransactionManager(demo02DataSource);
}
}
- application.properties配置文件
management.endpoints.web.exposure.include=*
demo01.datasource.url=jdbc:test:demo01
demo01.datasource.username=shua
demo01.datasource.password=
demo02.datasource.url=jdbc:test:demo02
demo02.datasource.username=shua
demo02.datasource.password=
- 通过actuator查看bean。 https://www.yuque.com/shuashua-qihie/ymgqvk/linz48
连接池
HikariCP
官网:https://github.com/brettwooldridge/HikariCP
在 Spring Boot 中的配置
-
Spring Boot 2.x
- 默认使⽤ HikariCP
- 配置 spring.datasource.hikari.* 【可参考DataSourceConfiguration类】
-
配置 Spring Boot 1.x
- 默认使⽤ Tomcat 连接池,需要移除 tomcat-jdbc 依赖
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
【在application.properties配置文件中配置】
常⽤ HikariCP 配置参数
更多的可参考官网:https://github.com/brettwooldridge/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
Alibaba Druid
“Druid连接池是阿⾥巴巴开源的数据库连接池项⽬。Druid连接池为监控⽽⽣, 内置强⼤的监控功能,监控特性不影响性能。功能强⼤,能防SQL注⼊,内置 Logging能诊断Hack应⽤⾏为。
官网地址:https://github.com/alibaba/druid/wiki/首页
实用功能
- 详细的监控(真的是全⾯)
- ExceptionSorter,针对主流数据库的返回码都有⽀持
- SQL 防注⼊
- 内置加密配置
- 众多扩展点,⽅便进⾏定制
数据源配置
- 直接配置 DruidDataSource
- 通过引入
druid-spring-boot-starter
。 在application.properties
中配置spring.datasource.druid.*
相关信息。
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=shua
spring.datasource.password=n/z7PyA5cvcXvs8px8FVmBVpaRyNsvJb3X7YfS38DJrIg25EbZaZGvH4aHcnc97Om0islpCAPc3MqsGvsrxVJw==
spring.datasource.druid.initial-size=5
spring.datasource.druid.max-active=5
spring.datasource.druid.min-idle=5
spring.datasource.druid.filters=config,stat,slf4j
spring.datasource.druid.connection-properties=config.decrypt=true;config.decrypt.key=${public-key}
spring.datasource.druid.filter.config.enabled=true
spring.datasource.druid.test-on-borrow=true
spring.datasource.druid.test-on-return=true
spring.datasource.druid.test-while-idle=true
public-key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALS8ng1XvgHrdOgm4pxrnUdt3sXtu/E8My9KzX8sXlz+mXRZQCop7NVQLne25pXHtZoDYuMh3bzoGj6v5HvvAQ8CAwEAAQ==
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=
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,错误码等其他辅助⼯具
常⽤的 Bean 注解
@Component
@Repository
@Service
@Controller
@RestController
简单的 JDBC 操作
JdbcTemplate
query
queryForObject
queryForList
update execute
SQL 批处理
-
JdbcTemplate
-
batchUpdate
BatchPreparedStatementSetter
-
-
NamedParameterJdbcTemplate
batchUpdate
SqlParameterSourceUtils.createBatch
小tips:解决IDEA的错误提示
解决IDEA中 Could not autowire. No beans of ‘xxxx’ type found 的错误提示
这个错误提示有时并不会产生影响,程序的编译和运行都是没有问题的。但强迫症也是真的受不了。
修改IDEA设置,降低Autowired检测的级别,将Severity的级别由之前的error改成warning或其它可以忽略的级别。
Spring 的事务抽象
⼀致的事务模型
- JDBC/Hibernate/myBatis
- DataSource/JTA
事务抽象的核⼼接⼝
PlatformTransactionManager
,部分实现类如下:
DataSourceTransactionManager
HibernateTransactionManager
JtaTransactionManager
TransactionDefinition
,几种属性如下:(注意TransactionDefinition
是一个接口哦)
Propagation
Isolation
Timeout
Read-only status
事务传播特性
详情可查看TransactionDefinition接口
传播特性 | 属性值 | 注释 |
---|---|---|
PROPAGATION_REQUIRED | 0 | 当前有事务就用当前的,没有就用新的 |
PROPAGATION_SUPPORTS | 1 | 事务可有可无,不是必须的 |
PROPAGATION_MANDATORY | 2 | 当前一定要有事务,不然就抛异常 |
PROPAGATION_REQUIRES_NEW | 3 | 无论是否有事务,都起个新的事务 |
PROPAGATION_NOT_SUPPORTED | 4 | 不支持事务,按非事务方式运行 |
PROPAGATION_NEVER | 5 | 不支持事务,如果有事务则抛异常 |
PROPAGATION_NESTED | 6 | 当前有事务就在当前事务里再起一个事务 |
REQUIRES_NEW 与 NESTED 事务传播特性的说明
-
REQUIRES_NEW
,始终启动⼀个新事务 。- 两个事务没有关联 。
-
NESTED
,在原事务内启动⼀个内嵌事务。- 两个事务有关联
- 外部事务回滚,内嵌事务也会回滚
事务隔离级别
详情可查看TransactionDefinition接口,默认隔离级别为ISOLATION_DEFAULT,值为-1,即由具体的数据库决定隔离级别。
隔离性 | 属性值 | 注释 |
---|---|---|
ISOLATION_READ_UNCOMMITTED | 1 | 读未提交 |
ISOLATION_READ_COMMITTED | 2 | 读已提交 |
ISOLATION_REPEATABLE_READ | 4 | 可重复读 |
ISOLATION_SERIALIZABLE | 8 | 串行读 |
编程式事务
有两种实现方式:1. TransactionTemplate
类;2. PlatformTransactionManager
类
TransactionTemplate
类,调用execute()方法时可传入的对象:
- TransactionCallback
- TransactionCallbackWithoutResult
代码示例(仅展示了核心代码)
public void insert(){
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
String sql="INSERT INTO `user`(`username`) VALUES ('刷刷');";
jdbcTemplate.execute(sql);
System.out.println(selectAll());
status.setRollbackOnly();
}
});
System.out.println(selectAll());
}
PlatformTransactionManager
- 可以传⼊
TransactionDefinition
进⾏定义
具体使用可参考https://blog.youkuaiyun.com/z69183787/article/details/8463507
声明式事务
基于注解的配置⽅式
开启事务注解的⽅式
-
xml中:
<tx:annotation-driven/>
-
SpringBoot中:
@EnableTransactionManagement
,一些可配置属性如下proxyTargetClass
mode
order
使用事务
添加 @Transactional
注解即可。@Transactional
的一些可配置项:
transactionManager
propagation
isolation
timeout
readOnly
怎么判断回滚或者说何时回滚?
可通过@Transactional
的rollbackFor
属性指明当出现特定的异常时进行回滚。
事务失效demo
比如下述情况,调用insert()方法时,事务就不会进行回滚。原因在于动态代理。
事务生效策略:
事务操作实现的本质
- Spring 的声明式事务本质上是通过 AOP 来增强了类的功能。
- Spring 的 AOP 本质上就是为类做了⼀个代理。 看似在调⽤⾃⼰写的类,实际⽤的是增强后的代理类
问题的解法
- 访问增强后的代理类的⽅法,⽽⾮直接访问⾃身的⽅法
Spring 的 JDBC 异常抽象
概览
Spring 会将数据操作的异常转换为 DataAccessException
, ⽆论使⽤何种数据访问⽅式,都能使⽤⼀样的异常 。
Spring是怎么认识那些错误码的
通过 SQLErrorCodeSQLExceptionTranslator
解析错误码
ErrorCode 定义 的位置:
-
org/springframework/jdbc/support/sql-error-codes.xml
-
Classpath 下的
sql-error-codes.xml