Spring聲明式事務管理從原理到實戰(zhàn)示例
?? 一、什么是聲明式事務管理?
? 簡單說:
你不用在代碼里手動寫 beginTransaction()、commit()、rollback(),而是通過配置或注解來告訴 Spring:“這個方法需要事務”,Spring 自動幫你管理事務的開始、提交或回滾。
?? 對比:編程式 vs 聲明式
| 類型 | 特點 | 代碼侵入性 |
|---|---|---|
| 編程式事務 | 手動控制事務(如使用 TransactionTemplate) | 高(代碼里到處是事務邏輯) |
| 聲明式事務 | 用配置或注解聲明事務行為 | 低(業(yè)務代碼干凈) |
?? Spring 推薦使用 聲明式事務,因為它更符合“輕量級容器”的理念 —— 業(yè)務代碼不依賴事務框架。
?? 二、聲明式事務是如何實現(xiàn)的?(核心原理)
Spring 的聲明式事務是基于 AOP(面向切面編程) 實現(xiàn)的。
?? 工作流程如下:
- 你有一個服務類,比如
DefaultFooService。 - 你在配置中聲明了哪些方法需要事務(通過
<tx:advice>或@Transactional)。 - Spring 在啟動時,會為這個類創(chuàng)建一個 代理對象(Proxy)。
- 當你調(diào)用
fooService.insertFoo(...)時,實際上是調(diào)用了代理對象的方法。 - 代理對象在方法執(zhí)行前開啟事務,執(zhí)行后根據(jù)結果決定提交或回滾。
你調(diào)用: fooService.insertFoo()
↓
實際執(zhí)行: Proxy → 開啟事務 → 調(diào)用真實方法 → 成功則提交,異常則回滾
??? 關鍵組件:
TransactionInterceptor:事務攔截器,負責在方法前后插入事務邏輯。TransactionManager:事務管理器,真正執(zhí)行開啟、提交、回滾操作(如DataSourceTransactionManager)。- AOP 代理:JDK 動態(tài)代理 或 CGLIB,用于織入事務邏輯。
?? 三、如何配置聲明式事務?(XML 配置方式)
文檔中的例子使用 XML 配置,雖然現(xiàn)在更多用注解,但理解 XML 有助于理解底層機制。
示例配置解析:
<!-- 定義數(shù)據(jù)源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"> ... </bean>
<!-- 定義事務管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 定義事務通知(規(guī)則) -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="get*" read-only="true"/> <!-- 所有get開頭的方法:只讀事務 -->
<tx:method name="*" /> <!-- 其他方法:默認事務(讀寫) -->
</tx:attributes>
</tx:advice>
<!-- 將事務通知應用到指定的切點 -->
<aop:config>
<!-- 切點:匹配 FooService 接口的所有方法 -->
<aop:pointcut id="fooServiceOperation"
expression="execution(* x.y.service.FooService.*(..))"/>
<!-- 綁定通知和切點 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
</aop:config>?? 關鍵點:
tx:method name="get*":所有以get開頭的方法使用 只讀事務(性能優(yōu)化)。tx:method name="*":其他方法使用默認事務(讀寫)。aop:pointcut使用 AspectJ 表達式 匹配方法。
?? 四、事務回滾機制(Rollback Rules)
這是 Spring 事務的一大亮點:你可以精確控制哪些異常觸發(fā)回滾。
默認規(guī)則:
- ? 運行時異常(RuntimeException):自動回滾(如
NullPointerException、IllegalArgumentException) - ? 檢查型異常(Checked Exception):不回滾(如
IOException、自定義的MyException)
?? 這與 EJB CMT 不同!EJB 中檢查型異常也不回滾,但 Spring 允許你自定義。
自定義回滾規(guī)則:
1. 某個檢查型異常也要回滾:
<tx:method name="updateStock" rollback-for="NoProductInStockException"/>
2. 某個運行時異常不要回滾:
<tx:method name="updateStock" no-rollback-for="InstrumentNotFoundException"/>
3. 多規(guī)則優(yōu)先級:
<tx:method name="*"
rollback-for="Throwable"
no-rollback-for="InstrumentNotFoundException"/>
? 所有異常都回滾,除了
InstrumentNotFoundException。
?? 五、響應式事務(Reactive Transaction Management)
Spring 5+ 支持響應式編程(如 WebFlux),事務也支持響應式。
關鍵區(qū)別:
| 特性 | 傳統(tǒng)(Imperative) | 響應式(Reactive) |
|---|---|---|
| 返回類型 | Foo, void | Mono<Foo>, Flux<Foo> |
| 事務管理器 | PlatformTransactionManager | ReactiveTransactionManager |
| 事務傳播 | 基于 ThreadLocal | 基于 Reactor Context |
| 事務觸發(fā) | 方法調(diào)用立即開始 | 返回的 Publisher 被訂閱時才開始 |
?? 響應式事務是“惰性的”:調(diào)用方法不立即開啟事務,而是等到
.subscribe()時才開始。
??? 六、不同 Bean 使用不同事務配置
你可以為不同的服務類設置不同的事務規(guī)則。
示例:
<aop:pointcut id="defaultServiceOperation"
expression="execution(* x.y.service.*Service.*(..))"/>
<aop:pointcut id="noTxServiceOperation"
expression="execution(* x.y.service.ddl.DefaultDdlManager.*(..))"/>
<aop:advisor pointcut-ref="defaultServiceOperation" advice-ref="defaultTxAdvice"/>
<aop:advisor pointcut-ref="noTxServiceOperation" advice-ref="noTxAdvice"/>*Service類:使用默認事務(可讀寫)DefaultDdlManager類:使用propagation="NEVER"(禁止在事務中運行)
?? 這很實用,比如 DDL 操作(建表、刪表)通常不應在事務中運行。
?? 七、<tx:method>的所有配置項總結
| 屬性 | 是否必需 | 默認值 | 說明 |
|---|---|---|---|
name | ? 是 | - | 方法名(支持 * 通配符) |
propagation | 否 | REQUIRED | 傳播行為(如 REQUIRED, REQUIRES_NEW, NEVER 等) |
isolation | 否 | DEFAULT | 隔離級別(如 READ_COMMITTED) |
timeout | 否 | -1(無超時) | 超時時間(秒) |
read-only | 否 | false | 是否只讀事務 |
rollback-for | 否 | - | 哪些異常觸發(fā)回滾(可寫多個,逗號分隔) |
no-rollback-for | 否 | - | 哪些異常不觸發(fā)回滾 |
?? 八、重要注意事項
- 代理機制限制:
- 只有 外部調(diào)用 代理對象的方法才會觸發(fā)事務。
- 如果你在同一個類中調(diào)用
this.method(),事務不會生效(因為沒走代理)。
- 事務不會跨遠程調(diào)用:
- Spring 不支持像 EJB 那樣將事務上下文傳播到遠程服務。
- 如果你需要分布式事務,考慮使用 Seata 或 Spring Cloud Alibaba 等方案。
- 異常必須拋出:
- 如果你在方法內(nèi)部
catch了異常但沒有重新拋出,事務不會回滾。 - 正確做法:
catch后throw或調(diào)用setRollbackOnly()。
- 如果你在方法內(nèi)部
@Transactional注解更常用:- 現(xiàn)代 Spring 開發(fā)通常使用
@Transactional注解代替 XML。
- 現(xiàn)代 Spring 開發(fā)通常使用
- 例如:
@Service
public class FooService {
@Transactional(readOnly = true)
public Foo getFoo(String name) { ... }
@Transactional(rollbackFor = MyException.class)
public void updateFoo(Foo foo) { ... }
}需要啟用:@EnableTransactionManagement
? 總結:如何理解這段內(nèi)容?
| 問題 | 回答 |
|---|---|
| 聲明式事務是什么? | 用配置或注解聲明事務,無需手動控制。 |
| 怎么實現(xiàn)的? | 基于 AOP,Spring 創(chuàng)建代理對象,在方法前后自動加事務邏輯。 |
| 怎么配置? | 用 <tx:advice> 定義規(guī)則,用 <aop:config> 應用到目標方法。 |
| 異常怎么回滾? | 默認運行時異常回滾,可通過 rollback-for 自定義。 |
| 不同類不同配置? | 可以,定義多個 <tx:advice> 和 <aop:advisor>。 |
| 響應式支持嗎? | 支持,基于 ReactiveTransactionManager 和 Reactor 上下文。 |
?? 建議學習路徑
- 先理解 AOP 基本概念(代理、切點、通知)
- 動手寫一個 XML 配置的聲明式事務例子
- 改造成
@Transactional注解方式 - 嘗試 自定義回滾規(guī)則
- 了解 事務傳播行為(如
REQUIRED,REQUIRES_NEW) - (進階)學習 響應式事務 和 分布式事務
如果你希望,我可以:
- 把這個內(nèi)容轉成中文思維導圖
- 寫一個完整的可運行代碼示例(Java + Spring + 注解)
- 解釋
@Transactional的各種傳播行為
歡迎繼續(xù)提問!
到此這篇關于Spring聲明式事務管理從原理到實戰(zhàn)示例的文章就介紹到這了,更多相關Spring聲明式事務管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java實現(xiàn)解壓zip壓縮包的兩種方法(支持多層級)
壓縮文件在生活中經(jīng)常能用到,在Java中提供了壓縮和解壓縮文件的功能,本文主要介紹了Java實現(xiàn)解壓zip壓縮包的兩種方法(支持多層級),感興趣的可以了解一下2024-03-03
Java代碼規(guī)范與質(zhì)量檢測插件SonarLint的使用
本文主要介紹了Java代碼規(guī)范與質(zhì)量檢測插件SonarLint的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08
Spring Cloud Alibaba Nacos 入門詳解
這篇文章主要介紹了Spring Cloud Alibaba Nacos入門詳解,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-03-03
SpringBoot+Netty實現(xiàn)簡單聊天室的示例代碼
這篇文章主要介紹了如何利用SpringBoot Netty實現(xiàn)簡單聊天室,文中的示例代碼講解詳細,對我們學習SpringBoot有一定幫助,感興趣的同學可以了解一下2022-02-02
SpringBoot+mybatis+Vue實現(xiàn)前后端分離項目的示例
本文主要介紹了SpringBoot+mybatis+Vue實現(xiàn)前后端分離項目的示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-12-12

