背景:项目中使用了两个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注解哦。
相关推荐
Spring Boot:mybatis-plus + atomikos + druid 实现不同实例数据库的多数据源配置和分布式事务管理(demo项目),想到工作上可能会用到多数据源,但是自己在这方面并不是很熟悉,于是在网上查阅了很多文章,结果...
springboot-jpa hibernate,mybatis +atomikos 多数据库事务管理 springboot2.05版本,该项目实现mybatis,hibernate多数据源事务的控制
springboot+mybatis+druid+atomikos 多数据源,分布式事务,集成websocket,redis,swagger2
使用atomikos,mybaits,mysql,druid,springboot实现的两阶段提交分布式事务,真实能够运行,放心下载
SpringBoot集成Atomikos使用Oracle数据库mybatisSpringBoot集成Atomikos使用Oracle数据库mybatisSpringBoot集成Atomikos使用Oracle数据库mybatisSpringBoot集成Atomikos使用Oracle数据库mybatis
springboot+Atomikos+jpa+mysql的JTA分布式事务实现,本案例涉及到2个数据库,预期结果,在同一个事务中,两个库的状态一致
本用例基于 Spring Boot + Druid + Mybatis 配置多数据源,并采用 JTA 实现分布式事务。
1 环境 (1) 数据库 CREATE TABLE `t_student` ( `n_id` int(11) NOT NULL AUTO_INCREMENT, `c_name` varchar(255) DEFAULT NULL, `c_age` int(12) DEFAULT NULL, PRIMARY KEY (`n_id`) USING BTREE ...
springboot该项目是基于springboot进行配置,包括了数据库配置,aop配置,多数据库和分布式事务配置数据库配置:jdbc,jpa,mybatis(注解和mapper文件)mvn mybatis-generator:generate 代码生成器配置多数据库的配置,...
spring+mybatis+atomikos,java分布式事务。 由于网上的多数据源事务的帖子大多是2010年以前的,现在spring都已经到4.X了,有些类已经弃用了。 原先很多都是用jotm实现的,但是由于spring的升级,totm的本地化实例...
springboot整合多数据源,使用jta+atomikos解决多数据源分布式事务,使用springboot+mybatis-plus(简化sql代码)+swagger(api接口可视化)技术
实现单表业务零SQL集成Atomikos支持分布式事务,以及支持多数据源配置统一异常处理统一响应结果封装基于JWT实现基于Token的鉴权机制使用Druid Spring Boot Starter集成Druid数据库连接池与监控使用AutoGenerator快速...
jee-boot-api是一个基于SpringBoot ,快速构建的RESTful API工程的脚手架,能够满足90%公司90%的需求,支持多数据源配置,分布式事务,多Redis配置,分布式调度,分布式缓存配置等;快速生成各模块的基础代码,极...