spring事务内切换数据源失效解决办法


项目:人人开源  多数据源

<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>2.5.5</version>
</dependency>

问题:    多数据源在事务下不生效
问题原因:    spring检测到如果开启了事务,会将Connection缓存起来,然后在事务再执行第二条sql时候,继续使用之前缓存好的Connection

临时解决方案:
1.不在事务内进行多数据源的切换(废话)
2.添加注解,当前方法不在事务内运行
    //当前方法不会运行在事务内,如果在事务内,则将事务挂起
  

  @Transactional(propagation = Propagation.NOT_SUPPORTED)


3.异步(网上答案,亲测失败)

PS.以上方案在分布式中无效

源头解决方案:
1、从源头解决问题,我们在往Spring容器注册事务管理器的时候,就可以更改其默认的事务管理器,从而Spring在选择到该数据源的时候就知道用哪一个事务管理器了。下面是相应的配置代码   

    @Autowired
    @Qualifier("ADataSource")
    private DataSource ADS;
 
  @Bean
    public PlatformTransactionManager uiTransactionManager() {
        DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(ADS);
return transactionManager;
    }

 


2、在使用 Transactional 注解的时候,我们会发现里面有一个值叫 value,也就是 transactionManager 的别名,在这里指定加载的事务管理器,也可以达到指定的效果。代码如下:
@Configuration
@EnableTransactionManagement
@MapperScan(basePackages = "*.*.*.B",sqlSessionTemplateRef = "BSqlSessionTemplate")
public class BDataSourceConfig {
 
    @Autowired
    @Qualifier("BDataSource")
    private DataSource BDS;
 
    @Bean
    public SqlSessionFactory mgSqlSessionFactory() throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        tk.mybatis.mapper.session.Configuration configuration = new tk.mybatis.mapper.session.Configuration();
        configuration.setMapUnderscoreToCamelCase(true);
        bean.setConfiguration(configuration);
        bean.setDataSource(BDS);
        bean.setTypeAliasesPackage("*.*.*.B");
        bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:*.xml"));
        return bean.getObject();
    }
 
    //  Spring注册Bean中,方法名即为Bean的名字
    @Bean
    public PlatformTransactionManager BTransactionManager() {
        return new DataSourceTransactionManager(BDS);
    }
 
    @Bean
    public SqlSessionTemplate BSqlSessionTemplate(@Qualifier("BSqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
 
}
 
 
--------配置代码结束--------
 
-------业务代码开始---------
@Transactional(value = "BTransactionManager")
public void test(){
}
-------业务代码结束---------

3、手动控制事务管理器,和上面一种方案类似,但是这种方案更具源码性吧,不用了Spring原生的 @Transactional 而改用自己实现的方式:

// 由于是多数据源,因此会有多个事务管理器,因此用Resource根据名称的注入方式更为合理
    @Resource
    PlatformTransactionManager ATransactionManager;
    @Transactional(rollbackFor = Exception.class)
    public boolean addMenu(MenuRequest request){
        TransactionStatus status = ATransactionManager.getTransaction(new DefaultTransactionDefinition());
        try {
            /** 业务代码 **/
        }catch (Exception e){
            log.error("addMenu {}",e);
            ATransactionManager.rollback(status);
            return false;
        }
        ATransactionManager.commit(status);
        return true;
    }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM