欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot2使用JTA組件實現基于JdbcTemplate多數據源事務管理(親測好用)

 更新時間:2022年08月23日 15:17:54   作者:十月圍城小童鞋  
這篇文章主要介紹了SpringBoot2使用JTA組件實現基于JdbcTemplate多數據源事務管理(親測好用),在Spring?Boot?2.x中,整合了這兩個JTA的實現分別是Atomikos和Bitronix,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下

一、JTA組件簡介

什么是JTA

JTA,全稱:Java Transaction API。JTA事務比JDBC事務更強大。一個JTA事務可以有多個參與者,而一個JDBC事務則被限定在一個單一的數據庫連接。所以,當我們在同時操作多個數據庫的時候,使用JTA事務就可以彌補JDBC事務的不足。

在Spring Boot 2.x中,整合了這兩個JTA的實現:

Atomikos:可以通過引入spring-boot-starter-jta-atomikos依賴來使用
Bitronix:可以通過引入spring-boot-starter-jta-bitronix依賴來使用

由于Bitronix自Spring Boot 2.3.0開始不推薦使用,所以在下面的動手環(huán)節(jié)中,我們將使用Atomikos作為例子來介紹JTA的使用。

什么是XA協(xié)議

XA協(xié)議是數據庫層面的一套分布式事務管理的規(guī)范,JTA是XA協(xié)議在Java中的實現,多個數據庫或是消息廠商實現JTA接口,開發(fā)人員只需要調用SpringJTA接口即可實現JTA事務管理功能。

二、SpringBoot整合JTA

準備工作

這里我們將使用最基礎的JdbcTemplate來實現數據訪問,所以如果你還不會使用JdbcTemplate配置多數據源,建議先看一JdbcTemplate的多數據源配置。

場景設定:

假設我們有兩個庫,分別為:test1和test2
這兩個庫中都有一張User表,我們希望這兩張表中的數據是一致的

假設這兩張表中都已經有一條數據:name=aaa,age=30;因為這兩張表中數據是一致的,所以要update的時候,就必須兩個庫中的User表更新時候,要么都成功,要么都失敗。

1、核心依賴

<!--JTA組件核心依賴-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jta-atomikos</artifactId>
</dependency>

2、環(huán)境配置

yml配置文件這里jtaManager的配置,在日志輸出中非常關鍵。

spring:
  jta:
    enabled: true
    transaction-manager-id: jtaManager
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
    driver-class-name: com.mysql.jdbc.Driver
  backdatasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&allowPublicKeyRetrieval=true
    driver-class-name: com.mysql.jdbc.Driver

3、jta組件配置類

package com.sgcc.qfjs.config;

import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.jta.atomikos.AtomikosDataSourceBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;


@Configuration
public class JtaDataSourceConfig {

    @Autowired
    private Environment env;

    @Autowired
    private DataSourceProperties properties;

    @Bean
    @Primary
    public DataSource primaryDatasource() {
        //數據庫鏈接
        MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
        mysqlXADataSource.setUrl(properties.getUrl());
        mysqlXADataSource.setUser(properties.getUsername());
        mysqlXADataSource.setPassword(properties.getPassword());
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
        //事務管理
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
        atomikosDataSourceBean.setUniqueResourceName("dataSource");
        return atomikosDataSourceBean;
    }

    @Bean
    public DataSource backDatasource() {
        //數據庫鏈接
        MysqlXADataSource mysqlXADataSource = new MysqlXADataSource();
        mysqlXADataSource.setUrl(env.getProperty("spring.backdatasource.url"));
        mysqlXADataSource.setUser(env.getProperty("spring.backdatasource.username"));
        mysqlXADataSource.setPassword(env.getProperty("spring.backdatasource.password"));
        mysqlXADataSource.setPinGlobalTxToPhysicalConnection(true);
        //事務管理
        AtomikosDataSourceBean atomikosDataSourceBean = new AtomikosDataSourceBean();
        atomikosDataSourceBean.setXaDataSource(mysqlXADataSource);
        atomikosDataSourceBean.setUniqueResourceName("backDataSource");
        return atomikosDataSourceBean;
    }

    @Bean("primaryTemplate")
    public JdbcTemplate primaryTemplate(){
        return new JdbcTemplate(primaryDatasource());
    }

    @Bean("backTemplate")
    public JdbcTemplate batchTemplate(){
        return new JdbcTemplate(backDatasource());
    }

}

4、創(chuàng)建一個Service實現,模擬兩種不同的情況。

@Service
@Slf4j
public class CatTestServiceImpl extends ServiceImpl<CatTestMapper, CatTest> implements CatTestService {

    @Autowired
    private JdbcTemplate primaryTemplate;
    @Autowired
    private JdbcTemplate backTemplate;

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

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

這里tx函數,是兩句update操作,一般都會成功;而tx2函數中,我們人為的制造了一個異常,這個異常是在test1庫中的數據更新后才產生的,這樣就可以測試一下test1更新成功,之后是否還能在JTA的幫助下實現回滾。

5、創(chuàng)建測試類,編寫測試用例

package com.sgcc.qfjs.hsf;

import com.sgcc.qfjs.module.service.CatTestService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class AppTest {

    @Autowired
    private CatTestService catTestService;

    @Test
    public void test1() throws Exception {
        // 正確更新的情況
        catTestService.tx();
    }

    @Test
    public void test2() throws Exception {
        // 更新失敗的情況
        try {
            catTestService.tx2();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

這里有兩個測試用例:

test1:因為沒有故意制造的異常,不出意外兩個庫的update都會成功,所以根據name=aaa去把兩個數據查出來,看age是否都被更新到了40。

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

6、測試驗證

執(zhí)行test1成功,查看數據庫數據是否更新成功

執(zhí)行test2成功,查看數據庫數據是否回滾成功

2022-07-28 11:09:04.999|DEBUG|main|com.atomikos.logging.Slf4jLogger|Line:32| XAResource.rollback ( 6A74614D616E61676572313635383937373734343831353030303031:6A74614D616E6167657231 ) on resource dataSource represented by XAResource instance com.mysql.jdbc.jdbc2.optional.JDBC4SuspendableXAConnection@339b45f8
2022-07-28 11:09:05.010|DEBUG|main|com.atomikos.logging.Slf4jLogger|Line:32| rollback() done of transaction jtaManager165897774481500001
2022-07-28 11:09:05.010|DEBUG|main|com.atomikos.logging.Slf4jLogger|Line:32| rollback() done of transaction jtaManager165897774481500001

到此這篇關于SpringBoot2使用JTA組件實現基于JdbcTemplate多數據源事務管理(親測好用)的文章就介紹到這了,更多相關SpringBoot2多數據源事務管理內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Java 如何讀取Excel格式xls、xlsx數據工具類

    Java 如何讀取Excel格式xls、xlsx數據工具類

    這篇文章主要介紹了Java 如何讀取Excel格式xls、xlsx數據工具類的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 詳解Java如何應對常見的安全威脅和攻擊類型

    詳解Java如何應對常見的安全威脅和攻擊類型

    隨著信息技術的快速發(fā)展,網絡安全問題日益突出,本文將以Java開發(fā)語言為例,深入探討網絡協(xié)議的安全性問題,通過分析常見的安全威脅和攻擊類型,設計和實施安全協(xié)議等主題,為讀者提供一些有益的思路和方法,需要的朋友可以參考下
    2023-11-11
  • Java 程序里transient關鍵字使用方法示例

    Java 程序里transient關鍵字使用方法示例

    這篇文章主要為大家介紹了Java 程序里transient關鍵字使用方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-11-11
  • 源碼分析Java中ThreadPoolExecutor的底層原理

    源碼分析Java中ThreadPoolExecutor的底層原理

    這篇文章主要帶大家從源碼分析一下Java中ThreadPoolExecutor的底層原理,文中的示例代碼講解詳細,具有一定的學習價值,需要的可以參考一下
    2023-05-05
  • Java 十大排序算法之歸并排序刨析

    Java 十大排序算法之歸并排序刨析

    歸并排序是采用分治法的一個非常典型的應用。先使每個子序列有序,再使子序列段間有序,也就是將已有的子序列合并,得到完全有序的序列;如果將兩個有序表合并成一個有序表,稱為二路歸并
    2021-11-11
  • Java mockito單元測試實現過程解析

    Java mockito單元測試實現過程解析

    這篇文章主要介紹了Java mockito單元測試實現過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • Java ArrayList的基本概念和作用及動態(tài)數組的機制與性能

    Java ArrayList的基本概念和作用及動態(tài)數組的機制與性能

    在Java中,ArrayList是一個實現了List接口的動態(tài)數組,它可以根據需要自動增加大小,因此可以存儲任意數量的元素,這篇文章主要介紹了探秘Java ArrayList的基本概念和作用及動態(tài)數組的機制與性能,需要的朋友可以參考下
    2023-12-12
  • Java拆箱與裝箱實例詳解

    Java拆箱與裝箱實例詳解

    這篇文章主要介紹了Java拆箱與裝箱,結合實例形式詳細分析了Java拆箱與裝箱相關的數據類型轉換操作技巧,需要的朋友可以參考下
    2019-11-11
  • Java中Future和FutureTask的示例詳解及使用

    Java中Future和FutureTask的示例詳解及使用

    Java中的Future和FutureTask通常和線程池搭配使用,用來獲取線程池返回執(zhí)行后的返回值,下面這篇文章主要給大家介紹了關于Java中Future和FutureTask使用的相關資料,需要的朋友可以參考下
    2021-11-11
  • java線程的基礎實例解析

    java線程的基礎實例解析

    這篇文章主要介紹了java線程的基礎實例解析,具有一定借鑒價值,需要的朋友可以參考下
    2017-12-12

最新評論