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

Spring?Boot?多數(shù)據(jù)源處理事務(wù)的思路詳解

 更新時(shí)間:2022年06月02日 11:05:14   作者:江南一點(diǎn)雨  
這篇文章主要介紹了Spring?Boot?多數(shù)據(jù)源如何處理事務(wù),本文單純就是技術(shù)探討,要從實(shí)際應(yīng)用中來說的話,我并不建議這樣去玩分布式事務(wù)、也不建議這樣去玩多數(shù)據(jù)源,畢竟分布式事務(wù)主要還是用在微服務(wù)場景下,對Spring?Boot?多數(shù)據(jù)源事務(wù)相關(guān)知識感興趣的朋友參考下本文

首先我先聲明一點(diǎn),本文單純就是技術(shù)探討,要從實(shí)際應(yīng)用中來說的話,我并不建議這樣去玩分布式事務(wù)、也不建議這樣去玩多數(shù)據(jù)源,畢竟分布式事務(wù)主要還是用在微服務(wù)場景下。

好啦,那就不廢話了,開整。

1. 思路梳理

首先我們來梳理一下思路。

在上篇文章中,我們是一個(gè)微服務(wù),在 A 中分別去調(diào)用 B 和 C,當(dāng) B 或者 C 有一個(gè)執(zhí)行失敗的時(shí)候,就去回滾。B 和 C 都是調(diào)用遠(yuǎn)程的服務(wù),所謂的回滾也不是傳統(tǒng)意義上的數(shù)據(jù)庫回滾,而是一種“反向補(bǔ)償”,即利用一條更新 SQL,將已經(jīng)更新的數(shù)據(jù)復(fù)原。在這個(gè)例子中,B 和 C 都是遠(yuǎn)程服務(wù),操作的也都是不同的數(shù)據(jù)庫,這不就是我們多數(shù)據(jù)源中的情況么!

在微服務(wù)中,一個(gè)服務(wù)實(shí)際上就代表了一個(gè)數(shù)據(jù)源,而在我們多數(shù)據(jù)源的案例中,一個(gè)注解就能標(biāo)記出來一個(gè)數(shù)據(jù)源,這樣一類比,你就會(huì)發(fā)現(xiàn)利用分布式事務(wù)來解決多數(shù)據(jù)源中的事務(wù)問題其實(shí)是非常 Easy 的。而且這里還不是微服務(wù)項(xiàng)目,只是一個(gè)單體項(xiàng)目,更簡單!

不過也有一些需要注意的細(xì)節(jié)。

2. 代碼實(shí)踐

接下來我們就結(jié)合代碼來講講。

2.1 案例準(zhǔn)備

首先多數(shù)據(jù)源的案例我就不重復(fù)寫了,我們之前已經(jīng)寫過一個(gè),這里就不再贅述,文章一開頭也有相關(guān)的鏈接,還沒看過的小伙伴可以先看看。

也可以直接在公眾號后臺回復(fù) dynamic_datasource 獲取相關(guān)的案例。

2.2 開始整活

因?yàn)樯掀恼挛抑饕呛痛蠹曳窒淼?seata 的 AT 模式,所以本文也是一樣,就先采用 AT 模式。

小伙伴們知道,在我們的多數(shù)據(jù)源案例中,我們用到了兩個(gè)庫,test08 和 test09,現(xiàn)在也還是這兩個(gè)庫,但是現(xiàn)在由于我們使用的是 AT 模式,我們需要在這兩個(gè)庫中分別創(chuàng)建 undo log 表,用來記錄我們對表的更新操作,當(dāng)事務(wù)提交之后,undo log 表中的數(shù)據(jù)就會(huì)被清除,undo log,undo log 表的腳本如下:

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

數(shù)據(jù)庫準(zhǔn)備好之后,接下來就是準(zhǔn)備依賴了,seata 有兩個(gè)依賴,一個(gè)是 seata-all,還有一個(gè)微服務(wù)版的,咱們這里就直接使用上篇文章中所用到的微服務(wù)版的,依賴如下:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.2.2.RELEASE</version>
</dependency>

配好之后,接下來提供兩個(gè)配置文件 file.conf 和 regsigry.conf,這兩個(gè)配置文件和上篇文章中介紹到的一模一樣,這里不再贅述。

接下來配置 application.yaml,如下:

spring:
  cloud:
    alibaba:
      seata:
        tx-service-group: my_test_tx_group
  main:
    allow-circular-references: true
seata:
  enable-auto-data-source-proxy: false
  application-id: dd

