Spring事物失效場景

環境配置

模塊 版本
mysql 5.7.44
SpringBoot 2.1.3.RELEASE
Mybatis Plus 3.2.0
mysql-connector 8.0.28

    因爲現在這家公司我在測試的時候發現出現了事物失效的情況,雖然調用的方法鏈路上都有Translate註解,但是依舊會出現事物會滾異常的情況。所以我想研究一下,看看這個代碼到底是什麼原因導致的事物失效。給各位打個點,不是因爲方法內部調用導致的,本身方法內調用同類方法已經獨立啓動一個AopProxy。

事物失效的場景

1. 非public修飾的方法

        在Java中的訪問權限有四種,private、default、protected、public。非public方法修飾的方法,就算加上Translate註解,事物也不會生效。失效的原因是 在AbstractFallbackTransactionAttributeSource類的computeTransactionAttribute方法中有個判斷,如果目標方法不是public,則TransactionAttribute返回null,即不支持事務。

/**
 * 非public方法,Transactional註解失效,導致事物無效
 */
@Transactional
private void authTypeTranslateUnable(){
    mapper.insert(new TranslateTableA("a"));
    mapper.insert(new TranslateTableA("b"));

    // 數據庫中應該不存在這兩條數據
    throw new RuntimeException("拋出異常");
}

2. final修飾

        如果事物方法被final修飾,那麼事物就會無效。原因是final修飾的方法無法進行動態代理,導致Spring無法通過動態代理實現事物。

/**
 * final 修飾,Transactional註解失效,導致事物無效
 */
@Transactional
public final void finalTypeTranslateUnable(){
    mapper.insert(new TranslateTableA("a"));
    mapper.insert(new TranslateTableA("b"));

    // 數據庫中應該不存在這兩條數據
    throw new RuntimeException("拋出異常");
}

3. 方法內部調用

        當調用方法沒有開啓事物,而被調用方法開啓事物的時候,會導致被調用方的事物失效。同樣是動態代理的原因,動態代理已經加到日後更新中,各位期待一下。這裏簡單解釋一下爲什麼會失效,是因爲在調用方法(innerMethodTranslateUnable)中,Spring已經生成動態代理類,之後調用innerMethodTranslateUnableStep2的時候,是在代理類中直接調用方法,所以Spring的Aop不會生效,就導致事物沒有開啓。但是如果我們在innerMethodTranslateUnable方法上添加事物,那麼事物就會生效。

/**
 * 事物可以生效的情況
 */
@Transactional
public void innerMethodTranslateUnable(){
    this.innerMethodTranslateUnableStep2();
}

public void innerMethodTranslateUnableStep2(){
    mapper.insert(new TranslateTableA("innerMethodTranslateUnable-a"));
    throw new RuntimeException("拋出異常");
}

4. 未被Sping管理的Bean

        這個就沒啥好解釋的了,bean沒有被Spring管理,那你用Spring的事物註解,那肯定不行的。

5. 多線程調用方法導致事物失效

        因爲每一條線程獲取到的數據庫鏈接可能不一樣,因爲事物是針對一條數據庫連接的,同一個事物無法在多條連接中實現

/**
 * 多線程調用導致事物失效
 * 因爲每一條線程獲取到的數據庫鏈接可能不一樣,因爲事物是針對一條數據庫連接的,同一個事物無法在多條連接中實現
 */
@Transactional
public void multThreadTranslateUnable(){
    mapper.insert(new TranslateTableA("multThreadTranslateUnable-a"));
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();
    new Thread(() -> {
        threadComponent.saveInfo();
    }).start();

    throw new RuntimeException("拋出異常");
}

6.  異常不匹配或者異常被方法內部try cache

7.  方法設置了不支持事物

/**
 * 使用不開啓事物,執行sql
 */
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void errorTranslatePropagationTranslateUnable(){
    mapper.insert(new TranslateTableA("innerPrivateMethodTranslateUnable-3"));
}

8.  mysql的數據引擎不支持事物,例如MyISAM

爲啥業務代碼中事物不生效呢?我明天補一下,今天我要搞一下socket的內容

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章