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