Springboot整合Atomikos

背景

项目中使用了两个 mysql 数据源,有一个功能是同时修改两个库里的表数据,需要进行事务控制。项目框架为 springcloud+mybatis。

项目结构

eece0e3f68dc51a3e27ba599c5b7f5f6.png

增加 maven 依赖

<!--分布式事务支持-->  
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-jta-atomikos</artifactId>  
</dependency>  
<!--lombok jar 自动get set-->  
<dependency>  
    <groupId>org.projectlombok</groupId>  
    <artifactId>lombok</artifactId>  
</dependency>

application.properties

#carinfo  
spring.datasource.carinfo.type=com.alibaba.druid.pool.DruidDataSource  
spring.datasource.carinfo.driverClassName=com.mysql.jdbc.Driver  
spring.datasource.carinfo.url=xxx  
spring.datasource.carinfo.username=xxx  
spring.datasource.carinfo.password=xxx  
spring.datasource.carinfo.maxActive=200  
spring.datasource.carinfo.minIdle=2  
spring.datasource.carinfo.initialSize=5  
spring.datasource.carinfo.maxWait=60000  
spring.datasource.carinfo.timeBetweenEvictionRunsMillis=60000  
spring.datasource.carinfo.minEvictableIdleTimeMillis=300000  
spring.datasource.carinfo.validationQuery=SELECT 1 FROM DUAL  
spring.datasource.carinfo.testWhileIdle=true  
spring.datasource.carinfo.testOnBorrow=false  
spring.datasource.carinfo.testOnReturn=false  
spring.datasource.carinfo.poolPreparedStatements=true  
spring.datasource.carinfo.maxPoolPreparedStatementPerConnectionSize=20  
spring.datasource.carinfo.filters=stat  
spring.datasource.carinfo.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000  

#emscartype  
spring.datasource.emscartype.type=com.alibaba.druid.pool.DruidDataSource  
spring.datasource.emscartype.driverClassName=com.mysql.jdbc.Driver  
spring.datasource.emscartype.url=xx  
spring.datasource.emscartype.username=xx  
spring.datasource.emscartype.password=xx  
spring.datasource.emscartype.maxActive=200  
spring.datasource.emscartype.minIdle=2  
spring.datasource.emscartype.initialSize=5  
spring.datasource.emscartype.maxWait=60000  
spring.datasource.emscartype.timeBetweenEvictionRunsMillis=60000  
spring.datasource.emscartype.minEvictableIdleTimeMillis=300000  
spring.datasource.emscartype.validationQuery=SELECT 1 FROM DUAL  
spring.datasource.emscartype.testWhileIdle=true  
spring.datasource.emscartype.testOnBorrow=false  
spring.datasource.emscartype.testOnReturn=false  
spring.datasource.emscartype.poolPreparedStatements=true  
spring.datasource.emscartype.maxPoolPreparedStatementPerConnectionSize=20  
spring.datasource.emscartype.filters=stat  
spring.datasource.emscartype.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000

DataSourceCarInfoProperties.java

package com.chinaway.ems.config.db;  

import lombok.Data;  
import org.springframework.boot.context.properties.ConfigurationProperties;  
import org.springframework.stereotype.Component;  

/** 
 * @Description: 
 * @ClassName: DataSourceCarInfoProperties 
 * @Author: Liu FangWei 
 * @Date: 2018/11/8 9:55 
 * @Version: 1.0 
 */  
@Component //自动注入  
@ConfigurationProperties(prefix = "spring.datasource.carinfo")  
@Data // lombok注解,生成getter/setter等方法  
public class DataSourceCarInfoProperties {  
    private String type;  
    private String driverClassName;  
    private String url;  
    private String username;  
    private String password;  
    private int minIdle;  
    private int maxActive;  
    private int maxWait;  
    private String filters;  
    private String connectionProperties;  

}

DataSourceEmsCarTypeProperties.java

package com.chinaway.ems.config.db;  

import lombok.Data;  
import org.springframework.boot.context.properties.ConfigurationProperties;  
import org.springframework.stereotype.Component;  

/** 
 * @Description: 
 * @ClassName: DataSourceCarInfoProperties 
 * @Author: Liu FangWei 
 * @Date: 2018/11/8 9:55 
 * @Version: 1.0 
 */  
