之前在项目中由于数据源比较多,为了方便切换数据源使用了AbstractRoutingDataSource+JdbcTemplate。刚开始都是查询操作,没有事物操作,但后来出现了一个事物操作,在一个service方法里面总是无法成功切换数据源。从网上搜了下也没有搜到解决方案,最后没办法只能阅读源码自己解决,最终定位到了问题,并成功的解决该问题。
问题原因:
在一个事物方法里面,在获取connection的时候,会先将connection和dataSource绑定存在ThreadLocal变量中,在下次切换数据源获取新connection时,首先会从ThreadLocal变量中查看该数据源是否已经有在使用的connection,如果有的话,则将该connection直接返回。
而在绑定数据源的时候传入的dataSouce并不是具体的数据源,而是整个AbstractRoutingDataSource;所以在下一次获取新connection时,会将原来的connection返回
解决方案:
重写JdbcTemplate类,将getDataSource()方法重写,让其返回的是具体的子数据源 而不是整个的AbstractRoutingDataSource。
public class SpringJdbcTemplate extends JdbcTemplate{
@Override
public DataSource getDataSource() {
// TODO Auto-generated method stub
DynamicDataSource router = (DynamicDataSource) super.getDataSource();
DataSource acuallyDataSource = router.getAcuallyDataSource();
return acuallyDataSource;
}
public SpringJdbcTemplate(DataSource dataSource) {
super(dataSource);
}
}
AbstractRoutingDataSource的实现类
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getCurrentDsLookupKey();
}
public DataSource getAcuallyDataSource() {
Object lookupKey = determineCurrentLookupKey();
if(null == lookupKey) {
return this;
}
DataSource determineTargetDataSource = this.determineTargetDataSource();
return determineTargetDataSource==null ? this : determineTargetDataSource;
}
}
配置JdbcTemplate对象时,用自定义的SpringJdbcTemplate代替org.springframework.jdbc.core.JdbcTemplate
这样就解决了无法切换数据源的问题。
PS:通过阅读绑定部分的代码,发型通过实现org.springframework.core.InfrastructureProxy接口,实现getWrappedObject()方法,该方法中返回具体的dataSource应该也能解决问题,但没有具体测试过,如果有兴趣的话,可以自己尝试下,如果成功的话,希望在评论里给我回复下,谢谢!
刚开始写博客,有错误的地方希望指正,谢谢