1. 程式人生 > 其它 >springboot事務失效的日常總結(@Transactional)

springboot事務失效的日常總結(@Transactional)

springboot事務失效的日常總結(@Transactional)

什麼是事務

​ 事務(Transaction),一般是指要做的或所做的事情。在計算機術語中是指訪問並可能更新資料庫中各種資料項的一個程式執行單元(unit)。

​ 事務是恢復和併發控制的基本單位

事務應該具有4個屬性:(這裡指的是單機,不是分散式

​ 原子性、一致性、隔離性、永續性。這四個屬性通常稱為ACID特性(單講一篇)

說人話就是:

​ 資料庫一次執行資料的單元(要麼這個事務(執行的sql)都成功,要麼都失敗)

為什麼使用事務

​ 說白了就是為了讓這批次同時成功,或同時失敗(也就是有個後悔的時候)

什麼時候使用事務

場景一:如果實際的業務中,需要將一條資料同時存放到兩張表中, 並且要求兩張表中的資料同步,那麼此時就需要使用事務管理機制,保證資料同步。如果出現錯誤情況,比如表一插入資料成功,表二插入資料失敗,那麼就回滾,終止資料持久化操作。

場景二:金融行業的軟體開發嚴格重視事務處理,比如我們常見的轉賬操作,一方的賬戶金額減少,對應的是另一方的賬戶金額增加,這個過程需要使用到事務機制,不然轉賬不能成功

場景三:要求同一批次的提交需要一起成功,或一起失敗

這個寫的比較直白,做個備份:

Java中為什麼使用事務?什麼時候使用事務?如何使用事務? - Java精進之路 - 部落格園 (cnblogs.com)

spring的事務:

程式設計式事務:

指在程式碼中手動的管理事務的提交,回滾等操作。

優點:可以自己控制事務的範圍,適合非同步的情況(可以指定程式碼行)

缺點:程式碼侵入性比較高

宣告式事務:

是面向AOP切面的。將具體的業務和事務處理進行解耦,程式碼侵入性比較低。使用的比較普遍。

優點:耦合度低,使用簡單(一般使用@Transactional)

缺點:只能使用在類,介面和方法上。使用的顆粒度比較高。不適合使用存在有非同步呼叫的情況(介面不推薦使用這個)

@Transactional事務的失效

1. @Transactional 應用在非 public 修飾的方法上

​ 因為@Transactional 的工作原理是基於AOP來實現的,所以,必須作用在public的方法上才行

protectedprivate 修飾的方法上使用 @Transactional 註解,雖然事務無效,但不會有任何報錯

2.@Transactional 註解屬性 propagation 設定錯誤

  1. TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
  2. TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式執行,如果當前存在事務,則把當前事務掛起。
  3. TransactionDefinition.PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則丟擲異常

以上這三種配置,是會導致註解失效的

3.@Transactional 註解屬性 rollbackFor 設定錯誤

​ rollbackFor 指定回滾的情況。spring預設是回滾RuntimeException或這error才回滾。當然自定義的RuntimeException異常類也是可以的。

​ 如果希望spring能夠回滾別型別的異常,那就需要使用rollbackFor去指定(當然如果是指定異常的子類,也同樣會回滾

@Transactional(rollbackFor=Exception.class)

4. 同一個類中方法呼叫,導致@Transactional失效

​ 其實這還是由於使用Spring AOP代理造成的,因為只有當事務方法被當前類以外的程式碼呼叫時,才會由Spring生成的代理物件來管理

開發中避免不了會對同一個類裡面的方法呼叫,比如有一個類Test,它的一個方法A,A再呼叫本類的方法B(不論方法B是用public還是private修飾),但方法A沒有宣告註解事務,而B方法有。則外部呼叫方法A之後,方法B的事務是不會起作用的。這也是經常犯錯誤的一個地方

 public void A() throws Exception {
        /**
         * 呼叫B方法
         */
        this.B();
        ... ...
    }

    @Transactional()
    public void B() throws Exception {
          mapper.insert();
    }        

5.異常被你的 catch“吃了

​ 這個就比較簡單了,就是你自己捕捉到了異常,並且自己處理,並不會丟擲到上層的方法呼叫。那就不會生效了

try {
    nowDate.setTime(1623832800000L);
} catch (Exception e) {
    System.out.println(e.getMessage());
}

6.資料庫不支援事務

​ 如mysql的資料庫引擎,innodb支援事務,而myisam就不支援。

這裡備註一個寫的比較好的部落格:

@Transaction註解失效的幾種場景 - 1024。 - 部落格園 (cnblogs.com)