@Component //自动注入  
@ConfigurationProperties(prefix = "spring.datasource.emscartype")  
@Data // lombok注解,生成getter/setter等方法  
public class DataSourceEmsCarTypeProperties {  
    private String type;  
    private String driverClassName;  
    private String url;  
    private String username;  
    private String password;  
    private int minIdle;  
    private int maxActive;  
    private int maxWait;  
    private String filters;  
    private String connectionProperties;  

}

DataSourceCarInfoConfig.java

package com.chinaway.ems.config.db;  

import javax.sql.DataSource;  

import com.alibaba.druid.pool.xa.DruidXADataSource;  
import org.apache.ibatis.session.SqlSessionFactory;  
import org.mybatis.spring.SqlSessionFactoryBean;  
import org.mybatis.spring.SqlSessionTemplate;  
import org.mybatis.spring.annotation.MapperScan;  
import org.springframework.beans.BeanUtils;  
import org.springframework.beans.factory.annotation.Autowired;  
import org.springframework.beans.factory.annotation.Qualifier;  
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.context.annotation.Primary;  

/** 
 * @Description: 
 * @ClassName: DataSourceCarInfoConfig 
 * @Author: Liu FangWei 
 * @Date: 2018/10/8 14:24 
 * @Version: 1.0 
 */  
@Configuration  
@MapperScan(basePackages = {"com.chinaway.ems.dao.carinfo"}, sqlSessionTemplateRef = "sqlSessionTemplateCarInfo")  
public class DataSourceCarInfoConfig {  

    @Bean(name = "dataSourceCarInfo")  
    public DataSource dataSourceCarInfo(DataSourceCarInfoProperties dataSourceCarInfoProperties) {  
        DruidXADataSource dataSource = new DruidXADataSource();  
        BeanUtils.copyProperties(dataSourceCarInfoProperties, dataSource);  
        AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();  
        xaDataSource.setXaDataSource(dataSource);  
        xaDataSource.setUniqueResourceName("dataSourceCarInfo");  
        return xaDataSource;  
    }  

    @Bean(name = "sqlSessionFactoryCarInfo")  
    public SqlSessionFactory sqlSessionFactoryCarInfo(@Qualifier("dataSourceCarInfo") DataSource dataSource)  
            throws Exception {  
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();  
        bean.setDataSource(dataSource);  
        bean.setTypeAliasesPackage("com.chinaway.ems.domain.carinfo");  
        //bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/car/*Mapper.xml"));  
        return bean.getObject();  
    }  

    @Bean(name = "sqlSessionTemplateCarInfo")  
    public SqlSessionTemplate sqlSessionTemplateCarInfo(  
            @Qualifier("sqlSessionFactoryCarInfo") SqlSessionFactory sqlSessionFactory) throws Exception {  
        return new SqlSessionTemplate(sqlSessionFactory);  
    }  

}

DataSourceEmsCarTypeConfig.java

package com.chinaway.ems.config.db;  

import com.alibaba.druid.pool.xa.DruidXADataSource;  
import org.apache.ibatis.session.SqlSessionFactory;  
import org.mybatis.spring.SqlSessionFactoryBean;  
import org.mybatis.spring.SqlSessionTemplate;  
import org.mybatis.spring.annotation.MapperScan;  
import org.springframework.beans.BeanUtils;  
import org.springframework.beans.factory.annotation.Qualifier;  
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.context.annotation.Primary;  

import javax.sql.DataSource;  

/** 
* @Description: 
* @ClassName: DataSourceEmsCarTypeConfig 
* @Author: Liu FangWei 
* @Date: 2018/10/8 14:24 
* @Version: 1.0 
*/  
@Configuration  
@MapperScan(basePackages = {"com.chinaway.ems.dao.emscartype"}, sqlSessionTemplateRef = "sqlSessionTemplateEmsCarType")  
public class DataSourceEmsCarTypeConfig {  

   @Primary  
   @Bean(name = "dataSourceEmsCarType")  
   public DataSource dataSourceEmsCarType(DataSourceEmsCarTypeProperties dataSourceEmsCarTypeProperties) {  
       DruidXADataSource dataSource = new DruidXADataSource();  
       BeanUtils.copyProperties(dataSourceEmsCarTypeProperties, dataSource);  
       AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();  
       xaDataSource.setXaDataSource(dataSource);  
       xaDataSource.setUniqueResourceName("dataSourceEmsCarType");  
       return xaDataSource;  
   }  

