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 ...
随机推荐
- sprintf、fprintf和printf这三个函数有什么区别?
都是把格式好的字符串输出,只是输出的目标不一样:1 printf,是把格式字符串输出到标准输出(一般是屏幕,可以重定向).2 sprintf,是把格式字符串输出到指定字符串中,所以参数比printf多 ...
- Redis-GEO
一. Redis的GEO特性 Redis3.2版本提供了GEO功能,支持存储地理位置信息用来实现诸如摇一摇,附近位置这类依赖于地理位置信息的功能.二. 命令2.1 增加地理位置信息 命令:geoadd ...
- <day006>bootstrap的简单学习 + 轮播图
任务1:bootstrap的简单学习 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta c ...
- Spark如何读写hive
原文引自:http://blog.csdn.net/zongzhiyuan/article/details/78076842 hive数据表建立可以在hive上建立,或者使用hiveContext.s ...
- (转)线程池 ExecutorService 详细介绍以及注意点区别
线程池 ExecutorService 相信java开发都用到,这里做个简单笔记 一 Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池 ...
- mysql 多表join
两个表可以简单地写为 select a.,b. from a left join b on a.id =b.id; 三个以上 select a.,b. from a left join b on a. ...
- eclipse变量名自动补全
对于编程人员来说,要记住大量的类名或类方法的名字,着实不是一件容易的事情.如果要IDE能够自动补全代码,那将为我们编程人员带来很大帮助. eclipse代码里面的代码提示功能默认是关闭的,只有输入“. ...
- 洛谷 P1941 飞扬的小鸟 (NOIP 2014)
题面 题解 背包细节题,wa了一片,上升的过程我们可以看做一个完全背包(多重背包好像跑不过去),下降 过程是一个0/1背包,为了避免冲突应该先跑多重,先跑0/1就有可能产生这个点又上升又下降的 非法情 ...
- 微信小程序连续旋转动画this.animation.rotate
一..js中封装旋转动画方法 添加animation属性 data:{ animation:''" } 改变animation的值(官网提供角度范围是-180~180,但是我发现角度越大会一 ...
- 小米手机的miui10 连接电脑。本地播放器推荐。
问题: 电脑连接了手机却不能看到手机里面的文件. 方法一 方法二 连接和电脑一样的wifi 进入文件管理 来自:百度经验. 本地播放器推荐 爱奇艺万能播放器(还不错,目前在用).qq影音 爱奇艺万能播 ...