spring事務(wù)處理的設(shè)計與實現(xiàn)--傳播級別的具體流程

問題

spring的事務(wù)處理為我們省掉了很多操作,如今只需要簡單的配置一下就可以完成對應(yīng)的事務(wù)操作况脆。不過停留在會用的層面上還是缺少一些遇見問題時處理的能力圈匆。下面我要總結(jié)一下spring事務(wù)處理時的設(shè)計中,傳播級別到底是如何工作的,比如

  1. REQUIRED為什么在try中catch住異常外層事務(wù)一樣會回滾纬傲?
  2. REQUIRES_NEW是如何開啟新事物,并與外層事務(wù)獨(dú)立開來汁雷?
  3. NESTED是如何做到子事務(wù)不影響外層事務(wù)?外層事務(wù)會影響子事務(wù)报咳?

名詞

外層事務(wù):事務(wù)A中調(diào)用了事務(wù)B侠讯,那么事務(wù)A就是B的外層事務(wù)。
新事務(wù):事務(wù)A中調(diào)用事務(wù)B暑刃,事務(wù)B的傳播級別為REQUIRES_NEW厢漩,那么事務(wù)B就是新事務(wù)。
子事務(wù):事務(wù)A中調(diào)用事務(wù)B岩臣,事務(wù)B的傳播級別為NESTED溜嗜,那么事務(wù)B就是新事務(wù)宵膨。

探究

先把這里org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction作為事務(wù)處理的入口,來看一下里面的行為炸宵。

image.png

前三行是一些配置信息與調(diào)用的方法信息涯曲,不多講。

這里的關(guān)鍵點在于if里面的內(nèi)容:
1.獲取TransactionInfo信息零截,可能會新建事務(wù)弧哎。createTransactionIfNecessary
2.執(zhí)行事務(wù)代碼invocation.proceedWithInvocation();
3.發(fā)生異常的時候的處理completeTransactionAfterThrowing(txInfo, ex);
4.無論有無異常序攘,都會清理當(dāng)前的事務(wù)信息。cleanupTransactionInfo(txInfo);
5.正常執(zhí)行后的提交動作泛粹。commitTransactionAfterReturning(txInfo);這里的提交并不保證完成提交碱呼,是問題1,3的關(guān)鍵舶斧。

先介紹幾個關(guān)鍵的元信息類:
TransactionDefinition:就是被@Transaction中的一些屬性信息呀忧,包含傳播級別,隔離級別商佑,超時時間喂急,只讀設(shè)置懂诗,名字。

TransactionAttribute:繼承了TransactionDefinition侯繁,包含了qualifier写穴,rollbackOn異扯韫埃回滾的支持信息。

DefaultTransactionStatus

image.png

transaction:事務(wù)對象昔逗,每一個事務(wù)方法都可能有自己獨(dú)立的對象卡乾,也可能公用一個陪踩。
newTransaction:是否是新事務(wù),用來影響事務(wù)的提交和回滾岂座。
newSynchronization: 新的同步器态蒂?沒找到一個很好的解釋,用來控制當(dāng)前線程與事務(wù)屬性的關(guān)系费什。TransactionSynchronizationManager就是這個關(guān)系的管理器钾恢。
readOnly: 只讀屬性,這里不關(guān)心鸳址。
debug:就是一個debug的開啟緩存赘那,省去二次計算。
suspendedResources:掛起的資源氯质,比如REQUIRES_NEW需要掛起外層事務(wù)。

TransactionInfo:事務(wù)的信息概括祠斧,包含上面的TransactionAttribute闻察,TransactionStatus,和事務(wù)管理器對象,方法信息辕漂,重要的是oldTransactionInfo外層事務(wù)信息呢灶,在事務(wù)結(jié)束后會恢復(fù)執(zhí)行外層的事務(wù)邏輯

回到方法TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

image.png

在449行用了一個委托的事務(wù)屬性對象來描述TransactionAttribute钉嘹。就是關(guān)于事務(wù)方法的描述信息鸯乃。
再來看461的getTransaction,這個過程就是對不同的傳播級別的處理方式跋涣。我們這里只關(guān)注DefaultTransactionStatus的變化缨睡。

