`
lfwer
  • 浏览: 84184 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

springboot实现mybatis分布式事务(atomikos)

阅读更多

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

 

项目结构如下

 

增加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 name="com.atomikos" level="WARN" additivity="true">
            <AppenderRef ref="AsyncAppender"/>
            <AppenderRef ref="Console"/>
        </Logger>

 

 

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

 

  • 大小: 34.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics