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应该也能解决问题,但没有具体测试过,如果有兴趣的话,可以自己尝试下,如果成功的话,希望在评论里给我回复下,谢谢!

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

猜你喜欢

转载自blog.csdn.net/jackycjw/article/details/80506340