springboot整合Atomikos的示例詳解
什么是Atomikos
Atomikos是一個開源的事務(wù)管理器,用于管理和控制分布式事務(wù)的執(zhí)行流程,提供了可靠的,高性能的事務(wù)管理解決方案,可以與多種應(yīng)用和數(shù)據(jù)庫集成
實(shí)戰(zhàn)
創(chuàng)建springBoot項(xiàng)目,pom.xml文件如下
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.14</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xpc</groupId>
<artifactId>distribute-transaction</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter-test</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置多數(shù)據(jù)源
server.port=8080 #數(shù)據(jù)源test spring.test-datasource.driverClassName = com.mysql.jdbc.Driver spring.test-datasource.jdbc-url = jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.test-datasource.username = root spring.test-datasource.password = 12345 #數(shù)據(jù)源cyp spring.cyp-datasource.driverClassName = com.mysql.jdbc.Driver spring.cyp-datasource.jdbc-url = jdbc:mysql://localhost:3306/test_1?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true spring.cyp-datasource.username = root spring.cyp-datasource.password = 12345 logging.level.com.atomikos = debug
多數(shù)據(jù)源配置類
//配置掃描對應(yīng)的dao層的包
@MapperScan(basePackages = "com.xpc.dao", sqlSessionFactoryRef = "testSqlSessionFactory")
@Configuration
public class TestMyBatisConfig {
@SneakyThrows
@Bean
public SqlSessionFactory testSqlSessionFactory(@Qualifier("testDataSource") DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean.getObject();
}
}
package com.xpc.config;
import lombok.SneakyThrows;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
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;
@Configuration
@MapperScan(basePackages = "com.xpc.dao1",sqlSessionFactoryRef = "cypSqlSessionFactory")
public class CypMyBatisConfig {
@SneakyThrows
@Bean
public SqlSessionFactory cypSqlSessionFactory(@Qualifier("cypDataSource") DataSource dataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean.getObject();
}
}
Atomikos配置
import com.atomikos.jdbc.AtomikosDataSourceBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
import java.util.Properties;
@Configuration
public class AtomikosDataSourceConfig {
@Value("${spring.test-datasource.jdbc-url}")
private String testUrl;
@Value("${spring.test-datasource.username}")
private String testUser;
@Value("${spring.test-datasource.password}")
private String testPassword;
@Value("${spring.cyp-datasource.jdbc-url}")
private String cypUrl;
@Value("${spring.cyp-datasource.username}")
private String cypUser;
@Value("${spring.cyp-datasource.password}")
private String cypPassword;
@Bean(name = "testDataSource")
public DataSource testDataSource() {
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
//設(shè)置唯一資源name
atomikosDataSourceBean.setUniqueResourceName("testDataSource");
atomikosDataSourceBean.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
Properties properties = new Properties();
properties.setProperty("URL", testUrl);
properties.setProperty("user", testUser);
properties.setProperty("password", testPassword);
atomikosDataSourceBean.setXaProperties(properties);
return atomikosDataSourceBean;
}
@Bean(name = "cypDataSource")
public DataSource cypDataSource() {
AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
//設(shè)置唯一資源name
atomikosDataSourceBean.setUniqueResourceName("cypDataSource");
atomikosDataSourceBean.setXaDataSourceClassName("com.mysql.cj.jdbc.MysqlXADataSource");
Properties properties = new Properties();
properties.setProperty("URL", cypUrl);
properties.setProperty("user", cypUser);
properties.setProperty("password", cypPassword);
atomikosDataSourceBean.setXaProperties(properties);
return atomikosDataSourceBean;
}
}
import org.springframework.context.annotation.Configuration;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.transaction.TransactionManager;
import javax.transaction.UserTransaction;
@Configuration
public class AtomikosConfig {
@Bean(name = "userTransaction")
public UserTransaction userTransaction() {
return new UserTransactionImp();
}
@Bean(name = "atomikosTransactionManager")
public TransactionManager atomikosTransactionManager() {
return new UserTransactionManager();
}
@Bean(name = "platformTransactionManager")
@DependsOn({"userTransaction", "atomikosTransactionManager"})
public PlatformTransactionManager transactionManager() {
UserTransaction userTransaction = userTransaction();
TransactionManager transactionManager = atomikosTransactionManager();
return new JtaTransactionManager(userTransaction, transactionManager);
}
}
dao層
@Mapper
public interface TestDao {
@Insert("insert into t_xpc (name) values (#{name})")
void insert(Test1 test1);
}
@Mapper
public interface CypDao {
@Insert("insert into t_cyp (name) values (#{name})")
void insert(Tcyp tcyp);
}
接下來就是service業(yè)務(wù)了
@Service
public class XpcService {
@Resource
private TestDao testDao;
@Resource
private CypDao cypDao;
@Transactional(rollbackFor = Exception.class)
public String test() {
Test1 test1 = new Test1();
test1.setName("xpc-5");
testDao.insert(test1);
Tcyp tcyp = new Tcyp();
tcyp.setName("xpc-5");
cypDao.insert(tcyp);
int i = 1/0;
return "success";
}
}
到這里springboot整合Atomikos就完成了,然后我們可以調(diào)用下該test方法,因?yàn)?int i = 1/0; 會拋出異常,所以這兩條數(shù)據(jù)都不會插入成功,也就意味著事務(wù)成功回滾了
Atomikos有什么缺點(diǎn)嗎?
Atomiko提供了兩階段提交,那么兩階段提交會有什么問題?
1:單點(diǎn)問題

