事務是邏輯上的一組操做,要麼都執行,要麼都不執行java
程序是否支持事務是取決於數據庫是否支持事務spring
MySQL是如何保證原子性的:sql
恢復機制是依賴回滾日誌實現的數據庫
編程式事務,在代碼中硬編碼(不推薦使用)編程
聲明式事務,在配置文件中配置(推薦使用),代碼侵入性小,經過AOP實現後端
Spring中事務管理相關的最重要的三個接口以下服務器
Spring並不直接管理事務,而是提供了多種事務管理器。spring經過該事務管理接口爲多個平臺提供了對應的事務管理器,具體的實現就是各個平臺本身的事情了。併發
該接口主要是將事務管理行爲抽象出來,而後不一樣的平臺去實現它,能夠保證提供給外部的行爲不變,方便咱們擴展。性能
該類定義了一些基本的事務屬性。優化
事務屬性包括了五個方面
該接口用來記錄事務的狀態,該接口定義了一組方法,用來獲取或判斷事務的相應狀態信息。
public interface TransactionStatus{ boolean isNewTransaction(); // 是不是新的事務 boolean hasSavepoint(); // 是否有恢復點 void setRollbackOnly(); // 設置爲只回滾 boolean isRollbackOnly(); // 是否爲只回滾 boolean isCompleted; // 是否已完成 }
事務傳播行爲是爲了解決業務層之間互相調用的事務問題。
當事務方法被另外一個事務方法調用時,必須制定事務應該如何傳播。例如:方法可能繼續在現有的事務中運行,也可能開啓一個新事務,並在本身的事務中運行。
事務傳播行爲類型 | 說明 | 是否支持當前事務 |
---|---|---|
REQUIRED | 若是當前存在事務,則加入該事務;若是當前沒有事務,則建立一個新的事務。(默認狀況) | ✔ |
SUPPORTS | 若是當前存在事務,則加入該事務;若是當前沒有事務,則以非事務的方式繼續運行。 | ✔ |
MANDATORY | 若是當前存在事務,則加入該事務;若是當前沒有事務,則拋出異常。(mandatory:強制性) | ✔ |
REQUIRES_NEW | 建立一個新的事務,若是當前存在事務,則把當前事務掛起。 | ✘ |
NOT_SUPPORTED** | 以非事務方式運行,若是當前存在事務,則把當前事務掛起。 | ✘ |
NEVER | 以非事務方式運行,若是當前存在事務,則拋出異常。 | ✘ |
NESTED | 若是當前存在事務,則建立一個事務做爲當前事務的嵌套事務來運行;若是當前沒有事務,則該取值等價於REQUIRED。 | ☹ |
TransactionDefinition接口中定義了五個表示隔離級別的常量。
所謂事務超時,就是指一個事務所容許執行的最長時間,若是超過該時間限制但事務尚未完成,則自動回滾事務。在TransactionDefinition中以int的值來表示超時時間,其單位是秒,默認值是-1
對於只有讀取數據查詢的事務,能夠指定事務類型爲readonly,即只讀屬性。只讀事務不涉及數據的修改,數據庫會提供一些優化手段,適合用在有多條數據庫查詢操做的方法中。
MySQL默認對每個新創建的鏈接都啓用了autocommit模式,在該模式下,每個發送到MySQL服務器的sql語句都會在一個單獨的事務中處理,執行結束後會自動提交事務,並開啓一個新事務。
若是不加Transaction,每條sql會開啓一個單獨的事務,中間被其餘事務改了數據,都會實時讀取到最新值。
若是你一次執行多條查詢語句,例如統計查詢,報表查詢,在這種場景下,多條查詢 SQL 必須保證總體的讀一致性,不然,在前條 SQL 查詢以後,後條 SQL 查詢以前,數據被其餘用戶改變,則該次總體的統計查詢將會出現讀數據不一致的狀態,此時,應該啓用事務支持
這些規則定義了那些異常會致使事務回滾而那些不會。默認狀況下,事務只有遇到了運行時異常(RuntimeException的子類)時纔會回滾,Error也會致使事務回滾,可是在遇到檢查型(Checked)異常時不會回滾。
若是要定義你回滾的異常類型能夠這樣
@Transactional(rollbackFor = MyException.class)
@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的工做機制是基於AOP實現的,AOP有事使用動態代理實現的。若是目標對象實現了接口,默認狀況下采用JDK的動態代理,若是對象沒有實現接口,會使用Cglib來作動態代理
createAopProxy()方法決定了使用JDK仍是Cglib來作動態代理
若是一個類或者一個類中的public方法上被標註@Transaction註解的話,Spring容器會在啓動的時候爲其建立一個代理類,在調用被@Transaction註解的public方法的時候,實際調用的是TransactionInterceptor類中的invoke方法。這個方法的做用就是在目標方法以前開啓事務,方法執行過程當中若是遇到異常的時候回滾事務,方法調用完成後提交事務。
若同一類中的其餘沒有@Transaction註解的方法內部調用有@Transaction註解的方法,有@Transaction註解的方法的事務會失效。
這是因爲Spring AOP代理的緣由形成的,由於只有@Transaction註解的方法在類之外被調用的時候,Spring事務管理才生效。
解決方法就是避免同一類中自調用或者使用AspectJ取代Spring AOP代理。
——我是冢狐,和你同樣熱愛編程。
歡迎關注公衆號「Java冢狐」獲取最新消息