@Transactional 註解下,事務失效的多種場景

威兰达發表於2024-06-07
package com.example.api.demo.boke;

import com.example.api.demo.config.exceptions.MyException;
import org.springframework.transaction.annotation.Transactional;

/**
 *  @Transactional
 *  註解下,事務失效的七種場景
 */
public class Transaction {

    /**
     * 1 異常被捕獲後沒有丟擲
     * 當異常被捕獲後,並且沒有再丟擲,那麼updateStudentA是不會回滾的。
     */
    @Transactional
    public void updateStudent() {
        this.updateStudentA();
        try {
            int i = 1 / 0;
            this.updateStudentB();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 2 丟擲非執行時異常
     * 非同步雖然丟擲了,但是丟擲的是非RuntimeException型別的異常,依舊不會生效。
     */
    @Transactional
    public void updateStudent2() throws MyException{
        this.updateStudentA();
        try {
            int i = 1 / 0;
            this.updateStudentB();
        } catch (Exception e) {
            throw new MyException();
        }
    }

    /**
     * 3 方法內部直接呼叫
     * 如果先呼叫updateStudent3(),那麼updateStudent3()是不會回滾的,其原因就是@Transactional根本沒生成代理,
     */
    public void updateStudent3() throws MyException{
        updateStudentG();
    }
    @Transactional
    public void updateStudentG() throws MyException{
        this.updateStudentA();
        int i = 1 / 0;
    }

    /**
     * 4 新開啟一個執行緒
     * 如下的方式updateStudentA()也不會回滾,因為spring實現事務的原理是透過ThreadLocal把資料庫連線繫結到當前執行緒中,
     * 新開啟一個執行緒獲取到的連線就不是同一個了。
     */
    @Transactional
    public void updateStudent4() throws MyException{
        this.updateStudentA();
        try {
            Thread.sleep(1000); //休眠1秒,保證updateStudentA先執行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(() -> {
            int i = 1/0;
        }).start();
    }

    /**
     * 5 註解到private方法上
     * idea直接會給出提示Methods annotated with ‘@Transactional’ must be overridable ,原理很簡單,private修飾的方式,spring無法生成動態代理。
     */
    @Transactional
    private void updateStudent5() throws MyException {
        this.updateStudentA();
        int i = 1/0;
    }

    /**
     * 6、 據庫本身不支援: mysql資料庫,必須設定資料庫引擎為InnoDB。
     * 7、 事務傳播屬性設定錯誤, 比如設定了:PROPAGATION_NOT_SUPPORIED(以非事務的方式執行,如果當前有事務則把當前事務掛起)
     * 8、 事務方法被final、static修飾
     * 9、 當前類沒有被Spring管理
     */


    private void updateStudentB() {
        System.out.println();
    }

    private void updateStudentA() {
        System.out.println();
    }


}

相關文章