SpringMVC-@Transaction聲明事務的使用

1- 事務ACID

事務由一系列操作組成的,保證所有操作整體原子執行,完整的事務滿足ACID特性

  • 原子性(Atomicity):事務是一個原子操作,由一系列動作組成。事務的原子性確保動作要么全部完成,要么完全不起作用。

  • 一致性(Consistency):一旦事務完成(不管成功還是失?。?,系統必須確保它所建模的業務處于一致的狀態,而不會是部分完成部分失敗。在現實中的數據不應該被破壞。

  • 隔離性(Isolation):可能有許多事務會同時處理相同的數據,因此每個事務都應該與其他事務隔離開來,防止數據損壞。

  • 持久性(Durability):一旦事務完成,無論發生什么系統錯誤,它的結果都不應該受到影響,這樣就能從任何系統崩潰中恢復過來。通常情況下,事務的結果被寫到持久化存儲器中。

2- 事務管理器

Spring并不直接管理事務,而是提供了多種事務管理器,他們將事務管理的職責委托給Hibernate或者JTA等持久化機制所提供的相關平臺框架的事務來實現。

2.1- PlatformTransactionManager

org.springframework.transaction.PlatformTransactionManager是Spring事務管理器的接口,通過這個接口,Spring為各個平臺如JDBC、Hibernate等都提供了對應的事務管理器,但是具體的實現就是各個平臺自己的事情了。

PlatformTransactionManager接口


提供了獲取TransactionDefinition的方法以及根據TransactionStatus相應的狀態進行提交或者回滾

TransactionStatus事務狀態接口

上面講到的調用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一個實現,這個接口的內容如下:


TransactionDefinition事務定義的接口

而TransactionDefinition接口內容如下:
屬性:



方法:


3- TransactionDefinition接口定義的事務的五個屬性

3.1- 傳播行為

當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播,沒有默認值。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行

我們可以看 org.springframework.transaction.annotation.Propagation 枚舉類中定義了6個表示傳播行為的枚舉值:

  • REQUIRED :如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。
  • SUPPORTS :如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
  • MANDATORY :如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
  • REQUIRES_NEW :創建一個新的事務,如果當前存在事務,則把當前事務掛起。
  • NOT_SUPPORTED :以非事務方式運行,如果當前存在事務,則把當前事務掛起。
  • NEVER :以非事務方式運行,如果當前存在事務,則拋出異常。
  • NESTED :如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價于 REQUIRED 。
    指定方法:通過使用 propagation 屬性設置,例如:
    @Transactional(propagation = Propagation.REQUIRED)
3.2- 隔離級別

隔離級別是指若干個并發的事務之間的隔離程度,與我們開發時候主要相關的場景包括:臟讀取、重復讀、幻讀。

并發事務引起的問題

在典型的應用程序中,多個事務并發運行,經常會操作相同的數據來完成各自的任務。并發雖然是必須的,但可能會導致一下的問題。

  • 臟讀(Dirty reads)——臟讀發生在一個事務讀取了另一個事務改寫但尚未提交的數據時。如果改寫在稍后被回滾了,那么第一個事務獲取的數據就是無效的。
  • 不可重復讀(Nonrepeatable read)——不可重復讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的數據時。這通常是因為另一個并發事務在兩次查詢期間進行了更新。
  • 幻讀(Phantom read)——幻讀與不可重復讀類似。它發生在一個事務(T1)讀取了幾行數據,接著另一個并發事務(T2)插入了一些數據時。在隨后的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄。

不可重復讀與幻讀的區別

  • 不可重復讀的重點是修改:
    同樣的條件, 你讀取過的數據, 再次讀取出來發現值不一樣了 ,在一個事務中前后兩次讀取的結果并不一致,導致了不可重復讀。
  • 幻讀的重點在于新增或者刪除:
    同樣的條件, 第1次和第2次讀出來的記錄數不一樣
  • 從總的結果來看, 似乎不可重復讀和幻讀都表現為兩次讀取的結果不一致。但如果你從控制的角度來看, 兩者的區別就比較大:
    對于前者, 只需要鎖住滿足條件的記錄。
    對于后者, 要鎖住滿足條件及其相近的記錄。

我們可以看 org.springframework.transaction.annotation.Isolation 枚舉類中定義了五個表示隔離級別的值:

  • DEFAULT :這是默認值,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言,通常這值就是: READ_COMMITTED ,Mysql為REPEATABLE_READ。
  • READ_UNCOMMITTED :該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止臟讀和不可重復讀,因此很少使用該隔離級別。
  • READ_COMMITTED :該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀,這也是大多數情況下的推薦值。
  • REPEATABLE_READ :該隔離級別表示一個事務在整個過程中可以多次重復執行某個查詢,并且每次返回的記錄都相同。即使在多次查詢之間有新增的數據滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止臟讀和不可重復讀。
  • SERIALIZABLE :所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。
    指定方法:通過使用 isolation 屬性設置,例如:
    @Transactional(isolation = Isolation.DEFAULT)
3.3- 只讀

事務的第三個特性是它是否為只讀事務。如果事務只對后端的數據庫進行該操作,數據庫可以利用事務的只讀特性來進行一些特定的優化。通過將事務設置為只讀,你就可以給數據庫一個機會,讓它應用它認為合適的優化措施。

3.4- 事務超時

為了使應用程序很好地運行,事務不能運行太長的時間。因為事務可能涉及對后端數據庫的鎖定,所以長時間的事務會不必要的占用數據庫資源。事務超時就是事務的一個定時器,在特定時間內事務如果沒有執行完畢,那么就會自動回滾,而不是一直等待其結束。

3.5- 回滾規則

事務五邊形的最后一個方面是一組規則,這些規則定義了哪些異常會導致事務回滾而哪些不會。默認情況下,事務只有遇到運行期異常Unchecked時才會回滾,而在遇到檢查型異常時不會回滾(這一行為與EJB的回滾行為是一致的)
但是你可以聲明事務在遇到特定的檢查型異常時像遇到運行期異常那樣回滾。同樣,你還可以聲明事務遇到特定的異常不回滾,即使這些異常是運行期異常。

4- Spring Boot 基于聲明式注解事務使用示例

在Spring Boot中,當我們使用了spring-boot-starter-jdbc或spring-boot-starter-data-jpa依賴的時候,框 架會自動默認分別注入DataSourceTransactionManager或JpaTransactionManager。所以我們不需要任何額外 配置就可以用@Transactional注解進行事務的使用。關于事務管理器,不管是JPA還是JDBC等都實現自接口 PlatformTransactionManager 如果你添加的是 spring-boot-starter-jdbc 依賴,框架會默認注入 DataSourceTransactionManager 實例。如果你添加的是 spring-boot-starter-data-jpa 依賴,框架會默認注入 JpaTransactionManager 實例。

4.1- 事務管理兩種方式

spring支持編程式事務管理和聲明式事務管理兩種方式。

  1. 編程式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對于編程式事務管理,spring推薦使用TransactionTemplate。

  2. 聲明式事務管理建立在AOP之上的。其本質是對方法前后進行攔截,然后在目標方法開始之前創建或者加入一個事務,在執行完目標方法之后根據執行情況提交或者回滾事務。聲明式事務最大的優點就是不需要通過編程的方式管理事務,這樣就不需要在業務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關的事務規則聲明(或通過基于@Transactional注解的方式),便可以將事務規則應用到業務邏輯中。

4.2- 單事務管理開啟與配置

在啟動類中配置事務管理器

  1. 默認事務管理器,只需開啟事務管理器即可,不需顯示的配置
  1. 顯示的指明事務管理器

如果你項目做的比較大,添加的持久化依賴比較多,我們還是會選擇人為的指定使用哪個事務管理器



在Spring容器中,我們手工注解@Bean 將被優先加載,框架不會重新實例化其他的 PlatformTransactionManager 實現類。

4.3- 多事務管理器的配置

對于同一個工程中存在多個事務管理器進行配置



啟動類實現TransactionManagementConfigurer接口,通過@Bean注解注入兩個事務管理器,實現annotationDrivenTransactionManager接口方法,指定value缺省值情況下提供的默認事務管理器,如下:



注:
如果Spring容器中存在多個 PlatformTransactionManager 實例,并且沒有實現接口 TransactionManagementConfigurer 指定默認值,在我們在方法上使用注解 @Transactional 的時候,就必須要用value指定,如果不指定,則會拋出異常。
4.4- @Transaction 注解使用的注意事項

@Transactional屬性


noRollback示例



@Transactional 可以作用于接口、接口方法、類以及類方法上。當作用于類上時,該類的所有 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別使用該標注來覆蓋類級別的定義。

最佳實踐:

  • 雖然 @Transactional 注解可以作用于接口、接口方法、類以及類方法上,但是 Spring 建議不要在接口或者接口方法上使用該注解,因為這只有在使用基于接口的代理時它才會生效。

  • @Transactional 注解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。如果你在 protected、private 或者默認可見性的方法上使用 @Transactional 注解,這將被忽略,也不會拋出任何異常。

  • 默認情況下,只有來自外部的方法調用才會被AOP代理捕獲,也就是,類內部方法調用本類內部的其他方法并不會引起事務行為,即使被調用方法使用@Transactional注解進行修飾。

事務異常排查列表:

  1. 數據庫本身是否支持事務,如mysql的myisam引擎就不支持事務
  2. 多數據源,是否指定了正確的事務管理器
  3. 數據源配置是否正確(MyBatis的SqlSessionFactoryBean引用的數據源與DataSourceTransactionManager引用的數據源是否一致)
  4. 私有方法不會生效事務(AOP默認不代理私有方法,也不會拋出異常)
  5. 被調用方法不會生效事務(this指針調用方法,并沒有使用AOP代理來執行方法)
  6. 不指明回滾的異常,方法內用戶拋出的checked異常不會生效回滾(默認只有unchecked異常發生回滾)

MyBatis自動參與到spring事務管理中,無需額外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的數據源與DataSourceTransactionManager引用的數據源一致即可,否則事務管理會不起作用。

@Transaction示例

方法上注解屬性會覆蓋類注解上的相同屬性



事務管理器保證事務方法內的SQL在同一個SqlSession中,相當于:


參考鏈接
Spring聲明式事務為何不回滾

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

推薦閱讀更多精彩內容

  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,891評論 6 342
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • 這部分的參考文檔涉及數據訪問和數據訪問層和業務或服務層之間的交互。 Spring的綜合事務管理支持覆蓋很多細節,然...
    竹天亮閱讀 1,044評論 0 0
  • spring官方文檔:http://docs.spring.io/spring/docs/current/spri...
    牛馬風情閱讀 1,699評論 0 3
  • 很多人喜歡這篇文章,特此同步過來 由淺入深談論spring事務 前言 這篇其實也要歸納到《常識》系列中,但這重點又...
    碼農戲碼閱讀 4,755評論 2 59