(十二)Spring從入門到入土——Spring事務

Spring事務

事務是邏輯上的一組操做,要麼都執行,要麼都不執行java

事務的特性(ACID)

  • 原子性
  • 一致性
  • 隔離性
  • 持久性

Spring管理事務的方式有幾種

程序是否支持事務是取決於數據庫是否支持事務spring

MySQL是如何保證原子性的:sql

恢復機制是依賴回滾日誌實現的數據庫

  • 編程式事務,在代碼中硬編碼(不推薦使用)編程

  • 聲明式事務,在配置文件中配置(推薦使用),代碼侵入性小,經過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和計算機基礎知識,保證讓你看完有所收穫,不信你打我
  • 若是看完有不一樣的意見或者建議,歡迎多多評論一塊兒交流。感謝各位的支持以及厚愛。

——我是冢狐,和你同樣熱愛編程。

image

歡迎關注公衆號「Java冢狐」獲取最新消息

相關文章
相關標籤/搜索