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)的更多相关文章

  1. 【spring boot】SpringBoot初学(7)– 多数据源及其事务

    前言 github: https://github.com/vergilyn/SpringBootDemo 代码位置: 参考: Spring Boot Reference Guide , §77.2 ...

  2. 使用spring+hibernate+atomikos+tomcat构建分布式事务

    本文通过一个demo,介绍如何使用spring+hibernate+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用. demo功能:实现一个能成功提交和回滚的涉及两个数据库数 ...

  3. 使用spring+mybatis+atomikos+tomcat构建分布式事务

    本文通过一个demo,介绍如何使用spring+mybatis+atomikos+tomcat构建在一个事务中涉及两个数据源的web应用. demo功能:实现一个能成功提交和回滚的涉及两个数据库数据源 ...

  4. springboot学习笔记:10.springboot+atomikos+mysql+mybatis+druid+分布式事务

    前言 上一篇文章我们整合了springboot+druid+mybatis+mysql+多数据源: 本篇文章大家主要跟随你们涛兄在上一届基础上配置一下多数据源情况下的分布式事务: 首先,到底啥是分布式 ...

  5. Springboot+Atomikos+Jpa+Mysql实现JTA分布式事务

    1 前言 之前整理了一个spring+jotm实现的分布式事务实现,但是听说spring3.X后不再支持jotm了,jotm也有好几年没更新了,所以今天整理springboot+Atomikos+jp ...

  6. spring boot + druid + mybatis + atomikos 多数据源配置 并支持分布式事务

    文章目录 一.综述 1.1 项目说明 1.2 项目结构 二.配置多数据源并支持分布式事务 2.1 导入基本依赖 2.2 在yml中配置多数据源信息 2.3 进行多数据源的配置 三.整合结果测试 3.1 ...

  7. springboot整合多数据源解决分布式事务

    一.前言        springboot整合多数据源解决分布式事务.             1.多数据源采用分包策略              2.全局分布式事务管理:jta-atomikos. ...

  8. Spring Boot 2.x基础教程:使用JTA实现多数据源的事务管理

    在一个Spring Boot项目中,连接多个数据源还是比较常见的.之前也介绍了如何在几种常用框架的场景下配置多数据源,具体可见: Spring Boot 2.x基础教程:JdbcTemplate的多数 ...

  9. Springboot源码分析之事务拦截和管理

    摘要: 在springboot的自动装配事务里面,InfrastructureAdvisorAutoProxyCreator ,TransactionInterceptor,PlatformTrans ...

随机推荐

  1. Xshell 排版错乱问题

  2. SQLServer 中存储过程

    SQLServer 中存储过程返回的三种方式( 包括存储过程的创建, 在存储过程中调用, 在VS中调用的方法)存储过程有三种返回:   1.   用return返回数字型数据   2.   用返回参数 ...

  3. 在idesktop中加载天地图服务并叠加矢量数据

    在天地图中加载天地图在线服务,然后叠加上我们制作的专题图,可以查看制图效果. 以加载山东省天地图矢量地图服务为例: 服务地址: http://www.sdmap.gov.cn/tileservice/ ...

  4. Python学习详细教程-武沛齐

    目录 Python之路[第一篇]:Python简介和入门 Python之路[第二篇]:Python基础(一) Python之路[第三篇]:Python基础(二) Python之路[第四篇]:模块 Py ...

  5. iframe 的那些事儿

    项目中有不少地方用到iframe,今儿把使用iframe遇到的一些问题一块儿总结一下. 1.javascript监听iframe加载完成事件 iframe加载过程需要一定时间,这个加载过程常常出现白屏 ...

  6. Integer 类和 int 基本数据类型的区别

    public static void main(String[] args) { Integer i = 10; Integer j = 10; System.out.println(i == j); ...

  7. day3:python运算符及数据类型(str)(int)

    运算符 算数运算 :a = 10 * 10赋值运算:a = a + 1 a+=1 比较运算:a = 1 > 5 逻辑运算: a = 1>6 or 1==1   a = 1 and b = ...

  8. 面试系列12 redis和memcached有什么区别

    (1)redis和memcached有啥区别 这个事儿吧,你可以比较出N多个区别来,但是我还是采取redis作者给出的几个比较吧 1)Redis支持服务器端的数据操作:Redis相比Memcached ...

  9. 拦截器(Interceptor)与过滤器(Filter)的区别

    转自:https://www.jianshu.com/p/cf088baa9b04 过滤器,是在java web中将你传入的request.response提前过滤掉一些信息,或者提前设置一些参数.然 ...

  10. 创建 linuxrc 文件

    创建 linuxrc,加入如下内容: [arm@localhost my_rootfs]#vi linuxrc #!/bin/sh #挂载/etc 为 ramfs, 并从/mnt/etc 下拷贝文件到 ...