国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring Boot 事務(wù)和事務(wù)傳播機制

這篇具有很好參考價值的文章主要介紹了Spring Boot 事務(wù)和事務(wù)傳播機制。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1. 為什么需要事務(wù)?

事務(wù)定義

將一組操作封裝成一個執(zhí)行單元 (封裝到一起),這一組的執(zhí)行具備原子性, 那么就要么全部成功,要么全部失敗.

為什么要用事務(wù)?

比如轉(zhuǎn)賬分為兩個操作:

第一步操作:A 賬戶-100 元。
第二步操作:B賬戶 +100 元。

如果沒有事務(wù),第一步執(zhí)行成功了,第二步執(zhí)行失敗了,那么 A 賬戶平白無故的 100 元就“人間蒸發(fā)”了。而如果使用事務(wù)就可以解決這個問題,讓這一組操作要么一起成功,要么一起失敗。

2. Spring中事務(wù)的實現(xiàn)

Spring中的事務(wù)操作分為兩類:

  1. 編程式事務(wù)(手動寫代碼操作事務(wù))
  2. 聲明式事務(wù)(利用注解自動開啟和提交事務(wù))

在開始講解它們之前,咱們先來回顧事務(wù)在MSQL 中是如何使用的?

2.1 MySQL中的事務(wù)使用

事務(wù)在 MySQL 有 3個重要的操作: 開啟事務(wù)、提交事務(wù)、回滾事務(wù),它們對應(yīng)的操作命令如下:

-- 開啟事務(wù)
start transaction;
-- 業(yè)務(wù)執(zhí)行

-- 提交事務(wù)
commit;

-- 回滾事務(wù)
rollback;

2.2 Spring 編程式事務(wù)(手動)

Spring 手動操作事務(wù)和上面MySQL 操作事務(wù)類似,它也是有3個重要操作步驟:

  • 開啟事務(wù)(獲取事務(wù))
  • 提交事務(wù)
  • 回滾事務(wù)

SpringBoot 內(nèi)置了兩個對象,DataSourceTransactionManager 用來獲取事務(wù)(開啟事務(wù))、提交或回滾事務(wù)的,而 TransactionDefinition 是事務(wù)的屬性,在獲取事務(wù)的時候需要將TransactionDefinition 傳遞進去從而獲得一個事務(wù) TransactionStatus,實現(xiàn)代碼如下:

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    // 編程式事務(wù)
    // JDBC 事務(wù)管理器
    @Autowired
    private DataSourceTransactionManager transactionManager;
    // 定義事務(wù)屬性 (使用TransactionDefinition記錄事務(wù)屬性)
    @Autowired
    private TransactionDefinition transactionDefinition;

    @RequestMapping("/del")
    public int del(Integer id) {
        if (id == null || id <= 0) return 0;
        // 1. 開啟事務(wù)
        TransactionStatus transactionStatus = null;
        int result = 0;
        try {
            transactionStatus = transactionManager.getTransaction(transactionDefinition);
            // 業(yè)務(wù)操作: 刪除用戶
            result = userService.del(id);
            System.out.println("刪除: " + result);
            // 2. 提交事務(wù) / 回滾事務(wù)
//            transactionManager.commit(transactionStatus); // 提交事務(wù)
        } catch (Exception e) {
            if (transactionStatus != null) {
                transactionManager.rollback(transactionStatus); // 回滾事務(wù)
            }
        }
        return result;
    }
}

業(yè)務(wù)操作相關(guān)代碼如下:

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    public int del(Integer id){
        return userMapper.del(id);
    }
}
@Mapper
public interface UserMapper {
    int del(@Param("id") Integer id);
}
    <delete id="del">
        delete from userinfo where id=#{id}
    </delete>

運行結(jié)果:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

可以看到, 刪除的業(yè)務(wù)操作已經(jīng)成功了, 但是因為回滾操作, 所以在執(zhí)行前后查詢數(shù)據(jù)庫的時候是可以看到對應(yīng)的數(shù)據(jù)依然存在.

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

