编程式事务控制
注入transactionManager
@Bean
public DataSourceTransactionManager rTransactionManager(){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(rDataSource());
return dataSourceTransactionManager;
}
注入transactionTemplate
@Bean
public TransactionTemplate rTransactionTemplate(){
return new TransactionTemplate(rTransactionManager());
}
开始事务控制
@EnableTransactionManagement // 开启事务
具体使用
@Autowired
TransactionTemplate rTransactionTemplate;
@Autowired
TransactionTemplate wTransactionTemplate;
@Override
public void saveAll(Frend frend) {
wTransactionTemplate.execute(wstatus->{
rTransactionTemplate.execute(rstatus->{
try{
wFrendMapper.save(frend);
rFrendMapper.save(frend);
int i=1/0;
//r库提交
return true;
}catch (Exception e){
e.printStackTrace();
wstatus.setRollbackOnly(); //注意此处是set 回滚方法
rstatus.setRollbackOnly();
return false;
}
});
// 主库执行成功,提交。
return true;
});
}
声明式事务控制
开启事务注解
@EnableTransactionManagement // 开启事务
具体使用
/**
* 2. Spring中七种Propagation类的事务属性详解: *
* REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 *
* SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 *
* MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。 *
* REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。 *
* NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 *
* NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。 *
* NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。
* ————————————————
* spring 事务:https://blog.csdn.net/sayoko06/article/details/79164858
*/
@Transactional(transactionManager = "wTransactionManager")
@Override
public void saveAll(Frend frend) {
// 此处是获取当前类的代理类,如果使用this.saveAllR()则会导致rTransactionManager事务没有没被spring管理,会导致从库事务回滚异常。
FrendService frendService = (FrendService) AopContext.currentProxy();
frendService.saveAllR(frend);
}
@Transactional(transactionManager = "rTransactionManager",
propagation = Propagation.REQUIRES_NEW) //新建事务,如果当前存在事务,把当前事务挂起。
@Override
public void saveAllR(Frend frend) {
wFrendMapper.save(frend);
rFrendMapper.save(frend);
int i = 1 / 0;
return;
}
框架事务控制
使用【dynamic-datasource】框架进行事务控制
引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.0</version>
</dependency>
数据源配置
spring:
datasource:
dynamic:
#设置默认的数据源或者数据源组,默认值即为master
primary: mysql
#严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
strict: false
datasource:
mysql:
url: jdbc:mysql://127.0.0.1:3306/shiguang?serverTimezone=CST&useSSL=false&rewriteBatchedStatements=true
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
## 最小空闲连接数
minimum-idle: 5
# ## 最大连接数
# maximum-pool-size: 20
## 自动提交
auto-commit: true
## 连接池名称
pool-name: TmcHikariCP
## 超时时间(ms)
connection-timeout: 30000
## 超时测试语句
connection-test-query: select now()
sqlServer:
url: jdbc:sqlserver://127.0.0.1:1433;databasename=bqwms
username: sa
password: 1qaz@WSX
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
具体使用
@Override
@DS("master")
public void save(Frend frend) {
frendMapper.save(frend);
}
@DS("master")
@DSTransactional
public void saveAll(){
// 执行多数据源的操作
}
原理解析
- 1.通过DynamicDataSourceAutoConfiguration自动配置类,
-
- 配置了DynamicRoutingDataSource 它就相当于我们之前自定义的那个DynamicDataSource, 用来动态提供数据源
-
- 配置DynamicDataSourceAnnotationAdvisor 就相当于 之前 自定义的一个切面类
- 4.设置DynamicDataSourceAnnotationInterceptor 当前advisor的拦截器 , 把它理解成之前环绕通知
-
- 当执行方法会调用DynamicDataSourceAnnotationInterceptor#invoke 来进行增强:
- 当执行方法会调用DynamicDataSourceAnnotationInterceptor#invoke 来进行增强:
-
- 在执行数据库操作时候, 就会调用DataSource.getConnection, 此时的DataSource指的就是DynamicRoutingDataSource
-
- 然后执行模板方法