深入理解 Spring 事務(wù)原理

深入理解 Spring 事務(wù)原理
參考:
https://mp.weixin.qq.com/s/HHLGfRuD_Ynv7GhDsy7rKA

一失晴、事務(wù)的基本原理

Spring事務(wù)的本質(zhì)其實(shí)就是數(shù)據(jù)庫對事務(wù)的支持绢慢,沒有數(shù)據(jù)庫的事務(wù)支持,
spring是無法提供事務(wù)功能的陷揪。對于純JDBC操作數(shù)據(jù)庫,想要用到事務(wù),可以按照以下步驟進(jìn)行:

獲取連接
Connection con = DriverManager.getConnection()
開啟事務(wù)
con.setAutoCommit(true/false);
執(zhí)行
CRUD
提交事務(wù)
/回滾事務(wù)
con.commit() / con.rollback();
關(guān)閉連接
conn.close();

使用Spring的事務(wù)管理功能后,我們可以不再寫步驟2和4的代碼九秀,而是由Spirng自動完成。那么Spring是如何在我們書寫的CRUD之前和之后開啟事務(wù)和關(guān)閉事務(wù)的呢粘我?解決這個(gè)問題鼓蜒,也就可以從整體上理解Spring的事務(wù)管理實(shí)現(xiàn)原理了。下面簡單地介紹下涂滴,注解方式為例子友酱。
配置文件開啟注解驅(qū)動,在相關(guān)的類和方法上通過注解@Transactional標(biāo)識。
spring在啟動的時(shí)候會去解析生成相關(guān)的bean夺姑,這時(shí)候會查看擁有相關(guān)注解的類和方法鳍征,并且為這些類和方法生成代理,并根據(jù)@Transaction的相關(guān)參數(shù)進(jìn)行相關(guān)配置注入或详,這樣就在代理中為我們把相關(guān)的事務(wù)處理掉了(開啟正常提交事務(wù)系羞,異常回滾事務(wù))霸琴。真正的數(shù)據(jù)庫層的事務(wù)提交和回滾是通過binlog或者redo log實(shí)現(xiàn)的椒振。

二、Spring事務(wù)的傳播屬性
所謂spring事務(wù)的傳播屬性梧乘,就是定義在存在多個(gè)事務(wù)同時(shí)存在的時(shí)候澎迎,spring應(yīng)該如何處理這些事務(wù)的行為。這些屬性在TransactionDefinition中定義选调,具體常量的解釋見下表:

Paste_Image.png

三夹供、數(shù)據(jù)庫隔離級別

Paste_Image.png

臟讀:一事務(wù)對數(shù)據(jù)進(jìn)行了增刪改,但未提交仁堪,另一事務(wù)可以讀取到未提交的數(shù)據(jù)哮洽。如果第一個(gè)事務(wù)這時(shí)候回滾了,那么第二個(gè)事務(wù)就讀到了臟數(shù)據(jù)弦聂。
不可重復(fù)讀:一個(gè)事務(wù)中發(fā)生了兩次讀操作鸟辅,第一次讀操作和第二次操作之間,另外一個(gè)事務(wù)對數(shù)據(jù)進(jìn)行了修改莺葫,這時(shí)候兩次讀取的數(shù)據(jù)是不一致的匪凉。
幻讀:第一個(gè)事務(wù)對一定范圍的數(shù)據(jù)進(jìn)行批量修改,第二個(gè)事務(wù)在這個(gè)范圍增加一條數(shù)據(jù)徙融,這時(shí)候第一個(gè)事務(wù)就會丟失對新增數(shù)據(jù)的修改洒缀。
總結(jié):
隔離級別越高,越能保證數(shù)據(jù)的完整性和一致性欺冀,但是對并發(fā)性能的影響也越大树绩。
大多數(shù)的數(shù)據(jù)庫默認(rèn)隔離級別為 Read Commited,比如 SqlServer隐轩、Oracle
少數(shù)數(shù)據(jù)庫默認(rèn)隔離級別為:Repeatable Read 比如: MySQL InnoDB饺饭。

四、Spring中的隔離級別

Paste_Image.png

?五职车、事物的嵌套
通過上面的理論知識的鋪墊瘫俊,我們大致知道了數(shù)據(jù)庫事務(wù)和spring事務(wù)的一些屬性和特點(diǎn),接下來我們通過分析一些嵌套事務(wù)的場景悴灵,來深入理解spring事務(wù)傳播的機(jī)制扛芽。

假設(shè)外層事務(wù) Service A 的 Method A() 調(diào)用 內(nèi)層Service B 的 Method B()

PROPAGATION_REQUIRED(spring 默認(rèn))
如果ServiceB.methodB() 的事務(wù)級別定義為 PROPAGATION_REQUIRED,那么執(zhí)行 ServiceA.methodA() 的時(shí)候spring已經(jīng)起了事務(wù)积瞒,這時(shí)調(diào)用 ServiceB.methodB()川尖,ServiceB.methodB() 看到自己已經(jīng)運(yùn)行在 ServiceA.methodA() 的事務(wù)內(nèi)部,就不再起新的事務(wù)茫孔。
假如 ServiceB.methodB() 運(yùn)行的時(shí)候發(fā)現(xiàn)自己沒有在事務(wù)中叮喳,他就會為自己分配一個(gè)事務(wù)被芳。
這樣,在 ServiceA.methodA() 或者在 ServiceB.methodB() 內(nèi)的任何地方出現(xiàn)異常馍悟,事務(wù)都會被回滾畔濒。