從上述代碼可以看出,以上代碼雖然可以實現(xiàn)事務(wù),但操作也很繁瑣,有沒有更簡單的實現(xiàn)方法呢?請看下面聲明式事務(wù)。

2.3 Spring 聲明式事務(wù) (自動)

聲明式事務(wù)的實現(xiàn)很簡單,只需要在需要的方法上添加 @Transactional 注解就可以實現(xiàn)了,無需手動開啟事務(wù)和提交事務(wù),進入方法時自動開啟事務(wù),方法執(zhí)行完會自動提交事務(wù),如果中途發(fā)生了沒有處理的異常會自動回滾事務(wù),具體實現(xiàn)代碼如下:

@RestController
@RequestMapping("/user2")
public class UserController2 {

    @Autowired
    private UserService userService;

    @Transactional  // 在方法開始之前開啟事務(wù), 方法正常執(zhí)行結(jié)束之后提交事務(wù), 如果執(zhí)行途中發(fā)生異常, 則回滾事務(wù).
    @RequestMapping("/del")
    public int del(Integer id) {
        if (id == null || id <= 0) return 0;
        return userService.del(id);
    }
}                  

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

執(zhí)行前后查詢數(shù)據(jù)庫, 可以看到由于正常執(zhí)行所以沒有觸發(fā)回滾.

2.3.1 @Transactional作用范圍

@Transactional 可以用來修飾方法或類

  • 修飾方法時:需要注意只能應(yīng)用到 public 方法上,否則不生效。推薦此種用法
  • 修飾類時:表明該注解對該類中所有的 public 方法都生效。

2.3.2 @Transactional 參數(shù)說明

參數(shù)

作用

value

當(dāng)配置了多個事務(wù)管理器時,可以使用該屬性指定選擇哪個事務(wù)管理器

transactionManager

當(dāng)配置了多個事務(wù)管理器時,可以使用該屬性指定選擇哪個事務(wù)管理器

propagation

事務(wù)的傳播行為,默認值為 Propagation.REQUIRED

isolation

事務(wù)的隔離級別.默認值為 Isolation.DEFAULT

timeout

事務(wù)的超時時間,默認值為-1. 如果超過該時間限制但事務(wù)還沒有完成,則自動回滾事務(wù).

readOnly

指定事務(wù)是否為只讀事務(wù).默認值為 false;

為了忽略那些不需要事務(wù)的方法,比如讀取數(shù)據(jù)可以設(shè)置read-only為 true.

rollbackFor

用于指定能夠觸發(fā)事務(wù)回滾的異常類型,可以指定多個異常類型

rollbackForClassName

用于指定能夠觸發(fā)事務(wù)回滾的異常類型,可以指定多個異常類型

noRollbackFor

拋出指定的異常類型,不回滾事務(wù),也可以指定多個異常類型

noRollbackForClassName

拋出指定的異常類型,不回滾事務(wù),也可以指定多個異常類型

2.3.3 注意事項

@Transactional 在異常被捕獲的情況下,不會進行事務(wù)自動回滾,驗證以下代碼是否會發(fā)生事務(wù)回滾:

@RestController
@RequestMapping("/user2")
public class UserController2 {
    @Autowired
    private UserService userService;

    @Transactional 
    @RequestMapping("/del")
    public int del(Integer id) {
        if (id == null || id <= 0) return 0;
        int result = userService.del(id);
        System.out.println("刪除: " + result);
        try {
            int num = 10 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        return result;
    }
}                  

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

執(zhí)行前后查詢數(shù)據(jù)庫, 可以看到在異常被捕獲的情況下,并不會進行事務(wù)自動回滾.

事務(wù)不會自動回滾解決方案
解決方案1

對于捕獲的異常,事務(wù)是會自動回滾的,因此解決方案1就是可以將異常重新拋出,具體實現(xiàn)如下:

@RestController
@RequestMapping("/user2")
public class UserController2 {
    @Autowired
    private UserService userService;

