spring 事務(wù)實現(xiàn)的示例
Spring 的事務(wù)實現(xiàn)本質(zhì)上是基于 AOP(面向切面編程) + 動態(tài)代理,在不修改原有業(yè)務(wù)代碼的情況下,把事務(wù)的開始、提交、回滾、異常處理這些橫切關(guān)注點“織入”到目標(biāo)方法中。
下面從最核心的幾個層面逐步拆解(以聲明式事務(wù) @Transactional 為例,這是 95%+ 項目實際使用的模式):
1. 整體架構(gòu)分層(最重要的一張思維導(dǎo)圖)
Spring 事務(wù)抽象層(PlatformTransactionManager)
↑
具體實現(xiàn)(DataSourceTransactionManager / JpaTransactionManager / JtaTransactionManager 等)
↑
TransactionSynchronizationManager(線程本地資源管理器)
↑
AOP 切面(TransactionInterceptor + 各種 Advice)
↑
動態(tài)代理(JDK Proxy / CGLIB)
↑
你的業(yè)務(wù) Bean(@Service 中的 @Transactional 方法)
2. 核心實現(xiàn)步驟(運行時發(fā)生了什么)
| 階段 | 發(fā)生了什么 | 關(guān)鍵類 / 組件 |
|---|---|---|
| 容器啟動 | 解析 @EnableTransactionManagement 或 <tx:annotation-driven/> | TransactionManagementConfigurer / AnnotationDrivenBeanDefinitionParser |
| 注冊 BeanFactoryTransactionAttributeSourceAdvisor(事務(wù)切面 Advisor) | ||
| Bean 創(chuàng)建 | 對于有 @Transactional 的類/方法,Spring 創(chuàng)建代理對象 | ProxyFactory / CglibAopProxy / JdkDynamicAopProxy |
| 外部調(diào)用方法時 | 調(diào)用的是代理對象的方法(不是原始對象) | |
| 代理攔截 | TransactionInterceptor(核心 Advice)被執(zhí)行 | TransactionInterceptor.invoke() |
| 讀取 @Transactional 的屬性(propagation、isolation、timeout、rollbackFor 等) | TransactionAttributeSource | |
| 事務(wù)開始 | 調(diào)用 PlatformTransactionManager.getTransaction(definition) | → 創(chuàng)建 / 加入 / 掛起事務(wù) |
| 把 Connection / TransactionStatus 綁定到 ThreadLocal | TransactionSynchronizationManager.bindResource() | |
| 目標(biāo)方法執(zhí)行 | 真正執(zhí)行你的業(yè)務(wù)代碼(原始對象的方法) | |
| 正常結(jié)束 | 提交:commit() | TransactionManager.commit(status) |
| 異常拋出 | 判斷是否需要回滾(默認(rèn) RuntimeException & Error 回滾,可自定義 rollbackFor) | rollbackOn() 判斷 |
| 回滾:rollback() | TransactionManager.rollback(status) | |
| 清理 | 解綁 ThreadLocal 資源,恢復(fù)掛起的舊事務(wù)(如果有嵌套) | cleanupTransaction() |
3. 傳播行為(Propagation)是怎么實現(xiàn)的?(最??键c)
| 傳播級別 | 代碼中是否有事務(wù) | 外面有事務(wù)嗎? | 實際效果 | 底層實現(xiàn)方式簡述 |
|---|---|---|---|---|
| REQUIRED | 無 | 無 | 新開事務(wù) | getTransaction() 創(chuàng)建新事務(wù) |
| REQUIRED | 有 | 有 | 加入已有事務(wù) | 復(fù)用已有 TransactionStatus |
| REQUIRES_NEW | — | 有 | 總是新建獨立事務(wù)(外面事務(wù)被掛起) | suspend() → create new → resume() |
| NESTED | — | 有 | 使用 savepoint(嵌套子事務(wù)) | createSavepoint() / rollbackToSavepoint() |
| SUPPORTS | — | 有 | 跟隨外面事務(wù),沒有就不用事務(wù) | 只讀模式或無事務(wù) |
| MANDATORY | — | 無 | 拋異常(必須在事務(wù)中調(diào)用) | 檢查當(dāng)前是否有事務(wù),沒有就 IllegalState |
| NEVER | — | 有 | 拋異常(禁止在事務(wù)中調(diào)用) | 同上 |
| NOT_SUPPORTED | — | 有 | 掛起外面事務(wù),以非事務(wù)方式執(zhí)行 | suspend() → 執(zhí)行 → resume() |
注意:NESTED 是唯一基于 savepoint 的傳播行為,其他的都是基于 Connection 的 commit/rollback。
4. 為什么自調(diào)用(this.method())事務(wù)會失效?
因為代理只對外部調(diào)用有效。
@Service
public class UserService {
@Transactional
public void outer() {
// 這里有事務(wù)
inner(); // ← this.inner() 直接調(diào)用原始對象的方法 → 繞過代理 → 無事務(wù)
}
@Transactional
public void inner() {
// 期望有事務(wù),但實際沒有(自調(diào)用場景)
}
}
解決辦法(任選其一):
- 用 @Transactional 的類注入自己(不推薦,循環(huán)依賴)
- 用 AopContext.currentProxy()(需開啟 exposeProxy=true)
- 把 inner 抽到另一個 @Service 類里(最推薦)
- 用編程式事務(wù) TransactionTemplate
5. 線程安全 & 資源綁定核心 —— TransactionSynchronizationManager
這是一個ThreadLocal大管家,里面存了:
- 當(dāng)前線程的 Connection / Session / TransactionStatus
- 資源是否只讀
- 事務(wù)同步器列表(可以注冊回調(diào):beforeCommit、afterCommit、afterCompletion 等)
幾乎所有事務(wù)相關(guān)的操作最終都會走到這里取/放資源。
總結(jié)一句話
Spring 事務(wù)的實現(xiàn)可以濃縮為:
“用動態(tài)代理(AOP)攔截方法 → 根據(jù) @Transactional 屬性通過 PlatformTransactionManager 在 ThreadLocal 中綁定/管理數(shù)據(jù)庫連接和事務(wù)狀態(tài) → 在方法正常結(jié)束或異常時統(tǒng)一 commit/rollback”。
最核心的兩句話:
- 沒有 AOP 動態(tài)代理 → 就沒有聲明式事務(wù)
- 沒有 PlatformTransactionManager → 就沒有真正的事務(wù)控制(Spring 只做協(xié)調(diào))
如果你想更深入看某一塊(比如 savepoint 實現(xiàn)細(xì)節(jié)、DataSourceTransactionManager 源碼、Reactive 事務(wù)區(qū)別、多數(shù)據(jù)源切換等),可以告訴我,我可以繼續(xù)拆更細(xì)。
到此這篇關(guān)于spring 事務(wù)實現(xiàn)的示例的文章就介紹到這了,更多相關(guān)spring 事務(wù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決SpringMVC同時接收J(rèn)son和Restful時Request里有Map的問題
今天小編就為大家分享一篇解決SpringMVC同時接收J(rèn)son和Restful時Request里有Map的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-08-08
Spring中配置和讀取多個Properties文件的方式方法
本篇文章主要介紹了Spring中配置和讀取多個Properties文件的方式方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2017-04-04
javaWeb如何實現(xiàn)隨機(jī)圖片驗證碼詳解
這篇文章主要給大家介紹了關(guān)于javaWeb如何實現(xiàn)隨機(jī)圖片驗證碼的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03

