@Transactional

一、作用于接口、接口方法、類以及類方法上

1??當(dāng)作用于類上時,該類的所有 public 方法將都具有該類型的事務(wù)屬性。

2??當(dāng)作用在方法級別時會覆蓋類級別的定義。

3??當(dāng)作用在接口和接口方法時則只有在使用基于接口的代理時它才會生效,也就是 JDK 動態(tài)代理,而不是 Cglib 代理。如果正在使用基于類的代理(也就是 CGLIB 代理)時,那么事務(wù)的設(shè)置將不能被基于類的代理所識別,而且對象也將不會被事務(wù)代理所包裝,因?yàn)樽⒔馐遣荒芾^承的。
Spring 的建議是在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實(shí)現(xiàn)的任何接口上。

4??當(dāng)在 protected、private 或者默認(rèn)可見性的方法上使用 @Transactional 時是不會生效的,也不會拋出任何異常。

5??默認(rèn)情況下,只有來自外部的方法調(diào)用才會被 AOP 代理捕獲,也就是,類內(nèi)部方法調(diào)用本類內(nèi)部的其他方法并不會引起事務(wù)行為,即使被調(diào)用方法使用 @Transactional 進(jìn)行修飾。

二、@Transactional 配置事務(wù)失效的場景

1??@Transactional 應(yīng)用在非 public 修飾的方法上。
注意:protected、private 修飾的方法上使用 @Transactional,雖然事務(wù)無效,但不會有任何報(bào)錯。

2??@Transactional 屬性 propagation 設(shè)置錯誤。
這種失效是由于配置錯誤,若是錯誤的配置以下三種 propagation,事務(wù)將不會發(fā)生回滾:
@Transactional(propagation=Propagation.SUPPORTS):如果當(dāng)前存在事務(wù),則加入該事務(wù);如果當(dāng)前沒有事務(wù),則以非事務(wù)的方式繼續(xù)運(yùn)行。 ②@Transactional(propagation=Propagation.NOT_SUPPORTED):以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
@Transactional(propagation=Propagation.NEVER):以非事務(wù)方式運(yùn)行,如果當(dāng)前存在事務(wù),則拋出異常。

3??@Transactional 屬性 rollbackFor 設(shè)置錯誤。
rollbackFor 可以指定能夠觸發(fā)事務(wù)回滾的異常類型。Spring 默認(rèn)拋出了未檢查 unchecked 異常(繼承自 RuntimeException 的異常)或者 Error 才回滾事務(wù);其他異常不會觸發(fā)回滾事務(wù)。如果在事務(wù)中拋出其他類型的異常,但卻期望 Spring 能夠回滾事務(wù),就需要指定 rollbackFor 屬性。

4??同一個類中方法調(diào)用,導(dǎo)致 @Transactional 失效。
一個類 Test,它的方法 A(未聲明注解事務(wù)),調(diào)用本類的方法 B(聲明有注解事務(wù)。不論是 public 的還是 private 的)。外部調(diào)用方法 A 之后,方法 B 的事務(wù)是不會起作用的。

5??如果異常被try{}catch{}了,事務(wù)就不回滾。如果想讓事務(wù)回滾必須再往外拋try{}catch{throw new RunTimeException()}。

如果 B 方法內(nèi)部拋了異常,而 A 方法此時 try catch 了 B 方法的異常,該事務(wù)不能正?;貪L。會拋出異常:

org.springframework.transaction.UnexpectedRollbackException: 
Transaction rolled back because it has been marked as rollback-only

因?yàn)楫?dāng) B 中拋出了一個異常以后,B 標(biāo)識當(dāng)前事務(wù)需要 rollback。但是由于 A 手動捕獲該異常并進(jìn)行處理,A 認(rèn)為當(dāng)前事務(wù)應(yīng)該正常 commit。此時就出現(xiàn)了前后不一致,也就是因?yàn)檫@樣,拋出了前面的UnexpectedRollbackException。

Spring 的事務(wù)是在調(diào)用業(yè)務(wù)方法之前開始的,業(yè)務(wù)方法執(zhí)行完畢之后才執(zhí)行 commit/rollback,事務(wù)是否執(zhí)行取決于是否拋出 RuntimeException。如果拋出 RuntimeException,并在業(yè)務(wù)方法中沒有 catch 的話,事務(wù)會回滾。

在業(yè)務(wù)方法中一般不需要 catch 異常,如果非要 catch 一定要throw new RuntimeException(),或者注解中指定拋異常類型@Transactional(rollbackFor = Exception.class),否則會導(dǎo)致事務(wù)失效,數(shù)據(jù) commit 造成數(shù)據(jù)不一致,所以有些時候 try catch 反倒會畫蛇添足。