    @Transactional 
    @RequestMapping("/del")
    public int del(Integer id) {
        if (id == null || id <= 0) return 0;
        int result = userService.del(id);
        System.out.println("刪除: " + result);
        try {
            int num = 10 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw e;
        }
        return result;
    }
}                  

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

執(zhí)行前后查詢數(shù)據(jù)庫, 可以看到這里是有異常, 觸發(fā)了回滾.

解決方案2

手動回滾事務(wù),在方法中使用 TransactionAspectSupport.currentTransactionStatus() 可以得到當(dāng)前的事務(wù),然后設(shè)置回滾方法 setRollbackOnly 就可以實現(xiàn)回滾了,具體實現(xiàn)代碼如下:

public class UserController2 {
        // .. 省略代碼, 同上
        try {
            int num = 10 / 0;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            // 手動回滾事務(wù)
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        return result;
    }
}                  

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

執(zhí)行前后訪問數(shù)據(jù)庫可以看到, 這里成功實現(xiàn)了回滾操作.

2.3.4 @Transactional 工作原理

@Transactional 是基于 AOP 實現(xiàn)的,AOP 又是使用動態(tài)代理實現(xiàn)的。如果目標(biāo)對象實現(xiàn)了接口,默認情況下會采用JDK 的動態(tài)代理,如果目標(biāo)對象沒有實現(xiàn)了接口,會使用CGLIB 動態(tài)代理。

@Transactional 在開始執(zhí)行業(yè)務(wù)之前,通過代理先開啟事務(wù),在執(zhí)行成功之后再提交事務(wù)。如果中途遇到的異常,則回滾事務(wù)。

@Transactional 實現(xiàn)思路預(yù)覽:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

@Transactional 具體執(zhí)行細節(jié)如下圖所示:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

3. 事務(wù)隔離級別

3.1 事務(wù)特性回顧

事務(wù)有4 大特性 (ACID),原子性、持久性、一致性和隔離性,具體概念如下:

  • 原子性: 一個事務(wù)(transaction)中的所有操作,要么全部完成,要么全部不完成,不會結(jié)束在中間某個環(huán)節(jié)。事務(wù)在執(zhí)行過程中發(fā)生錯誤,會被回滾 (Rollback)到事務(wù)開始前的狀態(tài),就像這個事務(wù)從來沒有執(zhí)行過一樣。
  • 一致性: 在事務(wù)開始之前和事務(wù)結(jié)束以后,數(shù)據(jù)庫的完整性沒有被破壞。這表示寫入的資料必須完全符合所有的預(yù)設(shè)規(guī)則,這包含資料的精確度、串聯(lián)性以及后續(xù)數(shù)據(jù)庫可以自發(fā)性地完成預(yù)定的工作。
  • 持久性: 事務(wù)處理結(jié)束后,對數(shù)據(jù)的修改就是永久的,即便系統(tǒng)故障也不會丟失。
  • 隔離性: 數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時對其數(shù)據(jù)進行讀寫和修改的能力,隔離性可以防止多個事務(wù)并發(fā)執(zhí)行時由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致。事務(wù)隔離分為不同級別,包括讀未提交 (Read uncommitted)、讀提交 (read committed) 、可重復(fù)讀 (repeatable read) 和串行化(Serializable)。

上面 4個屬性,可以簡稱為ACID

原子性 (Atomicity,或稱不可分割性)
一致性 (Consistency)
隔離性 (lsolation,又稱獨立性)
持久性 (Durability)

而這 4 種特性中,只有隔離性 (隔離級別) 是可以設(shè)置的。

為什么要設(shè)置事務(wù)的隔離級別?

設(shè)置事務(wù)的隔離級別是用來保障多個并發(fā)事務(wù)執(zhí)行更可控,更符合操作者預(yù)期的。

什么是可控呢?

比如近幾年比較嚴重的新冠病毒,我們會把直接接觸到確診病例的人員隔離到酒店,而把間接接觸者 (和直接接觸著但未確診的人) 隔離在自己的家中,也就是針對不同的人群,采取不同的隔離級別,這種隔離方式就和事務(wù)的隔離級別類似,都是采取某種行動讓某個事件變的“更可控”。而事務(wù)的隔離級別就是為了防止,其他的事務(wù)影響當(dāng)前事務(wù)執(zhí)行的一種策略。

3.2 Spring 中設(shè)置事務(wù)隔離級別

Spring 中事務(wù)隔離級別可以通過 @Transactional 中的 isolation 屬性進行設(shè)置,具體操作如下圖所示:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

3.2.1 MySQL事務(wù)隔離級別有 4 種

