java.lang.IllegalStateException: No value for key [DynamicDataSource@e5f43124] bound to thread

应用场景描述:

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版权协议,转载请附上原文出处链接和本声明。