Spring事務
事務是邏輯上的一組操作,要么都執行,要么都不執行
事務的特性(ACID)
- 原子性
- 一致性
- 隔離性
- 持久性
Spring管理事務的方式有幾種
程式是否支持事務是取決于資料庫是否支持事務
MySQL是如何保證原子性的:
恢復機制是依賴回滾日志實作的
-
編程式事務,在代碼中硬編碼(不推薦使用)
-
宣告式事務,在組態檔中配置(推薦使用),代碼侵入性小,通過AOP實作
-
- 基于XML的宣告式事務
- 基于注解的宣告式事務
Spring事務管理介面介紹
Spring中事務管理相關的最重要的三個介面如下
- PlatformTransactionManager:(平臺)事務管理器,Spring事務策略的核心(上層管理者)
- TransactionDefinition:事務定義資訊(事務隔離級別、傳播行為、超時、只讀、回滾規則)
- TransactionStatus:事務運行狀態
PlatformTransactionManager:事務管理介面
Spring并不直接管理事務,而是提供了多種事務管理器,spring通過該事務管理介面為多個平臺提供了對應的事務管理器,具體的實作就是各個平臺自己的事情了,
該介面主要是將事務管理行為抽象出來,然后不同的平臺去實作它,可以保證提供給外部的行為不變,方便我們擴展,
TransactionDefinition:事務屬性
該類定義了一些基本的事務屬性,
-
事務屬性包括了五個方面
-
- 隔離級別
- 傳播行為
- 回滾規則
- 是否只讀
- 事務超時
TransactionStatus:事務狀態
該介面用來記錄事務的狀態,該介面定義了一組方法,用來獲取或判斷事務的相應狀態資訊,
public interface TransactionStatus{
boolean isNewTransaction(); // 是否是新的事務
boolean hasSavepoint(); // 是否有恢復點
void setRollbackOnly(); // 設定為只回滾
boolean isRollbackOnly(); // 是否為只回滾
boolean isCompleted; // 是否已完成
}
事務屬性詳解
Spring事務傳播行為(列舉類:Propagation)
事務傳播行為是為了解決業務層之間互相呼叫的事務問題,
當事務方法被另一個事務方法呼叫時,必須制定事務應該如何傳播,例如:方法可能繼續在現有的事務中運行,也可能開啟一個新事務,并在自己的事務中運行,
| 事務傳播行為型別 | 說明 | 是否支持當前事務 |
|---|---|---|
| REQUIRED | 如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務,(默認情況) | ? |
| SUPPORTS | 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行, | ? |
| MANDATORY | 如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出例外,(mandatory:強制性) | ? |
| REQUIRES_NEW | 創建一個新的事務,如果當前存在事務,則把當前事務掛起, | ? |
| NOT_SUPPORTED** | 以非事務方式運行,如果當前存在事務,則把當前事務掛起, | ? |
| NEVER | 以非事務方式運行,如果當前存在事務,則拋出例外, | ? |
| NESTED | 如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價于REQUIRED, | ? |
Spring事務中的隔離級別(列舉類:Isolation)
TransactionDefinition介面中定義了五個表示隔離級別的常量,
- ISOLATION_DEFAULT: 后端資料庫默認的隔離級別,Mysql 默認采用的 REPEATABLE_READ隔離級別 Oracle 默認采用的 READ_COMMITTED隔離級別.
- ISOLATION_READ_UNCOMMITTED: 最低的隔離級別,允許讀取尚未提交的資料變更,可能會導致臟讀、幻讀或不可重復讀
- ISOLATION_READ_COMMITTED: 允許讀取并發事務已經提交的資料,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生
- ISOLATION_REPEATABLE_READ: 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生,
- ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別,所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀,但是這將嚴重影響程式的性能,通常情況下也不會用到該級別,
事務超時屬性
所謂事務超時,就是指一個事務所允許執行的最長時間,如果超過該時間限制但事務還沒有完成,則自動回滾事務,在TransactionDefinition中以int的值來表示超時時間,其單位是秒,默認值是-1
事務只讀屬性
對于只有讀取資料查詢的事務,可以指定事務型別為readonly,即只讀屬性,只讀事務不涉及資料的修改,資料庫會提供一些優化手段,適合用在有多條資料庫查詢操作的方法中,
MySQL默認對每一個新建立的連接都啟用了autocommit模式,在該模式下,每一個發送到MySQL服務器的sql陳述句都會在一個單獨的事務中處理,執行結束后會自動提交事務,并開啟一個新事務,
如果不加Transaction,每條sql會開啟一個單獨的事務,中間被其他事務改了資料,都會實時讀取到最新值,
如果你一次執行多條查詢陳述句,例如統計查詢,報表查詢,在這種場景下,多條查詢 SQL 必須保證整體的讀一致性,否則,在前條 SQL 查詢之后,后條 SQL 查詢之前,資料被其他用戶改變,則該次整體的統計查詢將會出現讀資料不一致的狀態,此時,應該啟用事務支持
事務回滾規則
這些規則定義了那些例外會導致事務回滾而那些不會,默認情況下,事務只有遇到了運行時例外(RuntimeException的子類)時才會回滾,Error也會導致事務回滾,但是在遇到檢查型(Checked)例外時不會回滾,
如果要定義你回滾的例外型別可以這樣
@Transactional(rollbackFor = MyException.class)
@Transaction注解
作用范圍
- 方法:推薦將注解使用在方法上,不過需要注意的是,該注解只能應用到public方法上,否則不生效
- 類:如果定義在類上,說明對該類中的所有public方法有有效
- 介面:不推薦在介面上使用
常用配置引數
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default TransactionDefinition.TIMEOUT_DEFAULT;
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
@Transactional的常用配置引數總結
| 屬性名 | 說明 |
|---|---|
| propagation | 事務的傳播方式,默認REQUIRED |
| isolation | 事務的隔離級別,默認DEFAULT |
| timeout | 事務超時時間,默認-1(不會超時),如果超過時間限制沒有完成,則自動回滾 |
| readOnly | 指定事務是否只讀,默認為false |
| rollbackFor | 用于指定能夠觸發事務回滾的例外型別,并且可以指定多個例外型別 |
@Transaction事務注解原理
@Transaction的作業機制是基于AOP實作的,AOP有事使用動態代理實作的,如果目標物件實作了介面,默認情況下采用JDK的動態代理,如果物件沒有實作介面,會使用Cglib來做動態代理
createAopProxy()方法決定了使用JDK還是Cglib來做動態代理
如果一個類或者一個類中的public方法上被標注@Transaction注解的話,Spring容器會在啟動的時候為其創建一個代理類,在呼叫被@Transaction注解的public方法的時候,實際呼叫的是TransactionInterceptor類中的invoke方法,這個方法的作用就是在目標方法之前開啟事務,方法執行程序中如果遇到例外的時候回滾事務,方法呼叫完成后提交事務,
注解失效情況
應用在非public修飾的方法上
Spring AOP自呼叫問題
若同一類中的其他沒有@Transaction注解的方法內部呼叫有@Transaction注解的方法,有@Transaction注解的方法的事務會失效,
這是由于Spring AOP代理的原因造成的,因為只有@Transaction注解的方法在類以外被呼叫的時候,Spring事務管理才生效,
解決方法就是避免同一類中自呼叫或者使用AspectJ取代Spring AOP代理,
propagation屬性設定錯誤
rollbackFor屬性設定錯誤
try/catch中沒有拋出例外導致失效
資料庫不支持事務
最后
- 如果覺得看完有識訓,希望能給我點個贊,這將會是我更新的最大動力,感謝各位的支持
- 歡迎各位關注我的公眾號【java冢狐】,專注于java和計算機基礎知識,保證讓你看完有所識訓,不信你打我
- 如果看完有不同的意見或者建議,歡迎多多評論一起交流,感謝各位的支持以及厚愛,
——我是冢狐,和你一樣熱愛編程,

歡迎關注公眾號“Java冢狐”獲取最新訊息
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/249696.html
標籤:Java