大家看下這里的幾個(gè)配置:

  • tx-service-group:這個(gè)是事務(wù)群組的名稱,相關(guān)名字是在 file.conf 中配置的。
  • allow-circular-references:這個(gè)是允許循環(huán)依賴,可能有的小伙伴已經(jīng)知道,現(xiàn)在最新版的 Spring Boot 中已經(jīng)禁掉了循環(huán)依賴,但是這個(gè) seata 中似乎還是用到了循環(huán)依賴,所以要開啟。
  • enable-auto-data-source-proxy:由于 seata 會(huì)自動(dòng)代理數(shù)據(jù)源,但是我們現(xiàn)在的數(shù)據(jù)源是自己加載的,所以關(guān)閉掉這個(gè)數(shù)據(jù)源的自動(dòng)代理,將來用自己的。
  • application-id:給我們的應(yīng)用取一個(gè)名字。

好啦,這個(gè)文件就配置好了。

接下來就是數(shù)據(jù)源問題了,剛剛說了,seata 中會(huì)自動(dòng)代理數(shù)據(jù)源,用到的代理對象是 DataSourceProxy,而我們在之前自定義的數(shù)據(jù)源加載中,并沒有用到這個(gè) DataSourceProxy 對象所以這里要稍作修改,一共改兩個(gè)地方,如下:

LoadDataSource.java

@Component
@EnableConfigurationProperties(DruidProperties.class)
public class LoadDataSource {
    @Autowired
    DruidProperties druidProperties;

    public Map<String, DataSourceProxy> loadAllDataSource() {
        Map<String, DataSourceProxy> map = new HashMap<>();
        Map<String, Map<String, String>> ds = druidProperties.getDs();
        try {
            Set<String> keySet = ds.keySet();
            for (String key : keySet) {
                DataSource dataSource = druidProperties.dataSource((DruidDataSource) DruidDataSourceFactory.createDataSource(ds.get(key)));
                DataSourceProxy proxyDs = new DataSourceProxy(dataSource);
                map.put(key, proxyDs);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }
}

其實(shí)這里的改動(dòng)就是把之前的 DataSource 用 DataSourceProxy 重新包裹一下,然后將獲取到的 DataSourceProxy 存起來。最后再修改一下動(dòng)態(tài)數(shù)據(jù)源的地方:

@Component
public class DynamicDataSource extends AbstractRoutingDataSource {

    public DynamicDataSource(LoadDataSource loadDataSource) {
        //1.設(shè)置所有的數(shù)據(jù)源
        Map<String, DataSourceProxy> allDs = loadDataSource.loadAllDataSource();
        super.setTargetDataSources(new HashMap<>(allDs));
        //2.設(shè)置默認(rèn)的數(shù)據(jù)源
        //將來,并不是所有的方法上都有 @DataSource 注解,對于那些沒有 @DataSource 注解的方法,該使用哪個(gè)數(shù)據(jù)源?
        super.setDefaultTargetDataSource(allDs.get(DataSourceType.DEFAULT_DS_NAME));
        //3
        super.afterPropertiesSet();
    }

    /**
     * 這個(gè)方法用來返回?cái)?shù)據(jù)源名稱,當(dāng)系統(tǒng)需要獲取數(shù)據(jù)源的時(shí)候,會(huì)自動(dòng)調(diào)用該方法獲取數(shù)據(jù)源的名稱
      * @return
     */
    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceType();
    }
}

Map 中的 value 類型變?yōu)?DataSourceProxy,其他都不變。

另外還有一個(gè)地方要改造下,就是解析 @DataSource 注解的切面,在之前的解析中,我們是將異常捕獲了,現(xiàn)在我們要將之拋出來,如下:

@Around("pc()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
    //獲取方法上面的有效注解
    DataSource dataSource = getDataSource(pjp);
    if (dataSource != null) {
        //獲取注解中數(shù)據(jù)源的名稱
        String value = dataSource.value();
        DynamicDataSourceContextHolder.setDataSourceType(value);
    }
    try {
        return pjp.proceed();
    } finally {
        DynamicDataSourceContextHolder.clearDataSourceType();
    }
}

將之拋出來的原因也很簡單,因?yàn)檫@是切面方法,所有的 service 層方法都在這里執(zhí)行,如果將異常捕獲了,將來 service 層方法不拋出異常,事務(wù)就沒法生效了。

好了,現(xiàn)在準(zhǔn)備工作就算是到位了。

接下來我們寫一個(gè)簡單的多數(shù)據(jù)源事務(wù)的案例,首先我們來創(chuàng)建一個(gè) MasterService,專門用來操作 master 數(shù)據(jù)源:

@Service
public class MasterService {
    @Autowired
    MasterMapper masterMapper;

    @DataSource("master")
    public void addUser(String username, Integer age) {
        masterMapper.addUser(username, age);
    }
}

mapper 就不用看了吧,就是普通的添加,大家可以在文末下載本文案例案例。

再來一個(gè) SlaveService,用來操作 slave 數(shù)據(jù)源:

@Service
public class SlaveService {
    @Autowired
    SlaveMapper slaveMapper;

