当前位置:   article > 正文

Spring Boot集成atomikos快速入门Demo

Spring Boot集成atomikos快速入门Demo

1.什么是atomikos

Atomikos是一个轻量级的分布式事务管理器,实现了Java Transaction API (JTA)规范,可以很方便的和Spring Boot集成,支持微服务场景下跨节点的全局事务。Atomikos公司官方网址为:https://www.atomikos.com/。其旗下最著名的产品就是事务管理器。产品分两个版本:

  • TransactionEssentials:开源的免费产品

  • ExtremeTransactions:上商业版,需要收费。

2.环境搭建

第一个mysql数据库

docker run --name docker-mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3333:3306 -d mysql

第二个mysql数据库

docker run --name docker-mysql-2 -e MYSQL_ROOT_PASSWORD=123456 -p 3334:3306 -d mysql

初始化数据

  1. create database demo;
  2. create table user_info
  3. (
  4. user_id varchar(64) not null primary key,
  5. username varchar(100) null ,
  6. age int(3) null ,
  7. gender tinyint(1) null ,
  8. remark varchar(255) null ,
  9. create_time datetime null ,
  10. create_id varchar(64) null ,
  11. update_time datetime null ,
  12. update_id varchar(64) null ,
  13. enabled tinyint(1) default 1 null
  14. );

说明

  1. msyql账号root
  2. mysql密码123456

3.项目代码

实验目的:实现2个mysql数据的分布式事务管理,要么全部成功,只要有一个失败就会滚。

pom..xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5. <parent>
  6. <artifactId>springboot-demo</artifactId>
  7. <groupId>com.et</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11. <artifactId>atomikos</artifactId>
  12. <properties>
  13. <maven.compiler.source>8</maven.compiler.source>
  14. <maven.compiler.target>8</maven.compiler.target>
  15. </properties>
  16. <dependencies>
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <dependency>
  22. <groupId>org.springframework.boot</groupId>
  23. <artifactId>spring-boot-autoconfigure</artifactId>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.springframework.boot</groupId>
  27. <artifactId>spring-boot-starter-test</artifactId>
  28. <scope>test</scope>
  29. </dependency>
  30. <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
  31. <dependency>
  32. <groupId>org.mybatis.spring.boot</groupId>
  33. <artifactId>mybatis-spring-boot-starter</artifactId>
  34. <version>1.3.0</version><!-- 1.3.0以上的版本没有@MapperScan以及@Select注解 -->
  35. </dependency>
  36. <!-- automatic+jta的分布式事务管理 -->
  37. <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jta-atomikos -->
  38. <dependency>
  39. <groupId>org.springframework.boot</groupId>
  40. <artifactId>spring-boot-starter-jta-atomikos</artifactId>
  41. </dependency>
  42. <dependency>
  43. <groupId>org.springframework.boot</groupId>
  44. <artifactId>spring-boot-devtools</artifactId>
  45. <scope>runtime</scope>
  46. </dependency>
  47. <dependency>
  48. <groupId>mysql</groupId>
  49. <artifactId>mysql-connector-java</artifactId>
  50. <!--boot 2.1默认 mysql8的版本; boot 2.0默认mysql5版本-->
  51. <version>8.0.13</version>
  52. <!--<version>5.1.46</version>-->
  53. <!--<scope>runtime</scope>-->
  54. </dependency>
  55. <dependency>
  56. <groupId>org.projectlombok</groupId>
  57. <artifactId>lombok</artifactId>
  58. <optional>true</optional>
  59. <version>1.18.2</version>
  60. </dependency>
  61. </dependencies>
  62. </project>

mapper

创建2个mapper连接不同的数据库

  1. package com.et.atomikos.mapper1;
  2. import org.apache.catalina.User;
  3. import org.apache.ibatis.annotations.Insert;
  4. import org.apache.ibatis.annotations.Param;
  5. import org.apache.ibatis.annotations.Select;
  6. public interface UserInfoMapper1 {
  7. // query
  8. @Select("SELECT * FROM user_info WHERE username = #{username}")
  9. User findByName(@Param("username") String username);
  10. // add
  11. @Insert("INSERT INTO user_info(user_id,username, age) VALUES(#{userId},#{username}, #{age})")
  12. int insert(@Param("userId") String userId,@Param("username") String username, @Param("age") Integer age);
  13. }
  1. package com.et.atomikos.mapper2;
  2. import org.apache.catalina.User;
  3. import org.apache.ibatis.annotations.Insert;
  4. import org.apache.ibatis.annotations.Param;
  5. import org.apache.ibatis.annotations.Select;
  6. public interface UserInfoMapper2 {
  7. // query
  8. @Select("SELECT * FROM user_info WHERE username = #{username}")
  9. User findByName(@Param("username") String username);
  10. // add
  11. @Insert("INSERT INTO user_info(user_id,username, age) VALUES(#{userId},#{username}, #{age})")
  12. int insert(@Param("userId") String userId,@Param("username") String username, @Param("age") Integer age);
  13. }