事務(wù)管理器是直接集成在我們服務(wù)中的,也就是java進(jìn)程中的,如果這時候這個服務(wù)掛了,那么整個分布式事務(wù)就都不可用了
2:資源鎖定問題
在事務(wù)第一階段的時候,我們的資源管理器RM就會鎖定一些資源,這時候,其它事務(wù)進(jìn)來就無法再次鎖定同樣的資源了,也就造成了阻塞的問題
如果這時候碰到了單點(diǎn)問題,導(dǎo)致這些資源釋放不掉,那么其它事務(wù)就再也拿不到這些資源了
3:性能瓶頸問題
事務(wù)管理器在發(fā)起第一階段的時候,必須等到所有的資源管理器都返回OK了,才會發(fā)起第二階段commit,如果這時候有一個資源管理在第一階段遲遲沒有返回OK,那么事務(wù)管理器就會一直阻塞在這里
4:數(shù)據(jù)不一致
假設(shè)現(xiàn)在事務(wù)管理器(TM)收到所有資源管理器(RM)的第一階段OK響應(yīng)了,這時候就會發(fā)起第二階段的commit了,但是這時候由于某些原因,導(dǎo)致某個資源管理器(RM)沒有收到commit,這時候其它的資源管理器(RM)已經(jīng)提交了,但是這個資源管理器(RM)還是沒有提交事務(wù)的,這時候就造成了數(shù)據(jù)不一致的問題了
以上就是springboot整合Atomikos的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于springboot整合Atomikos的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JAVA實(shí)現(xiàn)網(wǎng)絡(luò)/本地圖片轉(zhuǎn)BASE64存儲代碼示例
這篇文章主要給大家介紹了關(guān)于JAVA實(shí)現(xiàn)網(wǎng)絡(luò)/本地圖片轉(zhuǎn)BASE64存儲的相關(guān)資料,Base64是網(wǎng)絡(luò)上最常見的用于傳輸8Bit字節(jié)碼的編碼方式之一,Base64就是一種基于64個可打印字符來表示二進(jìn)制數(shù)據(jù)的方法,需要的朋友可以參考下2023-07-07
詳解如何在SpringBoot中實(shí)現(xiàn)優(yōu)雅關(guān)閉
這篇文章主要介紹了如何在SpringBoot中實(shí)現(xiàn)優(yōu)雅關(guān)閉,SpringBoot應(yīng)用程序的關(guān)閉可以是崩潰,也可以是手動關(guān)閉的,Shutdown、Crash 和 Graceful 之間的區(qū)別在于,它控制決定了我們可以用這個事件做什么,本文中,一起研究下Spring Boot提供的開箱即用功能之一:優(yōu)雅關(guān)閉2024-09-09
詳解Idea SpringBoot搭建SpringCloud的準(zhǔn)備工作(推薦)
這篇文章主要介紹了Idea SpringBoot搭建SpringCloud的準(zhǔn)備工作(推薦),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-10-10
使用Jenkins來構(gòu)建SVN+Maven項(xiàng)目的實(shí)現(xiàn)
這篇文章主要介紹了使用Jenkins來構(gòu)建SVN+Maven項(xiàng)目的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Spring MVC 更靈活的控制 json 返回問題(自定義過濾字段)
本篇文章主要介紹了Spring MVC 更靈活的控制 json 返回問題(自定義過濾字段),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02
Java中LinkedHashSet的實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Java中LinkedHasSet的實(shí)現(xiàn)原理詳解,LinkedHashSet?是具有可預(yù)知迭代順序的?Set?接口的哈希表和鏈接列表實(shí)現(xiàn),此實(shí)現(xiàn)與HashSet?的不同之處在于,后者維護(hù)著一個運(yùn)行于所有條目的雙重鏈接列表,需要的朋友可以參考下2023-09-09