  1. READ UNCOMMITTED: 讀未提交,也叫未提交讀,該隔離級別的事務(wù)可以看到其他事務(wù)中未提交的數(shù)據(jù)。該隔離級別因為可以讀取到其他事務(wù)中未提交的數(shù)據(jù),而未提交的數(shù)據(jù)可能會發(fā)生回滾,因此我們把該級別讀取到的數(shù)據(jù)稱之為臟數(shù)據(jù),把這個問題稱之為臟讀。
  2. READ COMMITTED: 讀已提交,也叫提交讀,該隔離級別的事務(wù)能讀取到已經(jīng)提交事務(wù)的數(shù)據(jù),因此它不會有臟讀問題。但由于在事務(wù)的執(zhí)行中可以讀取到其他事務(wù)提交的結(jié)果,所以在不同時間的相同 SQL查詢中,可能會得到不同的結(jié)果,這種現(xiàn)象叫做不可重復(fù)讀。
  3. REPEATABLE READ: 可重復(fù)讀,是MySQL的默認事務(wù)隔離級別,它能確保同一事務(wù)多次查詢的結(jié)果一致。但也會有新的問題,比如此級別的事務(wù)正在執(zhí)行時,另一個事務(wù)成功的插入了某條數(shù)據(jù),但因為它每次查詢的結(jié)果都是一樣的,所以會導(dǎo)致查詢不到這條數(shù)據(jù),自己重復(fù)插入時又失敗(因為唯一約束的原因)。明明在事務(wù)中查詢不到這條信息,但自己就是插入不進去,這就叫幻讀(Phantom Read)
  4. SERIALIZABLE: 序列化,事務(wù)最高隔離級別,它會強制事務(wù)排序,使之不會發(fā)生沖突,從而解決了臟讀、不可重復(fù)讀和幻讀問題,但因為執(zhí)行效率低,所以真正使用的場景并不多

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

1. 臟讀: 一個事務(wù)讀取到了另一個事務(wù)修改的數(shù)據(jù)之后,后一個事務(wù)又進行了回滾操作,從而導(dǎo)致第一個事務(wù)讀取的數(shù)據(jù)是錯誤的。
2. 不可重復(fù)讀: 一個事務(wù)兩次查詢得到的結(jié)果不同,因為在兩次查詢中間,有另一個事務(wù)把數(shù)據(jù)修改了。
3. 幻讀: 一個事務(wù)兩次查詢中得到的結(jié)果集不同,因為在兩次查詢中另一個事務(wù)有新增了一部分數(shù)據(jù)。

在數(shù)據(jù)庫中通過以下SQL 查詢?nèi)质聞?wù)隔離級別和當(dāng)前連接的事務(wù)隔離級別:

select @@global.tx_isolation,@@tx_isolation;

以上SQL的執(zhí)行結(jié)果如下:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

3.2.2 Spring 中事務(wù)隔離級別有 5 種