service

创建2个service,分别用不同mapper

  1. package com.et.atomikos.mapper1;
  2. import com.et.atomikos.mapper1.UserInfoMapper1;
  3. import com.et.atomikos.mapper2.UserInfoMapper2;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.stereotype.Service;
  6. import org.springframework.transaction.annotation.Transactional;
  7. @Service
  8. public class ManyService1 {
  9. @Autowired
  10. private UserInfoMapper1 userInfoMapper1;
  11. @Autowired
  12. private UserInfoMapper2 userInfoMapper2;
  13. @Transactional
  14. public int insert(String userId,String username, Integer age) {
  15. int insert = userInfoMapper1.insert(userId,username, age);
  16. int i = 1 / age;// if age is zero ,then a error will be happened.
  17. return insert;
  18. }
  19. @Transactional
  20. public int insertDb1AndDb2(String userId,String username, Integer age) {
  21. int insert = userInfoMapper1.insert(userId,username, age);
  22. int insert2 = userInfoMapper2.insert(userId,username, age);
  23. int i = 1 / age;// if age is zero ,then a error will be happened.
  24. return insert + insert2;
  25. }
  26. }
  1. package com.et.atomikos.mapper2;
  2. import com.et.atomikos.mapper2.UserInfoMapper2;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.stereotype.Service;
  5. import org.springframework.transaction.annotation.Transactional;
  6. @Service
  7. public class ManyService2 {
  8. @Autowired
  9. private UserInfoMapper2 userInfoMapper2;
  10. @Transactional
  11. public int insert(String userId,String username, Integer age) {
  12. int i = userInfoMapper2.insert(userId,username, age);
  13. System.out.println("userInfoMapper2.insert end :" + null);
  14. int a = 1 / 0;//touch a error
  15. return i;
  16. }
  17. }

config

初始化数据源1和数据源2

  1. package com.et.atomikos.config;
  2. import lombok.Data;
  3. import org.springframework.boot.context.properties.ConfigurationProperties;
  4. @Data
  5. @ConfigurationProperties(prefix = "spring.datasource.test1")
  6. public class DBConfig1 {
  7. // @Value("${mysql.datasource.test1.jdbcurl}")
  8. //@Value("${jdbcurl}")
  9. private String jdbcurl;
  10. //private String url;
  11. private String username;
  12. private String password;
  13. private int minPoolSize;
  14. private int maxPoolSize;
  15. private int maxLifetime;
  16. private int borrowConnectionTimeout;
  17. private int loginTimeout;
  18. private int maintenanceInterval;
  19. private int maxIdleTime;
  20. private String testQuery;
  21. }
  1. package com.et.atomikos.config;
  2. import com.atomikos.jdbc.AtomikosDataSourceBean;
  3. import com.mysql.cj.jdbc.MysqlXADataSource;
  4. import org.apache.ibatis.session.SqlSessionFactory;
  5. import org.mybatis.spring.SqlSessionFactoryBean;
  6. import org.mybatis.spring.SqlSessionTemplate;
  7. import org.mybatis.spring.annotation.MapperScan;
  8. import org.springframework.beans.factory.annotation.Qualifier;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import javax.sql.DataSource;
  12. import java.sql.SQLException;
  13. /**
  14. * @author liuhaihua
  15. * @version 1.0
  16. * @ClassName MyBatisConfig1
  17. * @Description todo
  18. * @date 2024年04月18日 13:37
  19. */
  20. @Configuration
  21. @MapperScan(basePackages = "com.et.atomikos.mapper1", sqlSessionTemplateRef = "test1SqlSessionTemplate")
  22. public class MyBatisConfig1 {
  23. @Bean(name = "test1DataSource") //test1DataSource
  24. public DataSource testDataSource(DBConfig1 testConfig) throws SQLException {
  25. MysqlXADataSource mysqlXaDataSource = new MysqlXADataSource();
  26. //mysqlXaDataSource.setUrl(testConfig.getUrl());
  27. mysqlXaDataSource.setUrl(testConfig.getJdbcurl());
  28. mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
  29. mysqlXaDataSource.setPassword(testConfig.getPassword());
  30. mysqlXaDataSource.setUser(testConfig.getUsername());
  31. mysqlXaDataSource.setPinGlobalTxToPhysicalConnection(true);
  32. // 将本地事务注册到创 Atomikos全局事务
  33. AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
  34. xaDataSource.setXaDataSource(mysqlXaDataSource);
  35. xaDataSource.setUniqueResourceName("test1DataSource");
  36. xaDataSource.setMinPoolSize(testConfig.getMinPoolSize());
  37. xaDataSource.setMaxPoolSize(testConfig.getMaxPoolSize());
  38. xaDataSource.setMaxLifetime(testConfig.getMaxLifetime());
  39. xaDataSource.setBorrowConnectionTimeout(testConfig.getBorrowConnectionTimeout());
  40. xaDataSource.setLoginTimeout(testConfig.getLoginTimeout());
  41. xaDataSource.setMaintenanceInterval(testConfig.getMaintenanceInterval());
  42. xaDataSource.setMaxIdleTime(testConfig.getMaxIdleTime());
  43. xaDataSource.setTestQuery(testConfig.getTestQuery());
  44. return xaDataSource;
  45. }
  46. @Bean(name = "test1SqlSessionFactory")
  47. public SqlSessionFactory testSqlSessionFactory(@Qualifier("test1DataSource") DataSource dataSource)
  48. throws Exception {
  49. SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
  50. bean.setDataSource(dataSource);
  51. return bean.getObject();
  52. }
  53. @Bean(name = "test1SqlSessionTemplate")
  54. public SqlSessionTemplate testSqlSessionTemplate(
  55. @Qualifier("test1SqlSessionFactory") SqlSessionFactory sqlSessionFactory) throws Exception {
  56. return new SqlSessionTemplate(sqlSessionFactory);
  57. }
  58. }