   @Bean(name = "sqlSessionFactoryEmsCarType")  
   public SqlSessionFactory sqlSessionFactoryEmsCarType(@Qualifier("dataSourceEmsCarType") DataSource dataSource)  
           throws Exception {  
       SqlSessionFactoryBean bean = new SqlSessionFactoryBean();  
       bean.setDataSource(dataSource);  
       bean.setTypeAliasesPackage("com.chinaway.ems.domain.emscartype");  
       //bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:/mapper/car/*Mapper.xml"));  
       return bean.getObject();  
   }  

   @Bean(name = "sqlSessionTemplateEmsCarType")  
   public SqlSessionTemplate sqlSessionTemplateEmsCarType(  
           @Qualifier("sqlSessionFactoryEmsCarType") SqlSessionFactory sqlSessionFactory) throws Exception {  
       return new SqlSessionTemplate(sqlSessionFactory);  
   }  

}

XATransactionManagerConfig.java

package com.chinaway.ems.config.db;  

import com.atomikos.icatch.jta.UserTransactionImp;  
import com.atomikos.icatch.jta.UserTransactionManager;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
import org.springframework.context.annotation.DependsOn;  
import org.springframework.transaction.PlatformTransactionManager;  
import org.springframework.transaction.annotation.EnableTransactionManagement;  
import org.springframework.transaction.jta.JtaTransactionManager;  

import javax.transaction.TransactionManager;  
import javax.transaction.UserTransaction;  

/** 
* @Description: 
* @ClassName: XATransactionManagerConfig 
* @Author: Liu FangWei 
* @Date: 2018/11/8 10:24 
* @Version: 1.0 
*/  
@Configuration  
@EnableTransactionManagement  
public class XATransactionManagerConfig {  

   @Bean(name = "userTransaction")  
   public UserTransaction userTransaction() throws Throwable {  
       UserTransactionImp userTransactionImp = new UserTransactionImp();  
       userTransactionImp.setTransactionTimeout(10000);  
       return userTransactionImp;  
   }  

   @Bean(name = "atomikosTransactionManager", initMethod = "init", destroyMethod = "close")  
   public TransactionManager atomikosTransactionManager() throws Throwable {  
       UserTransactionManager userTransactionManager = new UserTransactionManager();  
       userTransactionManager.setForceShutdown(false);  
       return userTransactionManager;  
   }  

   @Bean(name = "transactionManager")  
   @DependsOn({"userTransaction", "atomikosTransactionManager"})  
   public PlatformTransactionManager transactionManager() throws Throwable {  
       return new JtaTransactionManager(userTransaction(), atomikosTransactionManager());  
   }  

}

为了控制 atomikos 的日志输出目录,增加 transactions.properties

com.atomikos.icatch.service=com.atomikos.icatch.standalone.UserTransactionServiceFactory  
com.atomikos.icatch.log_base_dir=translogs  
com.atomikos.icatch.console_file_name=tm.out  
com.atomikos.icatch.log_base_name=tmlog  
com.atomikos.icatch.tm_unique_name=com.tlw.bpm.engine.atomikos.spring.jdbc.tm  
com.atomikos.icatch.console_file_limit=10000  
com.atomikos.icatch.console_file_count=10  
com.atomikos.icatch.max_timeout=600000  
com.atomikos.icatch.default_jta_timeout=120000  
com.atomikos.icatch.console_log_level=ERROR  
com.atomikos.icatch.enable_logging=false

因为 atomikos 频繁的输出日志,项目中用的 log4j2,通过配置 log4j2.xml 让 atomikos 只打印 warn 级别以上的日志

<Logger >  
   <AppenderRef ref="AsyncAppender"/>  
   <AppenderRef ref="Console"/>  
</Logger>

通过以上配置就可以实现 jta 了,记得在调用的 service 方法上加上 @Transactional 注解哦。


作者:lfwer

来源链接:

https://blog.csdn.net/lfwer/article/details/83901058

45a653c15d964a37661e73befe51f854.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值