溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Spring加入事務(wù)和嵌套事務(wù)的區(qū)別是什么

發(fā)布時(shí)間:2022-10-17 13:50:01 來(lái)源:億速云 閱讀:179 作者:iii 欄目:編程語(yǔ)言

本文小編為大家詳細(xì)介紹“Spring加入事務(wù)和嵌套事務(wù)的區(qū)別是什么”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“Spring加入事務(wù)和嵌套事務(wù)的區(qū)別是什么”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來(lái)學(xué)習(xí)新知識(shí)吧。

1.加入事務(wù)

加入事務(wù) REQUIRED 是 Spring 事務(wù)的默認(rèn)傳播級(jí)別。

所謂的加入當(dāng)前事務(wù),是指如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒(méi)有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。我們這里重點(diǎn)要討論的是第一種情況,也就是當(dāng)前存在事務(wù)的情況下,它和嵌套事務(wù)的區(qū)別,接下來(lái)我們通過(guò)一個(gè)示例來(lái)看加入事務(wù)的使用和執(zhí)行特點(diǎn)。

我們要實(shí)現(xiàn)的是用戶添加功能,只不過(guò)在添加用戶時(shí),我們需要給用戶表和日志表中分別插入一條數(shù)據(jù),UserController 實(shí)現(xiàn)代碼如下:

@Transactional(propagation = Propagation.REQUIRED)
@RequestMapping("/add")
public int add(UserInfo userInfo) {
    int result = 0;
    int userResult = userService.add(userInfo);
    System.out.println("用戶添加結(jié)果:" + userResult);
    if (userResult > 0) {
        LogInfo logInfo = new LogInfo();
        logInfo.setName("添加用戶");
        logInfo.setDesc("添加用戶結(jié)果:" + userResult);
        int logResult = logService.add(logInfo);
        System.out.println("日志添加結(jié)果:" + logResult);
        result = 1;
    }
    return result;
}

從上述代碼可以看出,添加用戶使用了事務(wù),并設(shè)置了事務(wù)傳播機(jī)制為 REQUIRED(加入事務(wù)),此控制器調(diào)用的 UserService 實(shí)現(xiàn)代碼如下:

@Transactional(propagation = Propagation.REQUIRED)
public int add(UserInfo userInfo) {
    int result = userMapper.add(userInfo);
    return result;
}

從上述代碼可以看出,它也是使用事務(wù),并設(shè)置了事務(wù)的傳播機(jī)制為 REQUIRED,而 LogService 也是類似的實(shí)現(xiàn)代碼:

@Transactional(propagation = Propagation.REQUIRED)
public int add(LogInfo logInfo) {
    int result = logMapper.add(logInfo);
    try {
        int number = 10 / 0;
    } catch (Exception e) {
        // 手動(dòng)回滾事務(wù)
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
    return result;
}

從上述代碼我們可以看出,在設(shè)置事務(wù)傳播機(jī)制的同時(shí),我們也在程序中主動(dòng)的設(shè)置了一個(gè)異常。

運(yùn)行以上程序的執(zhí)行結(jié)果如下圖所示:

Spring加入事務(wù)和嵌套事務(wù)的區(qū)別是什么

從上述結(jié)果我們可以看出:當(dāng)我們?cè)O(shè)置了加入事務(wù)的事務(wù)傳播機(jī)制之后,程序的執(zhí)行結(jié)果是將用戶表和日志表的事務(wù)都回滾了。

2.嵌套事務(wù)

嵌套事務(wù)指的是事務(wù)傳播級(jí)別中的 NESTED,所謂的嵌套當(dāng)前事務(wù),是指如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果當(dāng)前沒(méi)有事務(wù),則該取值等價(jià)于 REQUIRED。當(dāng)然,我們本文要研究的重點(diǎn)也是第一種情況,也就是當(dāng)前存在事務(wù)的前提下,嵌套事務(wù)和加入事務(wù)的區(qū)別。