    @DataSource("slave")
    public void addAccount(String name, Double balance) {
        int i = 1 / 0;
        slaveMapper.addAccount(name, balance);
    }
}

slave 數(shù)據(jù)源的方法中有一個(gè)異常。

最后,我們在 UserService 中分別調(diào)用這兩個(gè)方法:

@Service
public class UserService {
    @Autowired
    MasterService masterService;
    @Autowired
    SlaveService slaveService;

    @GlobalTransactional(rollbackFor = Exception.class)
    public void test() {
        masterService.addUser("javaboy.org", 99);
        slaveService.addAccount("javaboy.org", 99.0);
    }
}

注意,test 方法上有一個(gè)全局事務(wù)注解。

好啦,齊活!現(xiàn)在我們?nèi)?zhí)行這個(gè) test 方法,由于 slaveService#addAccount 中的方法會(huì)拋出異常,所以會(huì)導(dǎo)致整個(gè)事務(wù)回滾,最終的結(jié)果就是 master 中也沒有添加進(jìn)數(shù)據(jù)。

3. 總結(jié)

好啦,結(jié)合上一篇文章,相信大家應(yīng)該能夠熟練的使用 seata 分布式事務(wù)中的 at 模式了吧!

到此這篇關(guān)于Spring Boot 多數(shù)據(jù)源處理事務(wù)的思路詳解的文章就介紹到這了,更多相關(guān)Spring Boot 多數(shù)據(jù)源處理事務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java高并發(fā)鎖的3種實(shí)現(xiàn)示例代碼

    java高并發(fā)鎖的3種實(shí)現(xiàn)示例代碼

    本篇文章主要介紹了java高并發(fā)鎖的3種實(shí)現(xiàn)示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • Java 對象序列化 NIO NIO2詳細(xì)介紹及解析

    Java 對象序列化 NIO NIO2詳細(xì)介紹及解析

    這篇文章主要介紹了Java 對象序列化 NIO NIO2詳細(xì)介紹及解析的相關(guān)資料,序列化機(jī)制可以使對象可以脫離程序的運(yùn)行而對立存在,需要的朋友可以參考下
    2017-02-02
  • 解決SpringBoot application.yaml文件配置schema 無法執(zhí)行sql問題

    解決SpringBoot application.yaml文件配置schema 無法執(zhí)行sql問題

    這篇文章主要介紹了解決SpringBoot application.yaml文件配置schema 無法執(zhí)行sql問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java類加載策略之雙親委派機(jī)制全面分析講解

    Java類加載策略之雙親委派機(jī)制全面分析講解

    這篇文章主要介紹了Java雙親委派機(jī)制,雙親委派模型是Java加載類的機(jī)制,采用雙親委派模型的好處是Java類隨著它的類加載器一起具備了一種帶有優(yōu)先級的層級關(guān)系,通過這種層級關(guān)系可以避免類的重復(fù)加載,感興趣的朋友可以參考下
    2023-12-12
  • Spring Controller接收前端JSON數(shù)據(jù)請求方式

    Spring Controller接收前端JSON數(shù)據(jù)請求方式

    這篇文章主要為大家介紹了Spring Controller接收前端JSON數(shù)據(jù)請求方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-07-07
  • Redisson 分布式延時(shí)隊(duì)列 RedissonDelayedQueue 運(yùn)行流程

    Redisson 分布式延時(shí)隊(duì)列 RedissonDelayedQueue 運(yùn)行流程

    這篇文章主要介紹了Redisson分布式延時(shí)隊(duì)列 RedissonDelayedQueue運(yùn)行流程,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • jackson序列化和反序列化的應(yīng)用實(shí)踐指南

    jackson序列化和反序列化的應(yīng)用實(shí)踐指南

    這篇文章主要給大家介紹了關(guān)于jackson序列化和反序列化的應(yīng)用實(shí)踐指南,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • SpringBoot項(xiàng)目加載配置文件的6種方式小結(jié)

    SpringBoot項(xiàng)目加載配置文件的6種方式小結(jié)

    這篇文章給大家總結(jié)了六種SpringBoot項(xiàng)目加載配置文件的方式,通過@value注入,通過@ConfigurationProperties注入,通過框架自帶對象Environment實(shí)現(xiàn)屬性動(dòng)態(tài)注入,通過@PropertySource注解,yml外部文件,Java原生態(tài)方式注入這六種,需要的朋友可以參考下
    2023-09-09
  • Java設(shè)計(jì)模式之抽象工廠模式

    Java設(shè)計(jì)模式之抽象工廠模式

    這篇文章主要為大家詳細(xì)介紹了Java設(shè)計(jì)模式之抽象工廠模式的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Java-Java5.0注解全面解讀

    Java-Java5.0注解全面解讀

    這篇文章主要介紹了Java-Java5.0注解全面解讀,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評論