数据源2也是类似配置

controller

  1. package com.et.atomikos.controller;
  2. import com.et.atomikos.mapper1.ManyService1;
  3. import com.et.atomikos.mapper2.ManyService2;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. import javax.annotation.Resource;
  8. @RestController
  9. public class HelloWorldController {
  10. @Autowired
  11. private ManyService1 manyService1;
  12. @Resource
  13. private ManyService2 manyService2;
  14. //http://localhost:8088/datasource1?userId=9&username=datasource1&age=2
  15. @RequestMapping(value = "datasource1")
  16. public int datasource1(String userId,String username, Integer age) {
  17. return manyService1.insert(userId,username, age);
  18. }
  19. //http://localhost:8088/datasource2?userId=9&username=datasource2&age=2
  20. @RequestMapping(value = "datasource2")
  21. public int datasource2(String userId,String username, Integer age) {
  22. return manyService2.insert(userId,username, age);
  23. }
  24. //http://localhost:8088/insertDb1AndDb2?userId=1&username=tom5&age=2
  25. //http://localhost:8088/insertDb1AndDb2?userId=2&username=tom5&age=0 //touch a error
  26. @RequestMapping(value = "insertDb1AndDb2")
  27. public int insertDb1AndDb2(String userId,String username, Integer age) {
  28. return manyService1.insertDb1AndDb2(userId,username, age);
  29. }
  30. }

application.yaml

  1. server:
  2. port: 8088
  3. spring:
  4. application:
  5. name: manyDatasource
  6. datasource:
  7. # spring.datasource.test1
  8. # druid:
  9. test1:
  10. jdbcurl: jdbc:mysql://localhost:3333/demo?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
  11. username: root
  12. password: 123456
  13. initial-size: 1
  14. min-idle: 1
  15. max-active: 20
  16. test-on-borrow: true
  17. driver-class-name: com.mysql.cj.jdbc.Driver
  18. type: com.alibaba.druid.pool.DruidDataSource
  19. minPoolSize: 3
  20. maxPoolSize: 25
  21. maxLifetime: 20000
  22. borrowConnectionTimeout: 30
  23. loginTimeout: 30
  24. maintenanceInterval: 60
  25. maxIdleTime: 60
  26. test2:
  27. jdbcurl: jdbc:mysql://localhost:3334/demo?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8
  28. username: root
  29. password: 123456
  30. driver-class-name: com.mysql.cj.jdbc.Driver
  31. type: com.alibaba.druid.pool.DruidDataSource
  32. minPoolSize: 3
  33. maxPoolSize: 25
  34. maxLifetime: 20000
  35. borrowConnectionTimeout: 30
  36. loginTimeout: 30
  37. maintenanceInterval: 60
  38. maxIdleTime: 60
  39. mybatis:
  40. mapper-locations: classpath:mapper/*.xml
  41. spring.resources.static-locations: classpath:static/,file:static/
  42. logging:
  43. level:
  44. czs: debug
  45. org.springframework: WARN
  46. org.spring.springboot.dao: debug

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

  • https://github.com/Harries/springboot-demo

4.测试

启动Spring Boot 应用

插入第一个数据测试

http://localhost:8088/datasource1?userId=9&username=datasource1&age=2

插入第二个数据库

http://localhost:8088/datasource2?userId=9&username=datasource2&age=2

同时插入2个数据库

http://localhost:8088/insertDb1AndDb2?userId=1&username=tom5&age=2

异常回滚测试

http://localhost:8088/insertDb1AndDb2?userId=2&username=tom5&age=0  //touch a error

5.参考

  • https://github.com/ColoZhu/springbootmanyDatasource

  • http://www.liuhaihua.cn/archives/710435.html

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/466134
推荐阅读
相关标签
  

闽ICP备14008679号