PROPAGATION_REQUIRES_NEW
比如我們設(shè)計(jì) ServiceA.methodA() 的事務(wù)級別為 PROPAGATION_REQUIRED,ServiceB.methodB() 的事務(wù)級別為 PROPAGATION_REQUIRES_NEW锣咒。
那么當(dāng)執(zhí)行到 ServiceB.methodB() 的時(shí)候侵状,ServiceA.methodA() 所在的事務(wù)就會掛起,ServiceB.methodB() 會起一個(gè)新的事務(wù)毅整,等待 ServiceB.methodB() 的事務(wù)完成以后壹将,它才繼續(xù)執(zhí)行。
他與 PROPAGATION_REQUIRED 的事務(wù)區(qū)別在于事務(wù)的回滾程度了毛嫉。因?yàn)?ServiceB.methodB() 是新起一個(gè)事務(wù),那么就是存在兩個(gè)不同的事務(wù)妇菱。如果 ServiceB.methodB() 已經(jīng)提交承粤,那么 ServiceA.methodA() 失敗回滾,ServiceB.methodB() 是不會回滾的闯团。如果 ServiceB.methodB() 失敗回滾辛臊,如果他拋出的異常被 ServiceA.methodA() 捕獲,ServiceA.methodA() 事務(wù)仍然可能提交(主要看B拋出的異常是不是A會回滾的異常)房交。

PROPAGATION_SUPPORTS
假設(shè)ServiceB.methodB() 的事務(wù)級別為 PROPAGATION_SUPPORTS彻舰,那么當(dāng)執(zhí)行到ServiceB.methodB()時(shí),如果發(fā)現(xiàn)ServiceA.methodA()已經(jīng)開啟了一個(gè)事務(wù)候味,則加入當(dāng)前的事務(wù)刃唤,如果發(fā)現(xiàn)ServiceA.methodA()沒有開啟事務(wù),則自己也不開啟事務(wù)白群。這種時(shí)候尚胞,內(nèi)部方法的事務(wù)性完全依賴于最外層的事務(wù)。

PROPAGATION_NESTED
現(xiàn)在的情況就變得比較復(fù)雜了, ServiceB.methodB() 的事務(wù)屬性被配置為 PROPAGATION_NESTED, 此時(shí)兩者之間又將如何協(xié)作呢?
ServiceB#methodB 如果 rollback, 那么內(nèi)部事務(wù)(即 ServiceB#methodB) 將回滾到它執(zhí)行前的 SavePoint 而外部事務(wù)(即 ServiceA#methodA) 可以有以下兩種處理方式:

a帜慢、捕獲異常笼裳,執(zhí)行異常分支邏輯
<pre>
void methodA() {
try {
ServiceB.methodB();
} catch (SomeException) {
// 執(zhí)行其他業(yè)務(wù), 如
ServiceC.methodC();
}
}
</pre>
這種方式也是嵌套事務(wù)最有價(jià)值的地方, 它起到了分支執(zhí)行的效果, 如果 ServiceB.methodB 失敗, 那么執(zhí)行 ServiceC.methodC(), 而 ServiceB.methodB 已經(jīng)回滾到它執(zhí)行之前的 SavePoint, 所以不會產(chǎn)生臟數(shù)據(jù)(相當(dāng)于此方法從未執(zhí)行過), 這種特性可以用在某些特殊的業(yè)務(wù)中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都沒有辦法做到這一點(diǎn)。

b粱玲、 外部事務(wù)回滾/提交 代碼不做任何修改, 那么如果內(nèi)部事務(wù)(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滾到它執(zhí)行之前的 SavePoint(在任何情況下都會如此), 外部事務(wù)(即 ServiceA#methodA) 將根據(jù)具體的配置決定自己是 commit 還是 rollback躬柬。
另外三種事務(wù)傳播屬性基本用不到,在此不做分析抽减。

六允青、總結(jié)
對于項(xiàng)目中需要使用到事務(wù)的地方,我建議開發(fā)者還是使用spring的TransactionCallback接口來實(shí)現(xiàn)事務(wù)胯甩,不要盲目使用spring事務(wù)注解昧廷,如果一定要使用注解堪嫂,那么一定要對spring事務(wù)的傳播機(jī)制和隔離級別有個(gè)詳細(xì)的了解,否則很可能發(fā)生意想不到的效果木柬。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末皆串,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子眉枕,更是在濱河造成了極大的恐慌恶复,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件速挑,死亡現(xiàn)場離奇詭異谤牡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)姥宝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門翅萤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人腊满,你說我怎么就攤上這事套么。” “怎么了碳蛋?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵胚泌,是天一觀的道長。 經(jīng)常有香客問我肃弟,道長玷室,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任笤受,我火速辦了婚禮穷缤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘感论。我一直安慰自己绅项,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布比肄。 她就那樣靜靜地躺著快耿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪芳绩。 梳的紋絲不亂的頭發(fā)上掀亥,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天,我揣著相機(jī)與錄音妥色,去河邊找鬼搪花。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的撮竿。 我是一名探鬼主播吮便,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼幢踏!你這毒婦竟也來了髓需?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤房蝉,失蹤者是張志新(化名)和其女友劉穎僚匆,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體搭幻,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咧擂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了檀蹋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片松申。...
    茶點(diǎn)故事閱讀 38,064評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖俯逾,靈堂內(nèi)的尸體忽然破棺而出攻臀,到底是詐尸還是另有隱情,我是刑警寧澤纱昧,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站堡赔,受9級特大地震影響识脆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜善已,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一灼捂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧换团,春花似錦悉稠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至想虎,卻和暖如春卦尊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背舌厨。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工岂却, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓躏哩,卻偏偏與公主長得像署浩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子扫尺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評論 2 345

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