Spring 中事務(wù)隔離級別包含以下 5 種:

  1. Isolation.DEFAULT: 以連接的數(shù)據(jù)庫的事務(wù)隔離級別為主
  2. lsolation.READ_UNCOMMITTED: 讀未提交,可以讀取到未提交的事務(wù),存在臟讀
  3. Isolation.READ_COMMITTED: 讀已提交,只能讀取到已經(jīng)提交的事務(wù),解決了臟讀,存在不可重復(fù)讀。
  4. Isolation.REPEATABLE_READ: 可重復(fù)讀,解決了不可重復(fù)讀,但存在幻讀(MVSQL默認級
  5. lsolation.SERIALIZABLE: 串行化,可以解決所有并發(fā)問題,但性能太低。

從上述介紹可以看出,相比于 MySQL 的事務(wù)隔離級別,Spring 的事務(wù)隔離級別只是多了一個lsolation.DEFAULT (以數(shù)據(jù)庫的全局事務(wù)隔離級別為主)。

Spring 中事務(wù)隔離級別只需要設(shè)置 @Transactional 里的 isolation 屬性即可,具體實現(xiàn)代碼如下:

@RequestMapping("/save")
@Transactional(isolation = Isolation.SERIALIZABLE)
public Object save(User user) {
    // 業(yè)務(wù)實現(xiàn)
}

4. Spring 事務(wù)傳播機制

4.1 事務(wù)傳播機制是什么?

Spring 事務(wù)傳播機制定義了多個包含了事務(wù)的方法,相互調(diào)用時,事務(wù)是如何在這些方法間進行傳遞的。

4.2 為什么需要事務(wù)傳播機制?

事務(wù)隔離級別是保證多個并發(fā)事務(wù)執(zhí)行的可控性的(穩(wěn)定性的),而事務(wù)傳播機制是保證一個事務(wù)在多個調(diào)用方法間的可控性的 (穩(wěn)定性的)。

例子: 像新冠病毒一樣,它有不同的隔離方式(酒店隔離還是居家隔離),是為了保證疫情可控,然而在每個人的隔離過程中,會有很多個執(zhí)行的環(huán)節(jié),比如酒店隔離,需要負責(zé)人員運送、物品運送消殺原生活區(qū)域、定時核算檢查和定時送餐等很多環(huán)節(jié),而事務(wù)傳播機制就是保證一個事務(wù)在傳遞過程中是可靠性的,回到本身案例中就是保證每個人在隔離的過程中可控的。

事務(wù)隔離級別解決的是多個事務(wù)同時調(diào)用一個數(shù)據(jù)庫的問題,如下圖所示:

而事務(wù)傳播機制解決的是一個事務(wù)在多個節(jié)點(方法) 中傳遞的問題,如下圖所示:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

4.3 事務(wù)傳播機制有哪些?

Spring 事務(wù)傳播機制包含以下 7種:

  1. Propagation.REQUIRED: 默認的事務(wù)傳播級別,它表示如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個新的事務(wù)。
  2. Propagation.SUPPORTS: 如果當(dāng)前存在事務(wù),則加入該事務(wù); 如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運行。
  3. Propagation.MANDATORY: (mandatory: 強制性) 如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。
  4. Propagation.REQUIRES_NEW: 表示創(chuàng)建一個新的事務(wù),如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。也就是說不管外部方法是否開啟事務(wù),Propagation.REQUIRES_NEW 修飾的內(nèi)部方法會新開啟自己的事務(wù),且開啟的事務(wù)相互獨立,互不干擾。
  5. Propagation.NOT_SUPPORTED: 以非事務(wù)方式運行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
  6. Propagation.NEVER: 以非事務(wù)方式運行,如果當(dāng)前存在事務(wù),則拋出異常
  7. Propagation.NESTED: 如果當(dāng)前存在事務(wù),則創(chuàng)建一個事務(wù)作為當(dāng)前事務(wù)的嵌套事務(wù)來運行;如果當(dāng)前沒有事務(wù),則該取值等價于 PROPAGATION_REQUIRED。

以上 7 種傳播行為,可以根據(jù)是否支持當(dāng)前事務(wù)分為以下 3類:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

以情侶關(guān)系為例來理解以上分類:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

4.4 Spring 事務(wù)傳播機制使用和各種場景演示

4.4.1 支持當(dāng)前事務(wù)(REQUIRED)

我們有多個方法進行數(shù)據(jù)的傳遞.

不考慮攔截器, 考慮標(biāo)準的分層, 比如要執(zhí)行用戶User的添加add操作, 下圖為該執(zhí)行流程圖

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

首先要執(zhí)行add, 就會先在UserController加@Transactional, 下面為了演示事務(wù)的傳播機制, 就需要讓用戶調(diào)用UserService, 并加上@Transactional.
在UserService中, 我們需要操作兩張表, 先調(diào)用UserMapper中的add添加方法, 這個方法是添加用戶的, 再調(diào)用日志添加類.

從上圖可見, @Transactional是通過UserController傳遞到UserService, 再從UserService傳遞到LogService.

注意, 正常來說在*Service要調(diào)用*Mapper類, 但是這里如果使用LogMapper是Interface, 就無法演示清楚預(yù)期效果, 所以這里調(diào)用LogService.

在mycnblog中創(chuàng)建日志表.

CREATE TABLE `log` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `message` text COLLATE utf8mb4_unicode_ci NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

在項目中創(chuàng)建實體類:

@Data
public class UserInfo {
    private int id;
    private String username;
    private String password;
    private String photo;
    private LocalDateTime createtime;
    private LocalDateTime updatetime;
    private int state;
}
@Data
public class Log {
    private int id;
    private LocalDateTime timestamp;
    private String message;
}

演示事務(wù)傳播機制代碼實現(xiàn):

User
@RestController
@RequestMapping("/user3")
public class UserController3 {

    @Autowired
    private UserService userService;

    @RequestMapping("/add")
    @Transactional(propagation = Propagation.REQUIRED)
    public int add(String username, String password){
        if (null == username || null == password ||
                username.equals("") || password.equals("")) return 0;
        UserInfo user = new UserInfo();
        user.setUsername(username);
        user.setPassword(password);
        int result = userService.add(user);
        // 用戶添加操作
        return 0;
    }
}

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

@Service
public class UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LogService logService;

    @Transactional(propagation = Propagation.REQUIRED)
    public int add(UserInfo userInfo) {
        // 給用戶表添加用戶信息
        int addUserResult = userMapper.add(userInfo);
        System.out.println("添加用戶結(jié)果: " + addUserResult);
        // 添加日志信息
        Log log = new Log();
        log.setMessage("添加用戶信息"); 
        logService.add(log);
        return addUserResult;
    }
}