6??數(shù)據(jù)庫引擎不支持事務(wù)
事務(wù)能否生效,數(shù)據(jù)庫引擎是否支持事務(wù)是關(guān)鍵。常用的 MySQL 數(shù)據(jù)庫默認(rèn)使用支持事務(wù)的 innodb 引擎。一旦數(shù)據(jù)庫引擎切換成不支持事務(wù)的 MyISAM,那事務(wù)就從根本上失效了。

三、@Transactional 的可用參數(shù)

1??readOnly
該屬性用于設(shè)置當(dāng)前事務(wù)是否為只讀事務(wù),設(shè)置為 true 表示只讀,false 則表示可讀寫,默認(rèn)值為 false。

理解:
如果一次執(zhí)行單條查詢語句,則沒有必要啟用事務(wù)支持,數(shù)據(jù)庫默認(rèn)支持 SQL 執(zhí)行期間的讀一致性。
如果一次執(zhí)行多條查詢語句,例如統(tǒng)計(jì)查詢,報(bào)表查詢,在這種場景下,多條查詢 SQL 必須保證整體的讀一致性。否則,在前條 SQL 查詢之后,后條 SQL 查詢之前,數(shù)據(jù)被其他用戶改變,則該次整體的統(tǒng)計(jì)查詢將會出現(xiàn)讀數(shù)據(jù)不一致的狀態(tài),此時,應(yīng)該啟用事務(wù)支持。
【注意是一次執(zhí)行多次查詢來統(tǒng)計(jì)某些信息,這時為了保證數(shù)據(jù)整體的一致性,要用只讀事務(wù)】

2??rollbackFor
該屬性用于設(shè)置需要進(jìn)行回滾的異常類數(shù)組,當(dāng)方法中拋出指定異常數(shù)組中的異常時,則進(jìn)行事務(wù)回滾。例如:

  1. 指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)
  2. 指定多個異常類:@Transactional(rollbackFor={RuntimeException.class,BusinessException.class})

3??rollbackForClassName
該屬性用于設(shè)置需要進(jìn)行回滾的異常類名稱數(shù)組,當(dāng)方法中拋出指定異常名稱數(shù)組中的異常時,則進(jìn)行事務(wù)回滾。例如:

  1. 指定單一異常類名稱:@Transactional(rollbackForClassName="RuntimeException")
  2. 指定多個異常類名稱:@Transactional(rollbackForClassName={"RuntimeException","BusnessException"})

4??noRollbackFor
該屬性用于設(shè)置不需要進(jìn)行回滾的異常類數(shù)組,當(dāng)方法中拋出指定異常數(shù)組中的異常時,不進(jìn)行事務(wù)回滾。

5??timeout
該屬性用于設(shè)置事務(wù)的超時秒數(shù),默認(rèn)值為 -1,表示永不超時。

6??propagation
該屬性用于設(shè)置事務(wù)傳播行為。例如:@Transactional(propagation=Propagation.NOT_SUPPORTED)

四、基于注解@Transactional的事務(wù)

Spring 的事務(wù)基礎(chǔ)架構(gòu)代碼將默認(rèn)地只在拋出 RuntimeException 和 unchecked exceptions 時才標(biāo)識事務(wù)回滾。也就是說,當(dāng)拋出 RuntimeException 或其子類例的實(shí)例時(error 也一樣)默認(rèn)標(biāo)識事務(wù)回滾。從事務(wù)方法中拋出的 Checked exceptions 將不被標(biāo)識進(jìn)行事務(wù)回滾。

1??@Transactional 的異??刂疲J(rèn)是 unChecked Exception 回滾;Checked Exception 不回滾。
2??如果配置了rollbackFor 和 noRollbackFor 且兩個都是用同樣的異常,那么遇到該異常,還是回滾。
3??rollbackFor 和 noRollbackFor 配置也許不會涵蓋所有異常,對于遺漏的按照 unChecked Exception 回滾,Check ed Exception 不回滾。
4??讓 checked 例外也回滾:
在整個方法前加上@Transactional(rollbackFor=Exception.class)
5??讓 unchecked 例外不回滾:
@Transactional(notRollbackFor=RunTimeException.class)
6??不需要事務(wù)管理的(只查詢的)方法:
@Transactional(propagation=Propagation.NOT_SUPPORTED)

注意:
1??@Transactional 標(biāo)識的方法,處理過程盡量的簡單。尤其是帶鎖的事務(wù)方法,能不放在事務(wù)里面的最好不要放在事務(wù)里面??梢詫⒊R?guī)的數(shù)據(jù)庫查詢操作放在事務(wù)前面進(jìn)行,而事務(wù)內(nèi)進(jìn)行增、刪、改、加鎖查詢等操作。

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