spring 事務(wù)增強(qiáng) 接著上一篇 spring事務(wù)
上一篇文章,知道spring是通過什么把事務(wù)增強(qiáng)組合到切面里的语淘。
這一篇具體看看增強(qiáng)里都做了什么
核心抽象類TransactionAspectSupport的 invokeWithinTransaction方法
關(guān)鍵步驟
1诲宇、獲取事務(wù)管理對(duì)象 determineTransactionManager(txAttr)
- @Transation上指定manager
- TransactionAttribute 上指定的Qualifier
- 默認(rèn)事務(wù)管理對(duì)象
從上面可以猜測(cè),多個(gè)事務(wù)管理委托給多個(gè)數(shù)據(jù)源
2惶翻、事物管理對(duì)象是否 有回調(diào)
2.1 回調(diào)型事物管理對(duì)象 CallbackPreferringPlatformTransactionManager
事物管理對(duì)象可以是非數(shù)據(jù)庫事物管理姑蓝,如kafka事物. 在執(zhí)行事物的過程中跟數(shù)據(jù)庫很不一樣,所有需要基礎(chǔ)該類自己實(shí)現(xiàn).
2.2 非回調(diào)型事物管理對(duì)象
通常就是數(shù)據(jù)庫事物管理, 開啟事物吕粗,執(zhí)行sql纺荧,關(guān)閉事物等操作
2.2.1、createTransactionIfNecessary
開啟事務(wù)颅筋,如果有必要的話宙暇;
一種是無事務(wù)配置的,這種也是可以聲明切面配置事務(wù)增強(qiáng)议泵,不過是不會(huì)真正開啟事務(wù)占贫;
-
另一種是有事務(wù)配置。
getTransaction()獲取事務(wù)先口, 委托給doGetTransaction()方法獲取事務(wù)型奥;
如 數(shù)據(jù)庫事務(wù)DataSourceTransactionManager的 doGetTransaction方法從DataSource獲取事務(wù)如果從DataSource獲取到的事務(wù)是開啟狀態(tài)的,則處理當(dāng)前事務(wù)描述的傳播特性池充,根據(jù)聲明的傳播特性做處理( 如桩引,聲明為不要事務(wù)缎讼,如果當(dāng)前獲取到了事務(wù)收夸,則拋出異常),處理完血崭,直接返回;
具體處理 AbstractPlatformTransactionManager.handleExistingTransaction方法,根據(jù)傳播特性
PROPAGATION_NEVER: 即不要事務(wù)卧惜,但卻得到了事務(wù),拋出異常.
PROPAGATION_NOT_SUPPORTED: 即不支持事務(wù)夹纫,當(dāng)前事務(wù)會(huì)被掛起.
PROPAGATION_REQUIRES_NEW:即需要新的事務(wù), 則當(dāng)前事務(wù)被掛起, 并且開啟新的事務(wù)
PROPAGATION_NESTED: 即嵌套事務(wù), 如果事務(wù)管理器不允許嵌套事務(wù)則拋出異常. 如果連接支持jdbc savepoints則把當(dāng)前事務(wù)點(diǎn)當(dāng)作新事務(wù)返回(spring文檔的解析如下, 使用具有多個(gè)保存點(diǎn)的單個(gè)物理事務(wù)咽瓷,可以將其回滾到該保存點(diǎn)。這種部分回滾使內(nèi)部事務(wù)范圍觸發(fā)其范圍的回滾舰讹,盡管某些操作已回滾茅姜,但外部事務(wù)仍能夠繼續(xù)物理事務(wù)。此設(shè)置通常映射到JDBC保存點(diǎn)月匣,因此僅適用于JDBC資源事務(wù))钻洒。如果是JTA則已當(dāng)前事務(wù)開啟新事務(wù);如果從DataSource沒獲取到事務(wù)奋姿,或者事務(wù)是未開啟狀態(tài); 則嘗試掛起當(dāng)前事務(wù)(如果有)或者掛起所有事務(wù)(如果隔離級(jí)別是Synchronization的話,其他隔離級(jí)別則不掛起)
之后開啟新的事務(wù)
2.2.2 開啟新事務(wù)
開啟新事物是DataSourceTransactionManager的doBegin方法素标,包括獲取連接, 設(shè)置手動(dòng)提交称诗,設(shè)置事務(wù)開啟狀態(tài)等, 因?yàn)殚_啟的事務(wù)跟數(shù)據(jù)庫連接有綁定關(guān)系,我們可以大膽的猜測(cè)头遭,事務(wù)完全就是數(shù)據(jù)庫連接的隔離寓免。
拿到事務(wù)后, 把事務(wù)綁定到當(dāng)前線程,并記錄綁定前的事務(wù)计维;
try {
① 之后就是執(zhí)行被代理對(duì)象的數(shù)據(jù)庫操作
catch() {
②如果有返回異常袜香,則判斷異常處理,是否需要回滾等
}
finally {
③ 清除事務(wù)鲫惶,并把上一個(gè)事務(wù)設(shè)置為當(dāng)前線程綁定的事務(wù)(如果有的話);
}
② 源碼里如果當(dāng)前事務(wù)出現(xiàn)異常的處理流程大概如下
completeTransactionAfterThrowing(txInfo, throwable) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
回滾
} catch() {
有異常繼續(xù)往外拋出
}
}else {
try {
提交
}catch() {
有異常繼續(xù)往外發(fā)出
}
}
}
}
最后提交事務(wù), 這個(gè)過程也有可能回滾;
另一個(gè)非數(shù)據(jù)庫的事務(wù)本章不進(jìn)行分析, 請(qǐng)自行查閱源碼困鸥;
總結(jié)
spring事務(wù)不僅僅能管理數(shù)據(jù)庫事務(wù),也可以管理其他類型的事務(wù)剑按。
數(shù)據(jù)庫的事務(wù)管理依賴真實(shí)的數(shù)據(jù)庫的事務(wù)特性疾就。
通過spring聲明式事務(wù),使開發(fā)人員在開發(fā)數(shù)據(jù)庫操作時(shí)更加簡(jiǎn)單.
嵌套的事務(wù)傳播特性PROPAGATION_NESTED艺蝴, 能夠更細(xì)粒度的把控同事處理多個(gè)事務(wù)猬腰。
當(dāng)嵌套事務(wù)的內(nèi)部事務(wù)發(fā)聲異常,如果是事務(wù)可以處理的異常猜敢,則內(nèi)部事務(wù)回滾姑荷。 如果內(nèi)部事務(wù)無法處理的異常,則提交內(nèi)部事務(wù)缩擂,如果提交內(nèi)部事務(wù)的時(shí)候還拋出異常鼠冕,則異常往外一層事務(wù)拋出異常。
看一個(gè)題外例子胯盯。爆米豆的多數(shù)據(jù)源管理.
1懈费、首先知道baomidou的多數(shù)據(jù)源配置配置好連接屬性后,需要在業(yè)務(wù)類(通常是service類)上加@DS("xxx"), 這里的xx是數(shù)據(jù)源名稱. 如果不配置就用默認(rèn)數(shù)據(jù)源.
2博脑、通過之前spring的學(xué)習(xí)憎乙,爆米豆肯定會(huì)處理@DS這個(gè)注解。不出所料叉趣,DynamicDataSourceAnnotationAdvisor這個(gè)組合增強(qiáng)類就是處理@DS
3泞边、處理的過程就是把@DS聲明的數(shù)據(jù)源標(biāo)識(shí)放入鏈表里
4、當(dāng)數(shù)據(jù)庫操作的時(shí)候疗杉,會(huì)先獲取數(shù)據(jù)庫連接阵谚,而獲取連接時(shí)是通過數(shù)據(jù)源獲取,即最終通過數(shù)據(jù)源標(biāo)識(shí)獲取到真實(shí)數(shù)據(jù)源