所以接下來(lái)我們將上面代碼中的事務(wù)傳播機(jī)制改為 NESTED,它的實(shí)現(xiàn)代碼如下。 UserController 實(shí)現(xiàn)代碼如下:

@Transactional(propagation = Propagation.NESTED)
@RequestMapping("/add")
public int add(UserInfo userInfo) {
    int result = 0;
    int userResult = userService.add(userInfo);
    System.out.println("用戶添加結(jié)果:" + userResult);
    if (userResult > 0) {
        LogInfo logInfo = new LogInfo();
        logInfo.setName("添加用戶");
        logInfo.setDesc("添加用戶結(jié)果:" + userResult);
        int logResult = logService.add(logInfo);
        System.out.println("日志添加結(jié)果:" + logResult);
        result = 1;
    }
    return result;
}

UserService 實(shí)現(xiàn)代碼如下:

@Transactional(propagation = Propagation.NESTED)
public int add(UserInfo userInfo) {
    int result = userMapper.add(userInfo);
    return result;
}

LogService 實(shí)現(xiàn)代碼如下:

@Transactional(propagation = Propagation.NESTED)
public int add(LogInfo logInfo) {
    int result = logMapper.add(logInfo);
    try {
        int number = 10 / 0;
    } catch (Exception e) {
        // 手動(dòng)回滾事務(wù)
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
    return result;
}

運(yùn)行以上程序的執(zhí)行結(jié)果如下圖所示:

Spring加入事務(wù)和嵌套事務(wù)的區(qū)別是什么

從上述結(jié)果可以看出:當(dāng)設(shè)置嵌套事務(wù)的事務(wù)傳播級(jí)別之后,程序執(zhí)行了部分事務(wù)的回滾,用戶表添加的事務(wù)沒(méi)有回滾,只是日志表的事務(wù)回滾了。

3.加入事務(wù) VS 嵌套事務(wù)

加入事務(wù)(REQUIRED)和嵌套事務(wù)(NESTED)都是事務(wù)傳播機(jī)制的兩種傳播級(jí)別,如果當(dāng)前不存在事務(wù),那么二者的行為是一樣的;但如果當(dāng)前存在事務(wù),那么加入事務(wù)的事務(wù)傳播級(jí)別在遇到異常之后,會(huì)將事務(wù)全部回滾;而嵌套事務(wù)在遇到異常時(shí),只是執(zhí)行了部分事務(wù)的回滾。

4.嵌套事務(wù)實(shí)現(xiàn)原理

事務(wù)全部回滾很好理解,這本來(lái)就是事務(wù)原子性的一種體現(xiàn),而嵌套事務(wù)中的部分事務(wù)回滾是怎么實(shí)現(xiàn)的呢?

嵌套事務(wù)只所以能實(shí)現(xiàn)部分事務(wù)的回滾,是因?yàn)樵跀?shù)據(jù)庫(kù)中存在一個(gè)保存點(diǎn)(savepoint)的概念,以 MySQL 為例,嵌套事務(wù)相當(dāng)于新建了一個(gè)保存點(diǎn),而滾回時(shí)只回滾到當(dāng)前保存點(diǎn),因此之前的事務(wù)是不受影響的,這一點(diǎn)可以在 MySQL 的官方文檔匯總找到相應(yīng)的資料。

而 REQUIRED 是加入到當(dāng)前事務(wù)中,并沒(méi)有創(chuàng)建事務(wù)的保存點(diǎn),因此出現(xiàn)了回滾就是整個(gè)事務(wù)回滾,這就是嵌套事務(wù)和加入事務(wù)的區(qū)別。

保存點(diǎn)就像玩通關(guān)游戲時(shí)的“游戲存檔”一樣,如果設(shè)置了游戲存檔,那么即使當(dāng)前關(guān)卡失敗了,也能繼續(xù)上一個(gè)存檔點(diǎn)繼續(xù)玩,而不是從頭開(kāi)始玩游戲。

讀到這里,這篇“Spring加入事務(wù)和嵌套事務(wù)的區(qū)別是什么”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識(shí)點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過(guò)才能領(lǐng)會(huì),如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI