Atomikos是一个轻量级的分布式事务管理器,实现了Java Transaction API (JTA)规范,可以很方便的和Spring Boot集成,支持微服务场景下跨节点的全局事务。Atomikos公司官方网址为:https://www.atomikos.com/。其旗下最著名的产品就是事务管理器。产品分两个版本:
TransactionEssentials:开源的免费产品
ExtremeTransactions:上商业版,需要收费。
docker run --name docker-mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3333:3306 -d mysqldocker run --name docker-mysql-2 -e MYSQL_ROOT_PASSWORD=123456 -p 3334:3306 -d mysql
create database demo;create table user_info(user_id varchar(64) not null primary key,username varchar(100) null ,age int(3) null ,gender tinyint(1) null ,remark varchar(255) null ,create_time datetime null ,create_id varchar(64) null ,update_time datetime null ,update_id varchar(64) null ,enabled tinyint(1) default 1 null);
msyql账号rootmysql密码123456
实验目的:实现2个mysql数据的分布式事务管理,要么全部成功,只要有一个失败就会滚。
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>atomikos</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></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></dependencies></project>
创建2个mapper连接不同的数据库
package com.et.atomikos.mapper1;import org.apache.catalina.User;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;public interface UserInfoMapper1 {// queryUser findByName( String username);// addint insert( String userId, String username, Integer age);}
package com.et.atomikos.mapper2;import org.apache.catalina.User;import org.apache.ibatis.annotations.Insert;import org.apache.ibatis.annotations.Param;import org.apache.ibatis.annotations.Select;public interface UserInfoMapper2 {// queryUser findByName( String username);// addint insert( String userId, String username, Integer age);}
创建2个service,分别用不同mapper
package com.et.atomikos.mapper1;import com.et.atomikos.mapper1.UserInfoMapper1;import com.et.atomikos.mapper2.UserInfoMapper2;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;@Servicepublic class ManyService1 {@Autowiredprivate UserInfoMapper1 userInfoMapper1;@Autowiredprivate UserInfoMapper2 userInfoMapper2;@Transactionalpublic int insert(String userId,String username, Integer age) {int insert = userInfoMapper1.insert(userId,username, age);int i = 1 / age;// if age is zero ,then a error will be happened.return insert;}@Transactionalpublic int insertDb1AndDb2(String userId,String username, Integer age) {int insert = userInfoMapper1.insert(userId,username, age);int insert2 = userInfoMapper2.insert(userId,username, age);int i = 1 / age;// if age is zero ,then a error will be happened.return insert + insert2;}}
package com.et.atomikos.mapper2;import com.et.atomikos.mapper2.UserInfoMapper2;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;public class ManyService2 {private UserInfoMapper2 userInfoMapper2;public int insert(String userId,String username, Integer age) {int i = userInfoMapper2.insert(userId,username, age);System.out.println("userInfoMapper2.insert end :" + null);int a = 1 / 0;//touch a errorreturn i;}}
初始化数据源1和数据源2
package com.et.atomikos.config;import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;(prefix = "spring.datasource.test1")public class DBConfig1 {// @Value("${mysql.datasource.test1.jdbcurl}")//@Value("${jdbcurl}")private String jdbcurl;//private String url;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;}
package com.et.atomikos.config;import com.atomikos.jdbc.AtomikosDataSourceBean;import com.mysql.cj.jdbc.MysqlXADataSource;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.factory.annotation.Qualifier;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import javax.sql.DataSource;import java.sql.SQLException;/*** @author liuhaihua* @version 1.0* @ClassName MyBatisConfig1* @Description todo* @date 2024年04月18日 13:37*/public class MyBatisConfig1 {//test1DataSourcepublic 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;}public SqlSessionFactory testSqlSessionFactory( DataSource dataSource)throws Exception {SqlSessionFactoryBean bean = new SqlSessionFactoryBean();bean.setDataSource(dataSource);return bean.getObject();}public SqlSessionTemplate testSqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {return new SqlSessionTemplate(sqlSessionFactory);}}
数据源2也是类似配置
package com.et.atomikos.controller;import com.et.atomikos.mapper1.ManyService1;import com.et.atomikos.mapper2.ManyService2;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;public class HelloWorldController {private ManyService1 manyService1;private ManyService2 manyService2;//http://localhost:8088/datasource1?userId=9&username=datasource1&age=2public int datasource1(String userId,String username, Integer age) {return manyService1.insert(userId,username, age);}//http://localhost:8088/datasource2?userId=9&username=datasource2&age=2public int datasource2(String userId,String username, Integer age) {return manyService2.insert(userId,username, age);}//http://localhost:8088/insertDb1AndDb2?userId=1&username=tom5&age=2//http://localhost:8088/insertDb1AndDb2?userId=2&username=tom5&age=0 //touch a errorpublic int insertDb1AndDb2(String userId,String username, Integer age) {return manyService1.insertDb1AndDb2(userId,username, age);}}
server:port: 8088spring:application:name: manyDatasourcedatasource:# spring.datasource.test1# druid:test1:jdbcurl: jdbc:mysql://localhost:3333/demo?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456: 1: 1: 20: true: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceminPoolSize: 3maxPoolSize: 25maxLifetime: 20000borrowConnectionTimeout: 30loginTimeout: 30maintenanceInterval: 60maxIdleTime: 60test2:jdbcurl: jdbc:mysql://localhost:3334/demo?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: 123456: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSourceminPoolSize: 3maxPoolSize: 25maxLifetime: 20000borrowConnectionTimeout: 30loginTimeout: 30maintenanceInterval: 60maxIdleTime: 60mybatis:: classpath:mapper/*.xml: classpath:static/,file:static/logging:level:czs: debug: WARN: debug
以上只是一些关键代码,所有代码请参见下面代码仓库
https://github.com/Harries/springboot-demo
启动Spring Boot 应用
http://localhost:8088/datasource1?userId=9&username=datasource1&age=2http://localhost:8088/datasource2?userId=9&username=datasource2&age=2http://localhost:8088/insertDb1AndDb2?userId=1&username=tom5&age=2http://localhost:8088/insertDb1AndDb2?userId=2&username=tom5&age=0 //touch a errorhttps://github.com/ColoZhu/springbootmanyDatasource
http://www.liuhaihua.cn/archives/710435.html
原文作者:HBLOG;如有侵权,请联系管理员删除。