image.png

可見這里處理的有存在事務(wù)與不存在事務(wù)的兩種處理流程。
isExistingTransaction通過實現(xiàn)可以看到就是數(shù)據(jù)庫連接是否打開了事務(wù)陈辱。
先看在新建事務(wù)時的過程:

  1. 358行奖年,傳播級別為PROPAGATION_MANDATORY時,拋出異常沛贪,這就是這個傳播級別必須要在事務(wù)方法中調(diào)用的原因陋守。
  2. 362行,對于REQUIRED利赋,REQUIRES_NEW水评,NESTED級別的處理。重點關(guān)注DefaultTransactionStatus里面的newTransaction和newSynchronization媚送。
    370行中燥,在默認(rèn)情況下newSynchronization為true,因為getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS
    371行季希,newTransactionStatus方法中褪那,再用
    boolean actualNewSynchronization = newSynchronization &&!TransactionSynchronizationManager.isSynchronizationActive();
    來決定最終的newSynchronization。

TransactionSynchronizationManager.isSynchronizationActive()就是獲取當(dāng)前現(xiàn)成的事務(wù)同步器的激活狀態(tài)式塌。如果已經(jīng)激活博敬,就不用重復(fù)激活了。
由此可見峰尝,最終的newSynchronization是和當(dāng)前的同步器激活狀態(tài)關(guān)系的偏窝。只要是已經(jīng)激活,那么就是false了武学。

373行祭往,doBegin就是開啟了事務(wù)連接的事務(wù)狀態(tài)。
374行火窒,prepareSynchronization準(zhǔn)備同步器的初始化硼补。進(jìn)入方法里面可以看見是設(shè)置了當(dāng)前線程的:
1.激活狀態(tài)。2.隔離級別熏矿。3.只讀已骇。4.事務(wù)名稱离钝。5.空的同步器集合(TransactionSynchronization)。

這里我把幾種級別的各個參數(shù)流程列一下褪储,以便講解:


image.png

1.REQUIRED:
在沒有外層事務(wù)時卵渴,它需要一個事務(wù)管理器transaction,此時的事務(wù)同步器還沒有激活鲤竹,因此需要激活當(dāng)前線程的事務(wù)同步器即actualNewSynchonization為true浪读,同時調(diào)用了doBegin來讓具體的實現(xiàn)打開線程狀態(tài)。最后準(zhǔn)備并初始化線程同步器的狀態(tài)prepareSynchronization辛藻,即設(shè)置了當(dāng)前線程事務(wù)的信息碘橘,并激活了同步器狀態(tài)initSynchronization
在有外層事務(wù)時揩尸,它不需要掛起事務(wù)資源蛹屿,因為要加入到當(dāng)前的事務(wù)。事務(wù)同步器與外層用同一個岩榆。由于不會掛起資源错负,也就不會重置同步器的狀態(tài),也不需要重新激活同步器勇边。這樣就加入到當(dāng)前的事務(wù)中犹撒。
之后在調(diào)用事務(wù)方法的時候,如果出現(xiàn)了異常粒褒,即使被外層捕獲到不拋出识颊,也會使外層事務(wù)回滾。這里我們就要看一下completeTransactionAfterThrowing這個方法里面的東西奕坟。

completeTransactionAfterThrowing.png

很簡單祥款,在事務(wù)有效的時候,符合需要回滾的異常時月杉,走rollback方法刃跛。否則繼續(xù)commit操作。
再來深入一下rollback方法苛萎,里面調(diào)用了processRollback桨昙,
image.png

這里走的是第三個if分支,兩個條件腌歉,1.TransactionStatus的rollbackOnly狀態(tài)蛙酪;2.全局的rollbackOnly狀態(tài)isGlobalRollbackOnParticipationFailure,默認(rèn)返回true翘盖,表示調(diào)用失敗時候桂塞,需要全局回滾。之后進(jìn)入到doSetRollbackOnly馍驯,其實就是讓各自的實現(xiàn)去設(shè)置連接的rollbackOnly狀態(tài)藐俺。
之后在外層事務(wù)提交的時候炊甲,具體看commit方法。
image.png

