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