Spring事務(wù)傳播性與隔離級別

事務(wù)是邏輯處理原子性的保證手段,通過使用事務(wù)控制,可以極大的避免出現(xiàn)邏輯處理失敗導(dǎo)致的臟數(shù)據(jù)等問題。

事務(wù)最重要的兩個(gè)特性,是事務(wù)的傳播級別和數(shù)據(jù)隔離級別。傳播級別定義的是事務(wù)的控制范圍,事務(wù)隔離級別定義的是事務(wù)在數(shù)據(jù)庫讀寫方面的控制范圍。

以下是事務(wù)的7種傳播級別:

1)?PROPAGATION_REQUIRED?,默認(rèn)的spring事務(wù)傳播級別,

特性:上下文中,已經(jīng)存在事務(wù),那么就加入到事務(wù)中執(zhí)行,不存在事務(wù),則新建事務(wù)執(zhí)行。

2)PROPAGATION_SUPPORTS?,從字面意思就知道,supports,支持

特性:上下文中,如果存在事務(wù),則支持事務(wù)加入事務(wù),不存在,則使用非事務(wù)的方式執(zhí)行。

所以說,并非所有的包在transactionTemplate.execute中的代碼都會有事務(wù)支持。這個(gè)通常是用來處理那些并非原子性的非核心業(yè)務(wù)邏輯操作。應(yīng)用場景較少。

3)PROPAGATION_MANDATORY?,?

特性;上下文中,必須要存在事務(wù),否則就會拋出異常!

配置該方式的傳播級別是有效的控制上下文調(diào)用代碼遺漏添加事務(wù)控制的保證手段。比如一段代碼不能單獨(dú)被調(diào)用執(zhí)行,但是一旦被調(diào)用,就必須有事務(wù)包含的情況,就可以使用這個(gè)傳播級別。

4)PROPAGATION_REQUIRES_NEW

?特性:每次都會新建一個(gè)事務(wù),并且同時(shí)將上下文中的事務(wù)掛起,執(zhí)行當(dāng)前新建事務(wù)完成以后,上下文事務(wù)恢復(fù)再 ?執(zhí)行。

這是一個(gè)很有用的傳播級別,舉一個(gè)應(yīng)用場景:現(xiàn)在有一個(gè)發(fā)送100個(gè)紅包的操作,在發(fā)送之前,要做一些系統(tǒng)的初始化、驗(yàn)證、數(shù)據(jù)記錄操作,然后發(fā)送100封紅包,然后再記錄發(fā)送日志,發(fā)送日志要求100%的準(zhǔn)確,如果日志不準(zhǔn)確,那么整個(gè)父事務(wù)邏輯需要回滾。

怎么處理整個(gè)業(yè)務(wù)需求呢?就是通過這個(gè)PROPAGATION_REQUIRES_NEW 級別的事務(wù)傳播控制就可以完成。發(fā)送紅包的子事務(wù)不會直接影響到父事務(wù)的提交和回滾。

5)PROPAGATION_NOT_SUPPORTED?,這個(gè)也可以從字面得知,not supported ,不支持,

特性:上下文中,如果存在事務(wù),則掛起事務(wù),執(zhí)行當(dāng)前邏輯,結(jié)束后恢復(fù)上下文的事務(wù)。

這個(gè)級別有什么好處?可以幫助你將事務(wù)極可能的縮小。我們知道一個(gè)事務(wù)越大,它存在的風(fēng)險(xiǎn)也就越多。所以在處理事務(wù)的過程中,要保證盡可能的縮小范圍。比如一段代碼,是每次邏輯操作都必須調(diào)用的,比如循環(huán)1000次的某個(gè)非核心業(yè)務(wù)邏輯操作。這樣的代碼如果包在事務(wù)中,勢必造成事務(wù)太大,導(dǎo)致出現(xiàn)一些難以考慮周全的異常情況。所以這個(gè)事務(wù)這個(gè)級別的傳播級別就派上用場了。用當(dāng)前級別的事務(wù)模板抱起來就可以了。

6)PROPAGATION_NEVER?,該事務(wù)更嚴(yán)格,上面一個(gè)事務(wù)傳播級別只是不支持而已,有事務(wù)就掛起,

特性:上下文中,不能存在事務(wù),一旦有事務(wù),就拋出runtime異常,強(qiáng)制停止執(zhí)行!

7)PROPAGATION_NESTED?,字面也可知道,nested,嵌套級別事務(wù)。

特性:上下文中,如果存在事務(wù),則作為子事務(wù)嵌套事執(zhí)行,如果不存在事務(wù),則新建事務(wù)。

那么什么是嵌套事務(wù)呢?很多人都不理解,我看過一些博客,都是有些理解偏差。

嵌套是子事務(wù)套在父事務(wù)中執(zhí)行,子事務(wù)是父事務(wù)的一部分,在進(jìn)入子事務(wù)之前,父事務(wù)建立一個(gè)回滾點(diǎn),叫save point,然后執(zhí)行子事務(wù),這個(gè)子事務(wù)的執(zhí)行也算是父事務(wù)的一部分,然后子事務(wù)執(zhí)行結(jié)束,父事務(wù)繼續(xù)執(zhí)行。重點(diǎn)就在于那個(gè)save point。看幾個(gè)問題就明了了:

