最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot使用JTA實現對多數據源的事務管理

 更新時間:2023年11月17日 09:07:09   作者:miaowYHu  
了解事務的都知道,在我們日常開發(fā)中單單靠事務管理就可以解決絕大多數問題了,但是為啥還要提出JTA這個玩意呢,到底JTA是什么呢?他又是具體來解決啥問題的呢?本文小編就給大家介紹一下如何在Spring Boot中使用JTA實現對多數據源的事務管理

JTA

JTA(Java Transaction API)是Java平臺上用于管理分布式事務的API。它提供了一組接口和類,用于協調和控制跨多個資源(如數據庫、消息隊列等)的事務操作。

JTA的架構體系如下:

JTA的主要目標是確保分布式環(huán)境中的事務的原子性、一致性、隔離性和持久性(ACID屬性)。它通過以下幾個關鍵概念和組件來實現:

  • 事務管理器(Transaction Manager) :負責協調和管理事務的開始、提交和回滾等操作。它是JTA的核心組件,負責跟蹤和控制事務的狀態(tài)。
  • 用戶事務(User Transaction) :表示應用程序發(fā)起的事務,通過事務管理器來管理和控制。
  • XA資源管理器(XA Resource Manager) :表示分布式環(huán)境中的資源,如數據庫、消息隊列等。它實現了XA接口,可以參與到分布式事務中。
  • XA事務(XA Transaction) :表示跨多個XA資源管理器的分布式事務。它遵循XA協議,通過兩階段提交(Two-Phase Commit)來保證事務的一致性。

使用JTA,開發(fā)人員可以在分布式環(huán)境中編寫具有事務保證的應用程序。它提供了一種標準化的方式來處理分布式事務,簡化了開發(fā)人員的工作,同時確保了數據的一致性和可靠性。
JTA事務比我們常用的JDBC事務更加強大,一個JTA事務可以有多個參與者,而一個JDBC事務則別限定在一個單一的數據庫連接。

這么說吧,我舉個栗子:

我們采用多數據源的時候,假設我們對A數據源的更新與B數據源的更新具有事務性,比如:我們對訂單中創(chuàng)建一條新的訂單數據,同時我也需要在商品庫中進行相關商品的扣減庫存,假設我們對庫存進行扣減失敗了,那么我們肯定希望我們的訂單也返回到之前沒下訂單之前的狀態(tài),畢竟我下了訂單了,庫存沒減少,我這算哪門子的下了訂單。

如果這兩條數據位于一個數據庫,那么我們可以通過簡單的事務管理就可以完成操作,那么我們至此就可以結束了,但是當我們的這兩個操作要是在不同的數據庫中,那么我們該怎么辦呢?

那么我們就來測試一下:
Spring Boot中引入相關依賴:

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<!--重點圍繞這個依賴-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jta-atomikos</artifactId>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

之后再Spring Boot application配置連接數據庫的相關配置:

spring.jta.enabled=true

spring.jta.atomikos.datasource.primary.xa-properties.url=jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.jta.atomikos.datasource.primary.xa-properties.user=root
spring.jta.atomikos.datasource.primary.xa-properties.password=123456
spring.jta.atomikos.datasource.primary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource
spring.jta.atomikos.datasource.primary.unique-resource-name=test1
spring.jta.atomikos.datasource.primary.max-pool-size=25
spring.jta.atomikos.datasource.primary.min-pool-size=3
spring.jta.atomikos.datasource.primary.max-lifetime=20000
spring.jta.atomikos.datasource.primary.borrow-connection-timeout=10000

spring.jta.atomikos.datasource.secondary.xa-properties.url=jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
spring.jta.atomikos.datasource.secondary.xa-properties.user=root
spring.jta.atomikos.datasource.secondary.xa-properties.password=123456
spring.jta.atomikos.datasource.secondary.xa-data-source-class-name=com.mysql.cj.jdbc.MysqlXADataSource
spring.jta.atomikos.datasource.secondary.unique-resource-name=test2
spring.jta.atomikos.datasource.secondary.max-pool-size=25
spring.jta.atomikos.datasource.secondary.min-pool-size=3
spring.jta.atomikos.datasource.secondary.max-lifetime=20000
spring.jta.atomikos.datasource.secondary.borrow-connection-timeout=10000
@Configuration
public class DataSourceConfiguration {

    @Primary
    @Bean
    @ConfigurationProperties(prefix = "spring.jta.atomikos.datasource.primary")
    public DataSource primaryDataSource() {
        return new AtomikosDataSourceBean();
    }

    @Bean
    @ConfigurationProperties(prefix = "spring.jta.atomikos.datasource.secondary")
    public DataSource secondaryDataSource() {
        return new AtomikosDataSourceBean();
    }

    @Bean
    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource primaryDataSource) {
        return new JdbcTemplate(primaryDataSource);
    }

    @Bean
    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("secondaryDataSource") DataSource secondaryDataSource) {
        return new JdbcTemplate(secondaryDataSource);
    }

}

創(chuàng)建一個測試Service用來校驗我們的JTA是否可以完成我們想要的工作。

@Service
public class TestService {

    private JdbcTemplate primaryJdbcTemplate;
    private JdbcTemplate secondaryJdbcTemplate;

    public TestService(JdbcTemplate primaryJdbcTemplate, JdbcTemplate secondaryJdbcTemplate) {
        this.primaryJdbcTemplate = primaryJdbcTemplate;
        this.secondaryJdbcTemplate = secondaryJdbcTemplate;
    }

