多数据源事务控制
在多数据源下,由于涉及到数据库的多个读写。一旦发生异常就可能会导致数据不一致的情况,在这种情况希望使用事务进行回退。但是Spring的声明式事务在一次请求线程中只能使用一个数据源进行控制
但是对于多源数据库:
- 单一事务管理器(TransactionManager)无法切换数据源,需要配置多个TransactionManager。
- @Transactionnal是无法管理多个数据源的。 如果想真正实现多源数据库事务控制,肯定是需要分布式事务。 这里讲解多源数据库事务控制的一种变通方式。
@Bean
public DataSourceTransactionManager transactionManager1(DynamicDataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
@Bean
public DataSourceTransactionManager transactionManager2(DynamicDataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
只使用主库TransactionManger
使用主库事务管理器,也就是说事务中产生异常时,只能回滚主库数据。但是因为数据操作顺序是先主后从,所以分一下三种情况:
- 主库插入时异常,主库未插成功,这时候从库还没来及插入,主从数据是还是一致的
- 主库插入成功,从库插入时异常,这时候在主库事务管理器监测到事务中存在异常,将之前插入的主库数据插入,主从数据还是一致的
- 主库插入成功,从库插入成功,事务结束,主从数据一致。
@Override
@WR("W")
public void save(Frend frend) {
frendMapper.save(frend);
//int a=1/0; 1.主库插入时异常,主库未插成功,这时候从库还没来及插入,主从数据是还是一致的
}
@Override
@WR("R")
@Transactional(
transactionManager = "transactionManager2",propagation= Propagation.REQUIRES_NEW)
public void saveRead(Frend frend) {
frend.setName("xushu");
frendMapper.save(frend);
// int a=1/0; 2.主库插入成功,从库插入时异常,这时候在主库事务管理器监测到事务中存在异常,将之前插入的主库数据插入,主从数据还是一致的
}
@Override
@Transactional(transactionManager = "transactionManager1")
public void saveAll(Frend frend) {
// 3. 无异常情况:主库插入成功,从库插入成功,事务结束,主从数据一致。
FrendService self= (FrendService)AopContext.currentProxy();
self.save(frend);
self.saveRead(frend);
//int a=1/0; 从库插入之后出现异常, 只能回滚主库数据 ,从库数据是无法回滚的 , 数据将不一致
}
当然这只是理想情况,例外情况:
4.从库插入之后出现异常, 只能回滚主库数据 ,从库数据是无法回滚的 , 数据将不一致
5.从库数据插入成功后,主库提交,这时候主库崩溃了,导致数据没插入,这时候从库数据也是无法回滚的。这种方式可以简单实现多源数据库的事务管理,但是无法处理上述情况。
一个方法开启2个事务
spring编程式事务
// 读‐‐ 写库
@Override
public void saveAll(Frend frend) {
wtransactionTemplate.execute(wstatus ‐> {
rtransactionTemplate.execute(rstatus ‐> {
try{
saveW(frend);
saveR(frend);
int a=1/0;
return true;
}
catch (Exception e){
wstatus.setRollbackOnly();
rstatus.setRollbackOnly();
return false;
}
});
return true;
});
}
spring声明式事务
@Transactional
@Transactional(transactionManager = "wTransactionManager")
public void saveAll(Frend frend) throws Exception {
FrendService frendService = (FrendService) AopContext.currentProxy();
frendService.saveAllR(frend);
}
@Transactional(transactionManager = "rTransactionManager",propagation = Propagation.REQUIRES_NEW )
public void saveAllR(Frend frend) {
saveW(frend);
saveR(frend);
int a = 1 / 0;
}