AbstractRoutingDataSource数据源切换失败原因及解决方案

之前在项目中由于数据源比较多,为了方便切换数据源使用了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应该也能解决问题,但没有具体测试过,如果有兴趣的话,可以自己尝试下,如果成功的话,希望在评论里给我回复下,谢谢!

刚开始写博客,有错误的地方希望指正,谢谢

  • 10
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值