1. 程式人生 > >Spring Transactional註解

Spring Transactional註解

前言

使用@Transactional 註解有一段時間了,今天來對它進行下總結。

再說這個之前先說下事務。

事務的基本要素(ACID)

  1. 原子性(Atomicity):事務開始後所有操作,要麼全部做完,要麼全部不做,不可能停滯在中間環節。事務執行過程中出錯,會回滾到事務開始前的狀態,所有的操作就像沒有發生一樣。也就是說事務是一個不可分割的整體,就像化學中學過的原子,是物質構成的基本單位。

  2. 一致性(Consistency):事務開始前和結束後,資料庫的完整性約束沒有被破壞 。比如A向B轉賬,不可能A扣了錢,B卻沒收到。

  3. 隔離性(Isolation):同一時間,只允許一個事務請求同一資料,不同的事務之間彼此沒有任何干擾。比如A正在從一張銀行卡中取錢,在A取錢的過程結束前,B不能向這張卡轉賬。

  4. 永續性(Durability):事務完成後,事務對資料庫的所有更新將被儲存到資料庫,不能回滾。

說明

Transactional註解的主要引數如下:

在這裡插入圖片描述

下面來簡單介紹下它的引數:

value:一般用來配置指定的事務管理器。

propagation:事務的傳播屬性,有七種。見列舉Propagation,預設REQUIRED。

//支援當前事務,如果不存在就建立一個
REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
//支援當前事務,如果不存在就以非事務的方式執行
SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS)
, //支援當前事務,不存在就丟擲異常 MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY), //建立一個新事務,如果當前有事務就暫停當前事務 REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW), //以非事務方式執行,如果當前有事務就暫停當前事務 NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED), //以非事務的方式執行,如果當前有事務就丟擲異常 NEVER(TransactionDefinition.PROPAGATION_NEVER)
, //如果當前有事務,就加入當前事務。 NESTED(TransactionDefinition.PROPAGATION_NESTED);

isolation:隔離級別。事務的隔離級別有4種。我們看一下Isolation列舉類。

//使用預設的隔離級別,取決於底層資料庫的預設隔離級別
DEFAULT(TransactionDefinition.ISOLATION_DEFAULT),
//讀未提交,這種隔離級別最低,會出現髒讀,不可重複讀,虛讀(幻讀)等情況。一般不用。
READ_UNCOMMITTED(TransactionDefinition.ISOLATION_READ_UNCOMMITTED),
//讀已提交,這種隔離級別可以防止髒讀的產生,但是無法避免不可重複讀和虛讀(幻讀)的出現。
READ_COMMITTED(TransactionDefinition.ISOLATION_READ_COMMITTED),
//可重複讀,這種隔離級別可以防止髒讀、不可重複讀的出現,但是無法避免虛讀(幻讀)的產生。
REPEATABLE_READ(TransactionDefinition.ISOLATION_REPEATABLE_READ),
//序列化,這種隔離級別最高,可以避免髒讀、不可重複讀和虛讀(幻讀)的產生。
SERIALIZABLE(TransactionDefinition.ISOLATION_SERIALIZABLE);

隔離級別越高,越能保證資料的完整性和一致性,但是對併發效能的影響也越大。

Mysql預設隔離級別為可重複讀。

關於事務的併發問題

  1. 髒讀:事務A讀取了事務B更新的資料,然後B回滾操作,那麼A讀取到的資料是髒資料

  2. 不可重複讀:事務 A 多次讀取同一資料,事務 B 在事務A多次讀取的過程中,對資料作了更新並提交,導致事務A多次讀取同一資料時,結果 不一致。

  3. 幻讀:系統管理員A將資料庫中所有學生的成績從具體分數改為ABCDE等級,但是系統管理員B就在這個時候插入了一條具體分數的記錄,當系統管理員A改結束後發現還有一條記錄沒有改過來,就好像發生了幻覺一樣,這就叫幻讀。

小結:不可重複讀的和幻讀很容易混淆,不可重複讀側重於修改,幻讀側重於新增或刪除。解決不可重複讀的問題只需鎖住滿足條件的行,解決幻讀需要鎖表。

timeout : 事務的超時時間,預設為-1,即事務直到完成都不會超時。

readOnly:是否只讀,一般用來標識。擁有這個標識,寫入操作不一定會失敗,取決於資料庫系統。

rollbackFor:事務回滾條件。引數為繼承Throwable的class類。

rollbackForClassName:事務回滾條件。可以接受String陣列。

noRollbackFor: 事務不會回滾條件。

noRollbackForClassName:事務不會回滾條件。

原理

Spring的Transaction註解是如何實現並生效的呢?我們來探究下。

  1. 我們首先來看看SpringTransactionAnnotationParser這個類,這個是解析transaction註解的類。 在這裡插入圖片描述 呼叫AnnotationUtils類的getAnnotation方法拿到註解資訊。 在這裡插入圖片描述

  2. 可以看到AnnotationTransactionAttributeSource這個類呼叫了parseTransactionAnnotation方法。 在這裡插入圖片描述 在這裡插入圖片描述

  3. 我們來看下AbstractFallbackTransactionAttributeSource這個類的computeTransactionAttribute方法。呼叫了上圖的findTransactionAttribute方法。 在這裡插入圖片描述 在這裡插入圖片描述 getTransactionAttribute方法,由於獲取註解資訊耗時,故spring先從快取裡獲取註解事務資訊,查不到在用程式獲取。

  4. TransactionAspectSupport這個類的createTransactionIfNecessary方法,呼叫getTransactionAttribute方法。 在這裡插入圖片描述

  5. 我們可以看到AbstractTransactionAspect.aj檔案使用了createTransactionIfNecessary方法。 在這裡插入圖片描述 這個應用了aspectj。 Before指在事務開始之前獲取註解資訊。 After throwing 指當方法丟擲異常後的執行動作。這裡一般會進行回滾操作。 After returning指當方法返回前的執行動作。這裡一般會提交事務。 After 指當事務完成後的動作。這裡會清空當前事務註解資訊。

結論

事務的隔離級別和傳播屬性都是我們應該掌握和學習的,對於Spring的@Transactional 註解,我們不但要會使用,而且應該深入去理解它的實現原理。