springboot+atomikos+多数据源管理事务(mysql 8.0)
jta:Java Transaction API,即是java中对事务处理的api 即 api即是接口的意思
atomikos:Atomikos TransactionsEssentials 是一个为Java平台提供增值服务的并且开源类事务管理器
1.结构

2.pom依赖
我这里使用本地数据库是mysql8,
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<!--<version>2.0.0.RELEASE</version>-->
<version>2.1.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version><!-- 1.3.0以上的版本没有@MapperScan以及@Select注解 -->
</dependency>
<!-- automatic+jta的分布式事务管理 -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jta-atomikos -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--boot 2.1默认 mysql8的版本; boot 2.0默认mysql5版本-->
<version>8.0.13</version>
<!--<version>5.1.46</version>-->
<!--<scope>runtime</scope>-->
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency> </dependencies>
3.创建本地数据库+表

4.application.yml
server:
port: 8080
servlet:
# # 项目contextPath
context-path: /manyDatasource spring:
application:
name: manyDatasource
datasource:
# spring.datasource.test1
# druid:
test1:
# jdbc-url,url,jdbcurl哪个合适用哪个
jdbcurl: jdbc:mysql://localhost:3306/test1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
initial-size: 1
min-idle: 1
max-active: 20
test-on-borrow: true
# driver-class-name: com.mysql.jdbc.Driver
# 下面是最新的mysql8版本推荐的驱动
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
# 下面是另外加的配置数据源的参数
minPoolSize: 3
maxPoolSize: 25
maxLifetime: 20000
borrowConnectionTimeout: 30
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60 test2:
jdbcurl: jdbc:mysql://localhost:3306/test2?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
minPoolSize: 3
maxPoolSize: 25
maxLifetime: 20000
borrowConnectionTimeout: 30
loginTimeout: 30
maintenanceInterval: 60
maxIdleTime: 60 mybatis:
mapper-locations: classpath:mapper/*.xml #设置静态资源路径,多个以逗号分隔
spring.resources.static-locations: classpath:static/,file:static/ # 日志配置
logging:
level:
czs: debug
org.springframework: WARN
org.spring.springboot.dao: debug
5.实体类
ps.使用lombok插件挺方便的~ id数据库主键自增
@Data
public class User {
private Integer id;
private String name;
private long age;
}
6.mapper接口
UserMapper1:
public interface UserMapper1 {
// 查询语句
@Select("SELECT * FROM users WHERE NAME = #{name}")
User findByName(@Param("name") String name);
// 添加
@Insert("INSERT INTO users(NAME, AGE) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);
}
UserMapper2:
public interface UserMapper2 {
// 查询语句
@Select("SELECT * FROM users WHERE NAME = #{name}")
User findByName(@Param("name") String name);
// 添加
@Insert("INSERT INTO users(NAME, AGE) VALUES(#{name}, #{age})")
int insert(@Param("name") String name, @Param("age") Integer age);
}
7.service
ManyService1:
@Service
public class ManyService1 { @Autowired
private UserMapper1 userMapper1;
@Autowired
private UserMapper2 userMapper2; /* @Transactional(transactionManager = "test1TransactionManager",rollbackFor = Exception.class)
public int insert(String name, Integer age) {
int i = userMapper1.insert(name, age);
System.out.println("userMapper1.insert结束~ :" + i);
// int a = 1 / 0;//手动异常
return i;
}*/ // 开启事务,由于使用jta+atomikos解决分布式事务,所以此处不必再指定事务
@Transactional
public int insert(String name, Integer age) {
int insert = userMapper1.insert(name, age);
//int i = 1 / age;// 赋值age为0故意引发事务
return insert;
} //http://localhost:8080/manyDatasource/insertDb1AndDb2?name=tom3&age=2
// 开启事务,由于使用jta+atomikos解决分布式事务,所以此处不必再指定事务
@Transactional
public int insertDb1AndDb2(String name, Integer age) {
int insert = userMapper1.insert(name, age);
int insert2 = userMapper2.insert(name, age);
int i = 1 / age;// 赋值age为0故意引发事务
return insert + insert2;
} }
ManyService2:
@Service
public class ManyService2 { @Autowired
private UserMapper2 userMapper2; @Transactional(transactionManager = "test2TransactionManager",rollbackFor = Exception.class)
public int insert(String name, Integer age) {
int i = userMapper2.insert(name, age);
System.out.println("userMapper2.insert结束~ :" + null);
int a = 1 / 0;//手动异常
return i;
} }
8.Controller
@RestController
public class ManyController { @Autowired
private ManyService1 manyService1; @Resource
private ManyService2 manyService2; @RequestMapping(value = "datasource1")
public int datasource1(String name, Integer age) {
return manyService1.insert(name, age);
} @RequestMapping(value = "datasource2")
public int datasource2(String name, Integer age) {
return manyService2.insert(name, age);
} /**
* @Param:
* @Description: 这里测试两个service两个数据源的事务(不加上atomikos插件的情况下测试,
*使用DataSource1Config和DataSource2Config 两个配置类, 关闭DBConfig1, DBConfig2和MyBatisConfig1, MyBatisConfig1两个类)
* @Author: zyf 2019/5/10
*/
//http://localhost:8080/manyDatasource/testManyTrans?name=tom4&age=2
@RequestMapping(value = "testManyTrans")
public int testManyTrans(String name, Integer age) {
int i = 0;
int i1 = manyService1.insert(name, age);
System.out.println("manyService1.insert :" + i1); /*
第二个事务中会手动造成一个异常~,
但是第一个事务执行完毕了,保存到了数据库
*/
int i2 = manyService2.insert(name, age);
System.out.println("manyService2.insert :" + i2);
return i;
} /**
* @Param:
* @Description: 这里测试使用atomikos插件测试多数据源事务
* @Author: zyf 2019/5/10
*/
//http://localhost:8080/manyDatasource/insertDb1AndDb2?name=tom5&age=2
//http://localhost:8080/manyDatasource/insertDb1AndDb2?name=tom6&age=0 //测试除数为0后的事务管理
@RequestMapping(value = "insertDb1AndDb2")
public int insertDb1AndDb2(String name, Integer age) {
return manyService1.insertDb1AndDb2(name, age);
} }
9.配置数据源(*******重点总是在最后********)
DBConfig1:
@Data
@ConfigurationProperties(prefix = "spring.datasource.test1") // 注意这个前缀要和application.yml文件的前缀一样
public class DBConfig1 {
// @Value("${mysql.datasource.test1.jdbcurl}")
//@Value("${jdbcurl}")
private String jdbcurl;
//private String url;
// 比如这个url在properties中是这样子的mysql.datasource.test1.username = root
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery;
}
DBConfig2:
@Data
@ConfigurationProperties(prefix = "spring.datasource.test2")// 注意这个前缀要和application.yml文件的前缀一样
public class DBConfig2 {
//@Value("${spring.datasource.test2.jdbcurl}")
//@Value("${jdbcurl}")
//private String url;
private String jdbcurl;
private String username;
private String password;
private int minPoolSize;
private int maxPoolSize;
private int maxLifetime;
private int borrowConnectionTimeout;
private int loginTimeout;
private int maintenanceInterval;
private int maxIdleTime;
private String testQuery; }
上面两个配置类作用: 将application.yml配置文件中配置自动封装到实体类字段中,然后赋值给atomikos类型的数据源.(下面两个具体配置数据源)
MyBatisConfig1:
// 配置数据源
//@Bean(name = "testDataSource") //test1DataSource
@Bean(name = "test1DataSource") //test1DataSource
public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
//mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setUrl(testConfig.getJdbcurl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); // 将本地事务注册到创 Atomikos全局事务
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("test1DataSource"); xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
} @Bean(name = "test1SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
} @Bean(name = "test1SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
MyBatisConfig2 :
@Configuration
@MapperScan(basePackages = "czs.mapper2", sqlSessionTemplateRef = "test2SqlSessionTemplate")
public class MyBatisConfig2 { // 配置数据源
@Bean(name = "test2DataSource")
public DataSource testDataSource(DBConfig2 testConfig) throws SQLException {
MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
//mysqlXaDataSource.setUrl(testConfig.getUrl());
mysqlXaDataSource.setUrl(testConfig.getJdbcurl());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
mysqlXaDataSource.setPassword(testConfig.getPassword());
mysqlXaDataSource.setUser(testConfig.getUsername());
mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true); AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(mysqlXaDataSource);
xaDataSource.setUniqueResourceName("test2DataSource"); xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
xaDataSource.setTestQuery(testConfig.getTestQuery());
return xaDataSource;
} @Bean(name = "test2SqlSessionFactory")
public SqlSessionFactory testSqlSessionFactory(@Qualifier("test2DataSource") DataSource dataSource)
throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
} @Bean(name = "test2SqlSessionTemplate")
public SqlSessionTemplate testSqlSessionTemplate(
@Qualifier("test2SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
10.测试
http://localhost:8080/manyDatasource/insertDb1AndDb2?name=tom5&age=2
结果: test1和test2数据库都插入数据~
http://localhost:8080/manyDatasource/insertDb1AndDb2?name=tom6&age=0 (两个insert操作后,手动异常)
结果: test1和test2数据库都未插入数据~
GitHub传送门: https://github.com/ColoZhu/springbootmanyDatasource
参考出处: https://blog.csdn.net/qq_36138324/article/details/81612890
springboot+atomikos+多数据源管理事务(mysql 8.0)的更多相关文章
- 【spring boot】SpringBoot初学(7)– 多数据源及其事务
前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置: 参考: Spring Boot Reference Guide , §77.2 ...
- 使用spring+hibernate+atomikos+tomcat构建分布式事务
本文通过一个demo,介绍如何使用spring+hibernate+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用. demo功能:实现一个能成功提交和回滚的涉及两个数据库数 ...
- 使用spring+mybatis+atomikos+tomcat构建分布式事务
本文通过一个demo,介绍如何使用spring+mybatis+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用. demo功能:实现一个能成功提交和回滚的涉及两个数据库数据源 ...
- springboot学习笔记:10.springboot+atomikos+mysql+mybatis+druid+分布式事务
前言 上一篇文章我们整合了springboot+druid+mybatis+mysql+多数据源: 本篇文章大家主要跟随你们涛兄在上一届基础上配置一下多数据源情况下的分布式事务: 首先,到底啥是分布式 ...
- Springboot+Atomikos+Jpa+Mysql实现JTA分布式事务
1 前言 之前整理了一个spring+jotm实现的分布式事务实现,但是听说spring3.X后不再支持jotm了,jotm也有好几年没更新了,所以今天整理springboot+Atomikos+jp ...
- spring boot + druid + mybatis + atomikos 多数据源配置 并支持分布式事务
文章目录 一.综述 1.1 项目说明 1.2 项目结构 二.配置多数据源并支持分布式事务 2.1 导入基本依赖 2.2 在yml中配置多数据源信息 2.3 进行多数据源的配置 三.整合结果测试 3.1 ...
- springboot整合多数据源解决分布式事务
一.前言 springboot整合多数据源解决分布式事务. 1.多数据源采用分包策略 2.全局分布式事务管理:jta-atomikos. ...
- Spring Boot 2.x基础教程:使用JTA实现多数据源的事务管理
在一个Spring Boot项目中,连接多个数据源还是比较常见的.之前也介绍了如何在几种常用框架的场景下配置多数据源,具体可见: Spring Boot 2.x基础教程:JdbcTemplate的多数 ...
- Springboot源码分析之事务拦截和管理
摘要: 在springboot的自动装配事务里面,InfrastructureAdvisorAutoProxyCreator ,TransactionInterceptor,PlatformTrans ...
随机推荐
- [JZOJ3303] 【集训队互测2013】城市规划
题目 题目大意 求\(N\)个点的简单无向图的方案数(有编号). 结果对\(1004535809\)取模. 思考历程 感觉这个问题非常经典. 当时想到了一堆式子,但都觉得可能会有重和漏,于是弃掉了-- ...
- 校园商铺-1开发准备-3 Eclipse与maven的联合配置
1. JDK安装地址: 2.maven安装地址: 3.maven配置 注意:settings.xml文件极容易出现格式错误 4.tomcat修改端口 我本地启动了其他服务,占用了8080端口,因此需要 ...
- (转)iframe 高度100%时,出现垂直滚动条
问题 需求是这样的,iframe在一个div中,并且iframe高度与div一样,所以设置了iframe高度是100%,结果div出现了滚动条,在排除了padding.margin的因素外,还是有滚动 ...
- AtCoder ABC 129E Sum Equals Xor
题目链接:https://atcoder.jp/contests/abc129/tasks/abc129_e 题目大意 给定一个二进制表示的数 L,问有多少对自然数 (a, b) 满足 $a + b ...
- 一个mdl相关的问题
感觉挺有意义的,细节问题 http://www.kernelmode.info/forum/viewtopic.php?f=14&t=4318这个人代码到底犯了什么错误 I want to p ...
- java_static关键字
/** * static关键字:静态关键字 * 静态优先于非静态加载到内存中(静态优先于对进入到内存中) * 被static修饰的成员变量不能被序列化的,序列化的都是对象 * transient关键字 ...
- 【左偏树】 [JLOI2015]城池攻占
原来左偏树还可以打tag,get了 和线段树打tag一样,时不时Push_Down就好了 然后这里显然也是要先乘法后加法的 tag打上了之后还是其他一般左偏树差不多,有些细节注意一下 然后开 long ...
- 小程序跳转传参参数值为url时参数丢失
通过先encodeURIComponent,取到值以后再decodeURIComponent,拼接参数正常传递 A页面 switch: function (e) { var aa = 'UNNZVUf ...
- Ubuntu下安装和配置Apache2,小编觉得挺不错的,现在就分享给大家
本篇文章主要介绍了详解Ubuntu下安装和配置Apache2,小编觉得挺不错的,现在就分享给大家,也给大家做个参考.有兴趣的朋友可以了解一下.(http://xz.8682222.com) 在Ubun ...
- 在DataWorks中实现指定UDF只能被指定账户访问
背景 之前写过一篇文章是关于“DataWorks和MaxCompute内部权限体系的区别”有兴趣的朋友可以点击阅读查看详情.但是还是有些同学会问,我如何在DataWorks中实现我的具体某个Resou ...