在UserMapper中寫添加add方法.

@Mapper
public interface UserMapper {
    int add(UserInfo userInfo);
}

在xml中寫具體的實現(xiàn):

    <insert id="add">
        insert into userinfo(username, password) values
        (#{username},#{password})
    </insert>
Log

LogMapper.interface

@Mapper
public interface LogMapper {
    int add(Log log);
}

LogMapper.xml

    <insert id="add">
        insert into log(`message`) values(#{message})
    </insert>

LogService:

@Service
public class LogService {
    @Autowired
    private LogMapper logMapper;

    @Transactional(propagation = Propagation.REQUIRED)
    public int add(Log log) {
        int result = logMapper.add(log);
        System.out.println("添加日志結(jié)果: " + result);
        // 回滾操作
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        int num = 10 / 0;
        return result;
    }
}

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

接下來我們觀察一下在UserService中已經(jīng)執(zhí)行成功的user添加操作有沒有回滾事務(wù), 如果user中沒有正常添加數(shù)據(jù), 那么就說明REQUIRED是支持當(dāng)前的事務(wù), 并且是以加入的方式去進行的.

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

可以看到, 添加用戶和添加日志都已經(jīng)成功了, 最終有一個算數(shù)異常報出. 我們再來看一下數(shù)據(jù)庫.

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

可以看到, log回滾了, 符合預(yù)期, 然而userinfo中并沒有將前面url所傳數(shù)據(jù)wangwu添加過來, 那么這就說明, REQUIRED這種事務(wù)傳播機制是支持當(dāng)前事務(wù)的, 并且是加入事務(wù)的方式, 讓自己變成事務(wù)的一部分, 如果其中有任何一個地方出現(xiàn)問題, 不論前面做了多少業(yè)務(wù), 那么整條調(diào)用鏈上所有的方法都會進行回滾.

4.4.2 不支持當(dāng)前事務(wù)(REQUIRESNEW)

將整條事務(wù)調(diào)用鏈上的所有方法修改為 REQUIRES_NEW不支持當(dāng)前事務(wù),重新創(chuàng)建事務(wù),觀察執(zhí)行結(jié)果:

    @Transactional(propagation = Propagation.REQUIRES_NEW)

預(yù)期執(zhí)行結(jié)果: 在一個調(diào)用鏈上的事務(wù),各自執(zhí)行相互不干擾。

對上面的示例來說, 是用戶添加 (事務(wù)) 成功、但是日志添加 (事務(wù)) 失敗。

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

可以看到, 我們的執(zhí)行結(jié)果并沒有符合我們的預(yù)計結(jié)果.

原因是由于沒有處理 by zero的異常, 導(dǎo)致整個調(diào)用鏈上的其他對象都感知到了, 所以進行了回滾.

此時修改LogService代碼:

@Service
public class LogService {
    @Autowired
    private LogMapper logMapper;

    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public int add(Log log) {
        int result = logMapper.add(log);
        System.out.println("添加日志結(jié)果: " + result);
        // 回滾操作
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        return result;
    }
}

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

這個時候便不會報錯了.

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

可以看到, 用戶和日志都添加成功了, 但是日志中進行了手動回滾.

驗證一下:

Spring Boot 事務(wù)和事務(wù)傳播機制,JavaEE,java,mybatis,spring boot,后端,sql,mysql

說明符合了預(yù)期.


4.4.3 嵌套事務(wù) (NESTED) 和加入事務(wù) (REQUIRED )的區(qū)別

  • 整個事務(wù)如果全部執(zhí)行成功,二者的結(jié)果是一樣的。
  • 如果事務(wù)執(zhí)行到一半失敗了,那么加入事務(wù)整個事務(wù)會全部回滾;而嵌套事務(wù)會局部回滾,不會影響上一個方法中執(zhí)行的結(jié)果

至此, 整個JavaEE專欄的知識介紹就到這里.文章來源地址http://www.zghlxwxcb.cn/news/detail-667754.html

到了這里,關(guān)于Spring Boot 事務(wù)和事務(wù)傳播機制的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • Spring事務(wù)和事務(wù)傳播機制(1)

    Spring事務(wù)和事務(wù)傳播機制(1)

    ??????SSM專欄更新中,各位大佬覺得寫得不錯,支持一下,感謝了!?????? Spring + Spring MVC + MyBatis_冷兮雪的博客-CSDN博客 在Spring框架中,事務(wù)管理是一種用于維護數(shù)據(jù)庫操作的一致性和完整性的機制。Spring事務(wù)管理提供了靈活的方式來處理事務(wù),包括事務(wù)的創(chuàng)建

    2024年02月12日
    瀏覽(26)
  • Spring—事務(wù)及事務(wù)的傳播機制

    Spring—事務(wù)及事務(wù)的傳播機制

    將一組操作封裝成一個執(zhí)行單元, 即這一組操作一同成功 / 一同失敗 舉個栗子?? 未使用事務(wù) 滑稽老哥給女神轉(zhuǎn)賬 520 由于某種原因, 女神并未收到轉(zhuǎn)賬的 520, 而滑稽老哥卻被扣款 520 使用事務(wù) 滑稽老哥給女神轉(zhuǎn)賬 520 由于某種原因, 女神并未收到轉(zhuǎn)賬的 520 因為使用事務(wù), 所以

    2024年02月13日
    瀏覽(23)
  • Spring事務(wù)傳播機制解析

    在Java的Spring框架中,事務(wù)管理是保證應(yīng)用數(shù)據(jù)一致性和可靠性的關(guān)鍵。Spring提供了靈活的事務(wù)傳播機制,它定義了事務(wù)邊界,以及在嵌套方法調(diào)用時如何處理事務(wù)。本文旨在深入探討Spring的事務(wù)傳播行為,幫助開發(fā)者更好地理解和運用這一重要特性。 事務(wù)傳播機制指的是在

    2024年01月16日
    瀏覽(35)
  • spring的事務(wù)傳播機制

    spring的事務(wù)傳播機制

    嫌棄內(nèi)容代碼復(fù)雜的可直接看思維導(dǎo)圖大綱即可 指的就是當(dāng)一個事務(wù)方法被另一個事務(wù)方法調(diào)用時,這個事務(wù)方法應(yīng)該如何進行 默認,當(dāng)前存在事務(wù),則加入該事務(wù);不存在事務(wù),創(chuàng)建新事務(wù)。 始終以新的事務(wù)運行,當(dāng)前存在事務(wù),則掛起原事務(wù);不存在事務(wù),創(chuàng)建新事務(wù)

    2023年04月23日
    瀏覽(39)
  • Spring事務(wù)傳播機制

    Spring事務(wù)傳播機制

    編程式事務(wù)管理:通過? TransactionTemplate 或者 TransactionManager 手動管理事務(wù),實際應(yīng)用中很少使用,這不是本文的重點,就不在這里贅述。 聲明式事務(wù)管理:使用場景最多,也是最推薦使用的方式,直接加上@Transactional注解即可。 @Transactional 注解是用于聲明事務(wù)性方法的注解

    2024年01月16日
    瀏覽(43)
  • 【Spring】深入理解 Spring 事務(wù)及其傳播機制

    【Spring】深入理解 Spring 事務(wù)及其傳播機制

    在 Spring 框架中,事務(wù)(Transaction)是一種用于管理數(shù)據(jù)庫操作的機制,旨在 確保數(shù)據(jù)的 一致性、可靠性和完整性 。事務(wù)可以將一組數(shù)據(jù)庫操作(如插入、更新、刪除等)視為一個單獨的執(zhí)行單元,要么 全部成功地執(zhí)行,要么全部回滾 。這樣可以確保數(shù)據(jù)庫在任何時候都保

    2024年02月12日
    瀏覽(30)
  • Spring事務(wù)的四大特性+事務(wù)的傳播機制+隔離機制

    Spring事務(wù)的四大特性+事務(wù)的傳播機制+隔離機制

    原子性是指事務(wù)是一個不可分割的工作單位,事務(wù)中的操作要么都發(fā)生,要么都不發(fā)生。 事務(wù)是一個原子操作, 由一系列動作組成。 組成一個事務(wù)的多個數(shù)據(jù)庫操作是一個不可分割的原子單元 ,只有所有的操作執(zhí)行成功,整個事務(wù)才提交。 事務(wù)中的任何一個數(shù)據(jù)庫操作失敗

    2024年01月20日
    瀏覽(32)
  • 一文詳解Spring事務(wù)傳播機制

    一文詳解Spring事務(wù)傳播機制

    目錄 背景 Spring事務(wù) @Transactional注解 使用場景 失效場景 原理 常用參數(shù) 注意 事務(wù)傳播機制 處理嵌套事務(wù)流程 主事務(wù)為REQUIRED子事務(wù)為REQUIRED 主事務(wù)為REQUIRED子事務(wù)為REQUIRES_NEW 主事務(wù)為REQUIRED子事務(wù)為NESTED 實現(xiàn)方式 源碼解析 我們在使用Spring管理數(shù)據(jù)庫事務(wù)的時候很方便,只

    2023年04月26日
    瀏覽(21)
  • Spring @Transactional事務(wù)傳播機制詳解

    我們?nèi)粘9ぷ髦袠O少使用事務(wù)傳播級別,單純只是使用事務(wù)和rollbackfor拋出異常來解決事務(wù)問題,但其實我們很多時候使用的是不正確的,或者說會造成事務(wù)粒度過大,本文詳解一下事務(wù)傳播級別,也讓自己更好地處理事務(wù)問題。 1.什么是事務(wù)傳播機制? 舉個栗子,方法A是一

    2024年02月14日
    瀏覽(25)
  • Spring事務(wù)傳播的7種機制

    Spring事務(wù)傳播的7種機制

    1. Propagation.REQUIRED:默認的事務(wù)傳播級別,它表示如果當(dāng)前存在事務(wù),則加入該事務(wù);如果 當(dāng)前沒有事務(wù),則創(chuàng)建一個新的事務(wù)。 2. Propagation.SUPPORTS:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的 方式繼續(xù)運行。 3. Propagation.MANDATORY:(mandatory:強制

    2024年02月09日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包