如果子事務(wù)回滾,會發(fā)生什么??

父事務(wù)會回滾到進(jìn)入子事務(wù)前建立的save point,然后嘗試其他的事務(wù)或者其他的業(yè)務(wù)邏輯,父事務(wù)之前的操作不會受到影響,更不會自動(dòng)回滾。

如果父事務(wù)回滾,會發(fā)生什么??

父事務(wù)回滾,子事務(wù)也會跟著回滾!為什么呢,因?yàn)楦甘聞?wù)結(jié)束之前,子事務(wù)是不會提交的,我們說子事務(wù)是父事務(wù)的一部分,正是這個(gè)道理。那么:

事務(wù)的提交,是什么情況??

是父事務(wù)先提交,然后子事務(wù)提交,還是子事務(wù)先提交,父事務(wù)再提交?答案是第二種情況,還是那句話,子事務(wù)是父事務(wù)的一部分,由父事務(wù)統(tǒng)一提交。

現(xiàn)在你再體會一下這個(gè)”嵌套“,是不是有那么點(diǎn)意思?


PROPAGATION_REQUIRES_NEW?和?PROPAGATION_NESTED區(qū)別

PROPAGATION_REQUIRES_NEW:?完全是一個(gè)獨(dú)立新的事務(wù),不受其它事務(wù)影響。

(詳細(xì)解釋:

擁有自己的隔離范圍, 自己的鎖, 等等. 當(dāng)內(nèi)部事務(wù)開始執(zhí)行時(shí), 外部事務(wù)將被掛起, 內(nèi)務(wù)事務(wù)結(jié)束時(shí), 外部事 ? ? ? ? 務(wù)將繼續(xù) ?執(zhí)行.?)

PROPAGATION_NESTED :是外部事務(wù)的子事務(wù), 不會影響父事務(wù)(子事務(wù)回滾,不會導(dǎo)致父事務(wù)也會滾)

,但受到父事務(wù)控制(父事務(wù)回滾,子事務(wù)也會回滾)。


以上是事務(wù)的7個(gè)傳播級別,在日常應(yīng)用中,通常可以滿足各種業(yè)務(wù)需求,但是除了傳播級別,在讀取數(shù)據(jù)庫的過程中,如果兩個(gè)事務(wù)并發(fā)執(zhí)行,那么彼此之間的數(shù)據(jù)是如何影響的呢?

這就需要了解一下事務(wù)的另一個(gè)特性:數(shù)據(jù)隔離級別

數(shù)據(jù)隔離級別分為不同的四種:

1、Serializable?:最嚴(yán)格的級別,事務(wù)串行執(zhí)行,資源消耗最大;

2、REPEATABLE READ?:保證了一個(gè)事務(wù)不會修改已經(jīng)由另一個(gè)事務(wù)讀取但未提交(回滾)的數(shù)據(jù)。避免了“臟讀取”和“不可重復(fù)讀取”的情況,但是帶來了更多的性能損失。

3、READ COMMITTED?:大多數(shù)主流數(shù)據(jù)庫的默認(rèn)事務(wù)等級,保證了一個(gè)事務(wù)不會讀到另一個(gè)并行事務(wù)已修改但未提交的數(shù)據(jù),避免了“臟讀取”。該級別適用于大多數(shù)系統(tǒng)。

4、Read Uncommitted?:保證了讀取過程中不會讀取到非法數(shù)據(jù)。


上面的解釋其實(shí)每個(gè)定義都有一些拗口,其中涉及到幾個(gè)術(shù)語:臟讀、不可重復(fù)讀、幻讀。

這里解釋一下:


臟讀 :所謂的臟讀,其實(shí)就是讀到了別的事務(wù)回滾前的臟數(shù)據(jù)。比如事務(wù)B執(zhí)行過程中修改了數(shù)據(jù)X,在未提交前,事務(wù)A讀取了X,而事務(wù)B卻回滾了,這樣事務(wù)A就形成了臟讀。


不可重復(fù)讀 :不可重復(fù)讀字面含義已經(jīng)很明了了,比如事務(wù)A首先讀取了一條數(shù)據(jù),然后執(zhí)行邏輯的時(shí)候,事務(wù)B將這條數(shù)據(jù)改變了,然后事務(wù)A再次讀取的時(shí)候,發(fā)現(xiàn)數(shù)據(jù)不匹配了,就是所謂的不可重復(fù)讀了。


幻讀 :小的時(shí)候數(shù)手指,第一次數(shù)十10個(gè),第二次數(shù)是11個(gè),怎么回事?產(chǎn)生幻覺了?

幻讀也是這樣子,事務(wù)A首先根據(jù)條件索引得到10條數(shù)據(jù),然后事務(wù)B改變了數(shù)據(jù)庫一條數(shù)據(jù),導(dǎo)致也符合事務(wù)A當(dāng)時(shí)的搜索條件,這樣事務(wù)A再次搜索發(fā)現(xiàn)有11條數(shù)據(jù)了,就產(chǎn)生了幻讀。