    @Transactional
    public void tx() {
        // 修改test1庫中的數據
        primaryJdbcTemplate.update("update user set age = ? where name = ?", 30, "aaa");
        // 修改test2庫中的數據
        secondaryJdbcTemplate.update("update user set age = ? where name = ?", 30, "aaa");
    }

    @Transactional
    public void tx2() {
        // 修改test1庫中的數據
        primaryJdbcTemplate.update("update user set age = ? where name = ?", 40, "aaa");
        // 模擬:修改test2庫之前拋出異常
        throw new RuntimeException();
    }
}

在以上操作中,我們定義tx方法中,一般會成功,但tx2方法中,我們自己給他定義了一個異常,這個是在test1數據庫更新后才會產生的,這樣就可以測試一test1更新成功后,是否還能再JTA的幫助下實現回滾。

創(chuàng)建一個單元測試類:

@SpringBootTest(classes = Application.class)
public class ApplicationTests {

    @Autowired
    protected JdbcTemplate primaryJdbcTemplate;
    @Autowired
    protected JdbcTemplate secondaryJdbcTemplate;

    @Autowired
    private TestService testService;

    @Test
    public void test1() throws Exception {
        // 正確更新的情況
        testService.tx();
        Assertions.assertEquals(30, primaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));
        Assertions.assertEquals(30, secondaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));
    }

    @Test
    public void test2() throws Exception {
        // 更新失敗的情況
        try {
            testService.tx2();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 部分更新失敗,test1中的更新應該回滾
            Assertions.assertEquals(30, primaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));
            Assertions.assertEquals(30, secondaryJdbcTemplate.queryForObject("select age from user where name=?", Integer.class, "aaa"));
        }
    }
}

對以上測試用例:

test1:因為沒有故意制造的異常,一般情況下兩個庫的update都會成功,然后我們根據name=aaa去把兩個數據查出來,看age是否都被更新到了30。

test2:tx2函數會把test1中name=aaa的用戶age更新為40,然后拋出異常,JTA事務生效的話,會把age回滾回30,所以這里的檢查也是兩個庫的aaa用戶的age應該都為30,這樣就意味著JTA事務生效,保證了test1和test2兩個庫中的User表數據更新一致,沒有制造出臟數據。

以上就是SpringBoot使用JTA實現對多數據源的事務管理的詳細內容,更多關于SpringBoot JTA事務管理的資料請關注腳本之家其它相關文章!

相關文章

  • Java編程實現提取文章中關鍵字的方法

    Java編程實現提取文章中關鍵字的方法

    這篇文章主要介紹了Java編程實現提取文章中關鍵字的方法,較為詳細的分析了Java提取文章關鍵字的原理與具體實現技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11
  • Spring整合MyBatis圖示過程解析

    Spring整合MyBatis圖示過程解析

    這篇文章主要介紹了Spring整合MyBatis圖示過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • 初探Java中的泛型

    初探Java中的泛型

    這篇文章主要介紹了Java中泛型的相關資料,幫助大家更好的理解和學習Java,感興趣的朋友可以了解下
    2020-08-08
  • 教你怎么使用Optional處理null

    教你怎么使用Optional處理null

    今天教各位小伙伴怎么使用Optional處理null,文中有非常詳細的代碼示例,對正在學習java的小伙伴們有很大的幫助,需要的朋友可以參考下
    2021-05-05
  • 微服務springcloud 03.Eureka實現高可用的過程

    微服務springcloud 03.Eureka實現高可用的過程

    這篇文章主要介紹了微服務springcloud 03.Eureka實現高可用的相關資料,本文給大家介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • springboot中request和response的加解密實現代碼

    springboot中request和response的加解密實現代碼

    這篇文章主要介紹了springboot中request和response的加解密實現,在springboot中提供了RequestBodyAdviceAdapter和ResponseBodyAdvice,利用這兩個工具可以非常方便的對請求和響應進行預處理,需要的朋友可以參考下
    2022-06-06
  • Java?集合框架?Queue?和?Stack?體系

    Java?集合框架?Queue?和?Stack?體系

    這篇文章主要介紹了Java?集合框架Queue和Stack體系,Stack?繼承自Vector,并拓展了五個允許將容器視為棧結構的操作,Queue接口定義了隊列的能力,它繼承自Collection,更多相關內容需要得小伙伴可以參考一下
    2022-06-06
  • springmvc實現json交互-requestBody和responseBody

    springmvc實現json交互-requestBody和responseBody

    本文主要介紹了springmvc實現json交互-requestBody和responseBody的相關知識。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • Java中的Thread.join()詳解

    Java中的Thread.join()詳解

    這篇文章主要介紹了Thread.join()詳解?,join是Thread類的一個方法,啟動線程后直接調用,本文通過實例代碼介紹了join方法的作用及用法詳解,需要的朋友可以參考下
    2023-09-09
  • 10個經典的Java main方法面試題

    10個經典的Java main方法面試題

    這篇文章主要為大家分享了10個經典的Java main方法面試題,與其說是Java面試題,其實也是Java的一些最基礎知識問題,感興趣的小伙伴們可以參考一下
    2016-01-01

最新評論

梁平县| 栖霞市| 昂仁县| 永定县| 托克逊县| 广河县| 赣州市| 广州市| 荔波县| 横山县| 乌鲁木齐县| 万盛区| 承德市| 固始县| 马公市| 清水县| 伊金霍洛旗| 讷河市| 达拉特旗| 启东市| 莱芜市| 通江县| 荣成市| 上思县| 城口县| 沭阳县| 吉木乃县| 建水县| 岳西县| 山东省| 三都| 来宾市| 确山县| 根河市| 泸西县| 甘南县| 弥勒县| 井冈山市| 伊通| 孟州市| 根河市|