我們看見兩個分支欲芹,
defStatus.isLocalRollbackOnly()只回滾本事務(wù)

!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly(),shouldCommitOnGlobalRollbackOnly表示全局事務(wù)在標(biāo)記rollbackOnly時候是否需要繼續(xù)提交吟吝,默認(rèn)返回false菱父,只有JTa的實現(xiàn)返回了True。defStatus.isGlobalRollbackOnly()是獲取transaction的rollbackOnly標(biāo)記剑逃,應(yīng)該是標(biāo)記在對應(yīng)的連接狀態(tài)上浙宜。
由上面發(fā)現(xiàn)已經(jīng)將這個transaction標(biāo)記了rollbackOnly,所以就轉(zhuǎn)向了去處理回滾的操作蛹磺。processRollback->doRollback粟瞬。

描述有點多,總結(jié)一下就是:

1.REQUIRED參與到當(dāng)前的事務(wù)萤捆,融合進(jìn)來裙品。
2.當(dāng)它出現(xiàn)異常時,會標(biāo)記當(dāng)前的transaction管理器中連接的rollbackOnly狀態(tài)俗或,使得外層事務(wù)在提交的時候監(jiān)測到這個標(biāo)記市怎,發(fā)現(xiàn)不可以繼續(xù)提交,需要回滾辛慰。

2.REQUIRES_NEW:
在沒有外層事務(wù)時区匠,情況同REQUIRED,就是打開一個事務(wù)帅腌,激活同步器等操作驰弄。
在有外層事務(wù)時,它是需要掛起事務(wù)資源的速客,掛起資源時戚篙,會將同步器的狀態(tài)恢復(fù)為初始狀態(tài),通知具體實現(xiàn)進(jìn)行相應(yīng)的掛起資源操作挽封。這個時候此事務(wù)的同步器狀態(tài)為true已球,所以會準(zhǔn)備一個新的事務(wù)同步器狀態(tài),開啟新事務(wù)doBegin辅愿。
同1理來看智亮,這個新事物在processRollback中不會標(biāo)記transaction管理器的rollbackOnly狀態(tài),只是觸發(fā)了自己的doRollback操作点待,所以不會影響到外層事務(wù)的提交阔蛉。

3.NESTED:
在沒有外層事務(wù)時,情況同REQUIRED癞埠,就是打開一個事務(wù)状原,激活同步器等操作聋呢。
在有外層事務(wù)時,它不會掛起事務(wù)資源颠区,這里討論有支持savePoint的實現(xiàn)(除了Jta)削锰。不會重置同步器,也就是說與外層事務(wù)共用一個同步器毕莱。與REQUIRED類似器贩,與外層事務(wù)進(jìn)行了融合。只不過在發(fā)生異常的時候朋截,在processRollback走了status.hasSavepoint()分支蛹稍,這樣就優(yōu)先進(jìn)入了status.rollbackToHeldSavepoint()里面。


image.png

然后通過對應(yīng)的實現(xiàn)通知連接來回滾到某個savePoint部服,并且釋放掉唆姐。
這樣就完成了單獨(dú)的回滾操作,并不會向REQUIRED那樣影響到外層的提交廓八。
以上我們?nèi)齻€問題解答完了奉芦。

4.MANDATORY:
沒有外層事務(wù)時拋出異常,必須要在事務(wù)里面執(zhí)行瘫想。
有外層事務(wù)時仗阅,像REQUIRED那樣融合進(jìn)去。

5.SUPPORTS:
沒有外層事務(wù)時国夜,不會使用transaction管理器减噪,也就不會形成事務(wù)操作。
有外層事務(wù)時车吹,像REQUIRED那樣融合進(jìn)去筹裕。

6.NOT_SUPPORTED:
沒有外層事務(wù)時,以非事務(wù)方式運(yùn)行窄驹。
有外層事務(wù)時朝卒,把外層事務(wù)掛起,但是不會為自己新建事務(wù)乐埠,以非事務(wù)狀態(tài)運(yùn)行抗斤。

7.NEVER:
沒有外層事務(wù)時,以非事務(wù)方式運(yùn)行丈咐。
有外層事務(wù)時瑞眼,拋出一場。

