Spring Boot 事務(wù)詳解(事務(wù)傳播行為、事務(wù)屬性)
Spring Boot 事務(wù)詳解
引言
在現(xiàn)代應(yīng)用程序中,事務(wù)管理是確保數(shù)據(jù)一致性和完整性的重要機(jī)制。Spring Boot 提供了強(qiáng)大的事務(wù)管理功能,使得開發(fā)者可以輕松地定義和管理事務(wù)。本文將詳細(xì)介紹 Spring Boot 中的事務(wù)管理,包括事務(wù)傳播行為、事務(wù)屬性以及聲明式和編程式事務(wù)管理。
聲明式事務(wù)管理
聲明式事務(wù)管理是通過注解的方式來管理事務(wù),最常用的注解是 @Transactional
。這種方式簡單直觀,適合大多數(shù)場景。
示例
import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service public class UserService { @Transactional public void createUser(User user) { // 數(shù)據(jù)庫操作 } }
編程式事務(wù)管理
編程式事務(wù)管理是通過編程的方式來手動(dòng)控制事務(wù),通常使用 PlatformTransactionManager
和 TransactionTemplate
。
示例
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.DefaultTransactionDefinition; @Service public class UserService { @Autowired private PlatformTransactionManager transactionManager; public void createUser(User user) { DefaultTransactionDefinition def = new DefaultTransactionDefinition(); def.setName("createUserTransaction"); def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED); TransactionStatus status = transactionManager.getTransaction(def); try { // 數(shù)據(jù)庫操作 transactionManager.commit(status); } catch (Exception e) { transactionManager.rollback(status); throw e; } } }
事務(wù)傳播行為
事務(wù)傳播行為定義了當(dāng)一個(gè)事務(wù)方法調(diào)用另一個(gè)事務(wù)方法時(shí),事務(wù)如何傳播。Spring 提供了多種傳播行為,可以通過 @Transactional
注解進(jìn)行配置。以下是 Spring 支持的傳播行為及其使用場景:
1. REQUIRED
定義:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則創(chuàng)建一個(gè)新的事務(wù)。
使用場景:大多數(shù)業(yè)務(wù)操作都使用該傳播行為,因?yàn)樗_保了調(diào)用鏈上的所有操作都在同一個(gè)事務(wù)中。
示例:
@Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 業(yè)務(wù)邏輯 }
事務(wù)傳播示意圖:
+--------+ +--------+
| 方法A | | 方法B |
| |---------------> |
| | 傳播事務(wù) T1 | |
+--------+ +--------+
2. SUPPORTS
定義:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)方式執(zhí)行。
使用場景:適用于可選的事務(wù)操作,例如只讀查詢。
示例:
@Transactional(propagation = Propagation.MANDATORY) public void methodC() { // 業(yè)務(wù)邏輯 }
事務(wù)傳播示意圖:
+--------+ +--------+
| 方法A | | 方法C |
| |---------------> |
| | 傳播事務(wù) T1 | |
+--------+ +--------+
3. MANDATORY
定義:如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則拋出異常。
使用場景:用于強(qiáng)制要求在事務(wù)環(huán)境中執(zhí)行的方法。
示例:
@Transactional(propagation = Propagation.REQUIRES_NEW) public void methodD() { // 業(yè)務(wù)邏輯 }
事務(wù)傳播示意圖:
+--------+ +--------+
| 方法A | | 方法C |
| |---------------> |
| | 傳播事務(wù) T1 | |
+--------+ +--------+
4. REQUIRES_NEW
定義:創(chuàng)建一個(gè)新的事務(wù),如果當(dāng)前存在事務(wù),則將當(dāng)前事務(wù)掛起。
使用場景:適用于必須在一個(gè)新事務(wù)中執(zhí)行的操作,例如獨(dú)立的日志記錄。
示例:
@Transactional(propagation = Propagation.REQUIRES_NEW) public void methodD() { // 業(yè)務(wù)邏輯 }
事務(wù)傳播示意圖:
+--------+ +--------+
| 方法A | | 方法D |
| |------------->| |
| 掛起事務(wù) T1 | 創(chuàng)建事務(wù) T2 |
+--------+ +--------+
5. NOT_SUPPORTED
定義:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),則將當(dāng)前事務(wù)掛起。
使用場景:適用于不需要事務(wù)的操作,例如批量數(shù)據(jù)處理。
示例:
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void methodE() { // 業(yè)務(wù)邏輯 }
事務(wù)傳播示意圖:
+--------+ +--------+
| 方法A | | 方法E |
| |------------->| |
| 掛起事務(wù) T1 | 非事務(wù)執(zhí)行 |
+--------+ +--------+
6. NEVER
定義:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
使用場景:用于強(qiáng)制要求以非事務(wù)方式執(zhí)行的方法。
示例:
@Transactional(propagation = Propagation.NEVER) public void methodF() { // 業(yè)務(wù)邏輯 }
事務(wù)傳播示意圖:
+--------+ +--------+
| 方法A | | 方法F |
| |------------->| |
| | 如果存在事務(wù) T1,拋異常 |
+--------+ +--------+
7. NESTED
定義:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行;如果當(dāng)前沒有事務(wù),則行為與 REQUIRED
類似。
使用場景:適用于需要在主事務(wù)中執(zhí)行的子事務(wù),例如復(fù)雜的數(shù)據(jù)庫操作。
示例:
@Transactional(propagation = Propagation.NESTED) public void methodG() { // 業(yè)務(wù)邏輯 }
事務(wù)傳播示意圖:
+--------+ +--------+
| 方法A | | 方法G |
| |------------->| |
| 事務(wù) T1 | 嵌套事務(wù) T1.1 |
+--------+ +--------+
事務(wù)失效情況
Spring Boot 通過 Spring 框架的事務(wù)管理模塊來支持事務(wù)操作。事務(wù)管理在 Spring Boot 中通常是通過 @Transactional
注解來實(shí)現(xiàn)的。以下是一些常見的事務(wù)失效情況:
1. 未捕獲異常
如果一個(gè)事務(wù)方法中發(fā)生了未捕獲的異常,并且異常未被處理或傳播到事務(wù)邊界之外,那么事務(wù)會(huì)失效,所有的數(shù)據(jù)庫操作會(huì)回滾。
2. 非受檢異常
默認(rèn)情況下,Spring 對(duì)非受檢異常(RuntimeException
或其子類)進(jìn)行回滾處理,這意味著當(dāng)事務(wù)方法中拋出這些異常時(shí),事務(wù)會(huì)回滾。
3. 事務(wù)傳播屬性設(shè)置不當(dāng)
如果在多個(gè)事務(wù)之間存在事務(wù)嵌套,且事務(wù)傳播屬性配置不正確,可能導(dǎo)致事務(wù)失效。特別是在方法內(nèi)部調(diào)用有 @Transactional
注解的方法時(shí)要特別注意。
4. 多數(shù)據(jù)源的事務(wù)管理
如果在使用多數(shù)據(jù)源時(shí),事務(wù)管理沒有正確配置或者存在多個(gè) @Transactional
注解時(shí),可能會(huì)導(dǎo)致事務(wù)失效。
5. 跨方法調(diào)用事務(wù)問題
如果一個(gè)事務(wù)方法內(nèi)部調(diào)用另一個(gè)方法,而這個(gè)被調(diào)用的方法沒有 @Transactional
注解,這種情況下外層事務(wù)可能會(huì)失效。
6. 事務(wù)在非公開方法中失效
如果 @Transactional
注解標(biāo)注在私有方法上或者非 public
方法上,事務(wù)也會(huì)失效。
7. 使用this調(diào)用事務(wù)方法
Spring 事務(wù)是通過代理對(duì)象來控制的,只有通過代理對(duì)象的方法調(diào)用才會(huì)應(yīng)用事務(wù)管理的相關(guān)規(guī)則。當(dāng)使用 this
直接調(diào)用時(shí),是繞過了 Spring 的代理機(jī)制,因此不會(huì)應(yīng)用事務(wù)設(shè)置。
回滾條件
1. 自動(dòng)回滾事務(wù)
- 拋出未檢查異常(
RuntimeException
及其子類),例如:NullPointerException
等。
2. 不會(huì)自動(dòng)回滾
- 默認(rèn)情況下,檢查異常(如
IOException
、SQLException
等)不會(huì)觸發(fā)回滾??梢酝ㄟ^@Transactional
注解的rollbackFor
屬性配置回滾:
示例:
@Transactional(rollbackFor = IOException.class) public void methodH() { // 業(yè)務(wù)邏輯 }
事務(wù)屬性
除了傳播行為,Spring 還提供了一些其他事務(wù)屬性,可以通過 @Transactional
注解進(jìn)行配置。
1. 隔離級(jí)別
隔離級(jí)別定義了一個(gè)事務(wù)與其他事務(wù)隔離的程度。Spring 支持以下幾種隔離級(jí)別:
- DEFAULT:使用數(shù)據(jù)庫默認(rèn)的隔離級(jí)別。
- READ_UNCOMMITTED:讀未提交的變更。
- READ_COMMITTED:讀已提交的變更。
- REPEATABLE_READ:可重復(fù)讀。
- SERIALIZABLE:串行化。
示例:
@Transactional(isolation = Isolation.READ_COMMITTED) public void methodI() { // 業(yè)務(wù)邏輯 }
2. 事務(wù)超時(shí)
事務(wù)超時(shí)定義了事務(wù)在回滾之前可以運(yùn)行的最長時(shí)間(以秒為單位)。
示例:
@Transactional(timeout = 30) public void methodJ() { // 業(yè)務(wù)邏輯 }
3. 只讀事務(wù)
只讀事務(wù)用于優(yōu)化只讀操作。設(shè)置為只讀的事務(wù)可以提示數(shù)據(jù)庫引擎進(jìn)行某些優(yōu)化。
示例:
@Transactional(readOnly = true) public void methodK() { // 業(yè)務(wù)邏輯 }
4. 回滾規(guī)則
通過 rollbackFor
和 noRollbackFor
屬性可以指定哪些異常會(huì)觸發(fā)事務(wù)回滾,哪些不會(huì)。
示例:
@Transactional(rollbackFor = Exception.class) public void methodL() { // 業(yè)務(wù)邏輯 }
常見面試題解析
1. 什么是事務(wù)傳播行為?Spring 提供了哪些事務(wù)傳播行為?
答:事務(wù)傳播行為定義了當(dāng)一個(gè)事務(wù)方法調(diào)用另一個(gè)事務(wù)方法時(shí),事務(wù)如何傳播。Spring 提供了以下事務(wù)傳播行為:REQUIRED、SUPPORTS、MANDATORY、REQUIRES_NEW、NOT_SUPPORTED、NEVER、NESTED。
2. 如何配置事務(wù)的隔離級(jí)別?Spring 提供了哪些隔離級(jí)別?
答:可以通過 @Transactional
注解的 isolation
屬性配置事務(wù)的隔離級(jí)別。Spring 提供了以下隔離級(jí)別:DEFAULT、READ_UNCOMMITTED、READ_COMMITTED、REPEATABLE_READ、SERIALIZABLE。
3. 什么是只讀事務(wù)?如何配置?
答:只讀事務(wù)用于優(yōu)化只讀操作??梢酝ㄟ^ @Transactional
注解的 readOnly
屬性配置只讀事務(wù)。例如:@Transactional(readOnly = true)
。
4. 如何配置事務(wù)的超時(shí)時(shí)間?
答:可以通過 @Transactional
注解的 timeout
屬性配置事務(wù)的超時(shí)時(shí)間(以秒為單位)。例如:@Transactional(timeout = 30)
。
5. 如何指定哪些異常會(huì)觸發(fā)事務(wù)回滾?
答:可以通過 @Transactional
注解的 rollbackFor
屬性指定哪些異常會(huì)觸發(fā)事務(wù)回滾。例如:@Transactional(rollbackFor = Exception.class)
。
總結(jié)
Spring Boot 提供了強(qiáng)大的事務(wù)管理功能,通過 @Transactional
注解可以方便地配置事務(wù)的傳播行為和屬性。理解和合理應(yīng)用這些配置,可以有效地提高應(yīng)用程序的數(shù)據(jù)一致性和完整性。
到此這篇關(guān)于Spring Boot 事務(wù)詳解(事務(wù)傳播行為、事務(wù)屬性)的文章就介紹到這了,更多相關(guān)Spring Boot 事務(wù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于阿里巴巴TransmittableThreadLocal使用解讀
文章主要介紹了三種ThreadLocal的使用:ThreadLocal、InheritableThreadLocal和TransmittableThreadLocal,ThreadLocal和InheritableThreadLocal在單線程和部分情況下可以正常工作,但TransmittableThreadLocal在處理線程池時(shí)表現(xiàn)更佳2025-02-02java實(shí)現(xiàn)微信公眾平臺(tái)自定義菜單的創(chuàng)建示例
這篇文章主要介紹了java實(shí)現(xiàn)微信公眾平臺(tái)自定義菜單的創(chuàng)建示例,需要的朋友可以參考下2014-04-04Java網(wǎng)絡(luò)編程TCP實(shí)現(xiàn)聊天功能
這篇文章主要為大家詳細(xì)介紹了Java網(wǎng)絡(luò)編程TCP實(shí)現(xiàn)聊天功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07IDEA配置Gradle及Gradle安裝的實(shí)現(xiàn)步驟
本文主要介紹了IDEA配置Gradle及Gradle安裝的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08SpringBoot導(dǎo)入mail依賴報(bào)錯(cuò)問題解決
這篇文章主要介紹了SpringBoot導(dǎo)入mail依賴報(bào)錯(cuò)問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10詳細(xì)分析Java并發(fā)集合ArrayBlockingQueue的用法
這篇文章主要介紹了詳細(xì)分析Java并發(fā)集合ArrayBlockingQueue的用法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04