一個(gè)對照關(guān)系表:

?????????????????????????????????????? Dirty reads????????? non-repeatable reads??????????? phantom reads

Serializable????????????????????????? 不會????????????????? ? ? ? 不會????????????????????????? ? ? ? ? ? ? ? ?? 不會

REPEATABLE READ???????????? 不會????????????????? ? ? ? 不會???????????????????????? ? ? ? ? ? ? ? ? ?? 會

READ COMMITTED?????????? ? 不會??????????????????????? 會??????????????????????????? ? ? ? ? ? ? ? ? ? ? 會

Read Uncommitted?????????? ? 會??????????????????? ? ? ?? 會??????????????????????????? ? ? ? ? ? ? ? ? ? ? 會


所以最安全的,是Serializable,但是伴隨而來也是高昂的性能開銷。

另外,事務(wù)常用的兩個(gè)屬性:readonly和timeout

一個(gè)是設(shè)置事務(wù)為只讀以提升性能。

另一個(gè)是設(shè)置事務(wù)的超時(shí)時(shí)間,一般用于防止大事務(wù)的發(fā)生。還是那句話,事務(wù)要盡可能的小!

最后引入一個(gè)問題:

一個(gè)邏輯操作需要檢查的條件有20條,能否為了減小事務(wù)而將檢查性的內(nèi)容放到事務(wù)之外呢??

很多系統(tǒng)都是在DAO的內(nèi)部開始啟動(dòng)事務(wù),然后進(jìn)行操作,最后提交或者回滾。這其中涉及到代碼設(shè)計(jì)的問題。小一些的系統(tǒng)可以采用這種方式來做,但是在一些比較大的系統(tǒng),

邏輯較為復(fù)雜的系統(tǒng)中,勢必會將過多的業(yè)務(wù)邏輯嵌入到DAO中,導(dǎo)致DAO的復(fù)用性下降。所以這不是一個(gè)好的實(shí)踐。

來回答這個(gè)問題:能否為了縮小事務(wù),而將一些業(yè)務(wù)邏輯檢查放到事務(wù)外面?答案是:對于核心的業(yè)務(wù)檢查邏輯,不能放到事務(wù)之外,而且必須要作為分布式下的并發(fā)控制!

一旦在事務(wù)之外做檢查,那么勢必會造成事務(wù)A已經(jīng)檢查過的數(shù)據(jù)被事務(wù)B所修改,導(dǎo)致事務(wù)A徒勞無功而且出現(xiàn)并發(fā)問題,直接導(dǎo)致業(yè)務(wù)控制失敗。

所以,在分布式的高并發(fā)環(huán)境下,對于核心業(yè)務(wù)邏輯的檢查,要采用加鎖機(jī)制。

比如事務(wù)開啟需要讀取一條數(shù)據(jù)進(jìn)行驗(yàn)證,然后邏輯操作中需要對這條數(shù)據(jù)進(jìn)行修改,最后提交。

這樣的一個(gè)過程,如果讀取并驗(yàn)證的代碼放到事務(wù)之外,那么讀取的數(shù)據(jù)極有可能已經(jīng)被其他的事務(wù)修改,當(dāng)前事務(wù)一旦提交,又會重新覆蓋掉其他事務(wù)的數(shù)據(jù),導(dǎo)致數(shù)據(jù)異常。

所以在進(jìn)入當(dāng)前事務(wù)的時(shí)候,必須要將這條數(shù)據(jù)鎖住,使用for update就是一個(gè)很好的在分布式環(huán)境下的控制手段。

一種好的實(shí)踐方式是使用編程式事務(wù)而非生命式,尤其是在較為規(guī)模的項(xiàng)目中。對于事務(wù)的配置,在代碼量非常大的情況下,將是一種折磨,而且人肉的方式,絕對不能避免這種問題。

將DAO保持針對一張表的最基本操作,然后業(yè)務(wù)邏輯的處理放入manager和service中進(jìn)行,同時(shí)使用編程式事務(wù)更精確的控制事務(wù)范圍。

特別注意的,對于事務(wù)內(nèi)部一些可能拋出異常的情況,捕獲要謹(jǐn)慎,不能隨便的catch Exception 導(dǎo)致事務(wù)的異常被吃掉而不能正常回滾。



Spring配置聲明式事務(wù):

* 配置SessionFactory

* 配置事務(wù)管理器

* 事務(wù)的傳播特性

* 那些類那些方法使用事務(wù)


編寫業(yè)務(wù)邏輯方法

* 繼承HibernateDaoSupport類,使用HibernateTemplate來持久化,HibernateTemplate是

?? Hibernate Session的輕量級封裝

* 默認(rèn)情況下運(yùn)行期異常才會回滾(包括繼承了RuntimeException子類),普通異常是不會滾的

* 編寫業(yè)務(wù)邏輯方法時(shí),最好將異常一直向上拋出,在表示層(struts)處理

* 關(guān)于事務(wù)邊界的設(shè)置,通常設(shè)置到業(yè)務(wù)層,不要添加到Dao上

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,995評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,991評論 2 374

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