应用场景描述:
Spring 5+atomikos+JdbcTemplate+DynamicDataSource 多数据源动态切换

跟踪原代码,有如下发现:
在TransactionSynchronizationManager这个类中,

有一个resources。里面存的东西如图:

当事务开启时,事务里的相关资源都会在这里记录一份,在事务提交之后,后依次调用
TransactionSynchronizationManager 里面的unbindResource方法。
值得注意的是,resources里面的key, 存的是动态数据源的指针,假设事务中涉及两个数据源A和B,那么,在resources中存放的key只有一个

当根据xa数据源unbindResource时,会解绑两次,但是resource中只有一个key,所以第二次解绑时,找不到对应的key,就会报错。
按照我们的设想,如果resources里面的key是我们的真实目标数据源的名字A和B,那么解绑时也根据A和B来解绑,就能解决这个问题。
1、改造动态数据源
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
public Object determineCurrentLookupKey() {
String peek = DynamicContextHolder.peek();
if(peek == null){
peek = "default_datasource_name";
}
return peek;
}
@Override
public int hashCode() {
// return this.determineCurrentLookupKey().hashCode();
String peek = (String)this.determineCurrentLookupKey();
AtomikosDataSourceBean dataSourceBean = (AtomikosDataSourceBean)DynamicDataSourceFactory.getDynamicTargetDataSources().get(peek);
return dataSourceBean.getUniqueResourceName().hashCode();
}
@Override
protected DataSource determineTargetDataSource() {
String peek = (String)this.determineCurrentLookupKey();
AtomikosDataSourceBean dataSourceBean = (AtomikosDataSourceBean)DynamicDataSourceFactory.getDynamicTargetDataSources().get(peek);
return dataSourceBean;
}
}2、改造jdbcTemplate, 重写obtainDataSource方法,这个方法就是在resources中放置资源时,用真实的数据源做为KEY
public class JdbcTemplate extends org.springframework.jdbc.core.JdbcTemplate {
JdbcTemplate(DynamicDataSource dataSource){
super(dataSource);
}
@Override
protected DataSource obtainDataSource() {
DynamicDataSource dataSource = (DynamicDataSource)super.obtainDataSource();
return dataSource.determineTargetDataSource();
}
}3、注入jdbcTemplate
@Bean
public JdbcTemplate jdbcTemplate(DynamicDataSource dynamicDataSource) {
return new JdbcTemplate(dynamicDataSource);
}
版权声明:本文为nicky2406062123原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。