總結(jié):

以上就是把所有傳播級別的具體流程簡單分析了一下棵逊,讓我們知道了這7中級別是如何工作的伤疙,也解決了REQUIRED,REQUIRES_NEW和NESTED里面對于異常是如何處理的。
1.REQUIRED在處理異常時是給對應(yīng)的連接設(shè)置了rollbackOnly狀態(tài),來影響外層事務(wù)的提交的徒像。外層事務(wù)發(fā)現(xiàn)了rollbackOnly為true黍特,就會轉(zhuǎn)向到回滾流程。
2.REQUIRES_NEW是一個單獨(dú)的事務(wù)操作锯蛀,回滾完自己的事務(wù)不會影響其他灭衷。
3.NESTED是融合在外層事務(wù)中的,只不過這里支持了savePoint的操作谬墙,使得子事務(wù)在回滾時會指定到一個savePoint上今布,不會影響外層事務(wù)。因為與外層事務(wù)融合了拭抬,所以外層事務(wù)會影響到子事務(wù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末侵蒙,一起剝皮案震驚了整個濱河市造虎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌纷闺,老刑警劉巖算凿,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異犁功,居然都是意外死亡氓轰,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門浸卦,熙熙樓的掌柜王于貴愁眉苦臉地迎上來署鸡,“玉大人,你說我怎么就攤上這事限嫌⊙デ欤” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵怒医,是天一觀的道長炉抒。 經(jīng)常有香客問我,道長稚叹,這世上最難降的妖魔是什么焰薄? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮扒袖,結(jié)果婚禮上塞茅,老公的妹妹穿的比我還像新娘。我一直安慰自己僚稿,他們只是感情好凡桥,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蚀同,像睡著了一般缅刽。 火紅的嫁衣襯著肌膚如雪啊掏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天衰猛,我揣著相機(jī)與錄音迟蜜,去河邊找鬼。 笑死啡省,一個胖子當(dāng)著我的面吹牛娜睛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播卦睹,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼畦戒,長吁一口氣:“原來是場噩夢啊……” “哼肩钠!你這毒婦竟也來了棕兼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤泪掀,失蹤者是張志新(化名)和其女友劉穎徐鹤,沒想到半個月后垃环,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡返敬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年遂庄,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片劲赠。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡涛目,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出经磅,到底是詐尸還是另有隱情泌绣,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布预厌,位于F島的核電站阿迈,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏轧叽。R本人自食惡果不足惜苗沧,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望炭晒。 院中可真熱鬧待逞,春花似錦、人聲如沸网严。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至怜庸,卻和暖如春当犯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背割疾。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工嚎卫, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宏榕。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓拓诸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親麻昼。 傳聞我的和親對象是個殘疾皇子奠支,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 什么是事務(wù) 事務(wù)就是一組操作數(shù)據(jù)庫的動作集合。 動作集合被完整地執(zhí)行抚芦,我們稱該事務(wù)被提交胚宦。動作集合中的某一部分執(zhí)行...
    超級變換形態(tài)閱讀 683評論 0 6
  • 事務(wù)傳播行為 什么叫事務(wù)傳播行為?聽起來挺高端的燕垃,其實很簡單。 即然是傳播井联,那么至少有兩個東西卜壕,才可以發(fā)生傳播。單...
    青青子衿zq閱讀 2,501評論 0 2
  • 轉(zhuǎn)載自:http://www.reibang.com/p/8ddc01f23540 Spring事務(wù)機(jī)制主要包括...
    星海辰光大人閱讀 347評論 0 0
  • 分享日志第一百一十四天10.3 讓分享成為一種習(xí)慣烙常!讀經(jīng) 遍 累計 56遍 今天與同伴做了個小游戲轴捎,是兒時玩過的互...
    孝文4931閱讀 161評論 0 1
  • 今天帶孩子去看馬戲團(tuán)表演,孩子們很興奮蚕脏,我卻不太喜歡看這些侦副。 不愛看并不是說節(jié)目不精彩或其他原因,而是我每次看到馴...
    無聊啊哈哈閱讀 79評論 0 0