Spring中的事務提交事件

大卫小东(Sheldon)發表於2024-10-18

如果想在spring操作事務結束後執行一些程式碼,應該怎麼辦?

為什麼要這樣?比如我們在事務中給其他系統發了訊息,期望事務提交後過一會收到這個系統的回應,然後操作剛剛提交的資料。但是如果回應來的太快就像龍捲風,我們的事務是託管給Spring的可能還沒提交,也就沒法操作了

一個方案是使用 ApplicationEventPublisher,可以參考我之前的千萬訪問量部落格
https://www.iteye.com/blog/somefuture-2405963

登陸訪問量是100多萬,我就假設總訪問量是10倍吧哈哈
image

這個API是 Spring 1 就提供的,從 Spring 5 開始,提供了一個新的事物相關的API,叫 TransactionSynchronization 事物同步機制。

上程式碼

先編寫一個Bean實TransactionSynchronization介面

import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.stereotype.Component;

@Component
public class AfterTransactionCommitExecutor implements TransactionSynchronization {

    @Override
    public void afterCommit() {
        // 事務提交後執行的操作
        System.out.println("事務已提交,執行後續操作");
    }

    // 其他需要重寫的方法...

    public void registerSynchronization() {
        // 註冊當前例項到事務同步管理器
        TransactionSynchronizationManager.registerSynchronization(this);
    }
}

然後,你可以在服務層或者合適的地方呼叫registerSynchronization()方法來註冊事務同步回撥

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class SomeService {

    @Autowired
    private AfterTransactionCommitExecutor afterTransactionCommitExecutor;

    @Transactional
    public void doWork() {
        // 業務邏輯...

        // 註冊事務同步回撥
        afterTransactionCommitExecutor.registerSynchronization();
    }
}

基本上使用它還是為了運算元據,所以需要把引數傳給他。

一 成員變數

最簡單的就是加一個成員屬性。

@Component
public class AfterTransactionCommitExecutor extends TransactionSynchronizationAdapter {

    private Object parameter;

    @Override
    public void afterCommit() {
        // 事務提交後使用引數執行操作
        doSomethingWithParameter(parameter);
    }

    public void setParameter(Object parameter) {
        this.parameter = parameter;
    }

    private void doSomethingWithParameter(Object parameter) {
    }

    public void registerSynchronization() {
        TransactionSynchronizationManager.registerSynchronization(this);
    }
}
@Service
public class SomeService {

    @Autowired
    private AfterTransactionCommitExecutor afterTransactionCommitExecutor;

    @Transactional
    public void doWork(Object parameter) {
        // 設定引數
        afterTransactionCommitExecutor.setParameter(parameter);
        // 註冊事務同步回撥
        afterTransactionCommitExecutor.registerSynchronization();
    }
}

二 每次建立匿名類物件

@Service
public class SomeService {

    @Transactional
    public void doWork(final Object parameter) {
        // 業務邏輯...

        // 註冊事務同步回撥並傳遞引數
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
            @Override
            public void afterCommit() {
                doSomethingWithParameter(parameter);
            }
        });
    }

    private void doSomethingWithParameter(Object parameter) {
        // 使用引數執行相關操作
    }
}

注意,在使用成員變數傳遞引數時,如果多個事務併發執行,可能會存線上程安全問題。為了避免這個問題,可以使用ThreadLocal來儲存引數,或者在事務方法中每次都建立一個新的TransactionSynchronization例項。

相關文章