[解決] spring service 呼叫當前類方法事務不生效

suliver發表於2021-09-09

今天在測試框架的時候,我想在一個service類的方法中呼叫 當前類的另一個方法(該方法透過@Transactional開啟事務),這時候發現被呼叫類的事務並沒有生效。

    public boolean test1() {        // xxx 業務邏輯
        return test2();
    }    
    @Transactional
    public boolean test2() {
        testMapper.insertSalary("test", UUID.randomUUID().toString());        int a = 10/0;        return true;
    }

WHY? 搜尋引擎一番查詢之後,瞭解到問題的關鍵:
@Transactional 是基於aop生的代理物件開啟事務的
PS:不瞭解代理模式的小夥伴,結尾有傳送門

思路

1.spring 的事務是透過 aop 管理的
2.aop 會透過動態代理 為我們生成代理物件,aop 的功能(例如事務)都是在代理物件中實現的

  1. aop 生成的代理類又在 spring 容器中,所以我們只要在 spring 容器中拿到當前這個bean 再去呼叫 test2() 就可以開啟事務了。

解決
import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.stereotype.Component;/**
 * Spring的ApplicationContext的持有者,可以用靜態方法的方式獲取spring容器中的bean
 *
 */@Componentpublic class SpringContextHolder implements ApplicationContextAware {    private static ApplicationContext applicationContext;    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
    }    public static ApplicationContext getApplicationContext() {
        assertApplicationContext();        return applicationContext;
    }    @SuppressWarnings("unchecked")    public static <T> T getBean(String beanName) {
        assertApplicationContext();        return (T) applicationContext.getBean(beanName);
    }    public static <T> T getBean(Class<T> requiredType) {
        assertApplicationContext();        return applicationContext.getBean(requiredType);
    }    private static void assertApplicationContext() {        if (SpringContextHolder.applicationContext == null) {            throw new RuntimeException("applicaitonContext屬性為null,請檢查是否注入了SpringContextHolder!");
        }
    }

}
    public boolean test1() {        // xxx 業務邏輯
        // 在spring容器中 獲取當前類的代理類
        return SpringContextHolder.getBean(TestS.class).test2();
    }    
    @Transactional
    public boolean test2() {
        testMapper.insertSalary("test", UUID.randomUUID().toString());        int a = 10/0;        return true;
    }



作者:殷天文
連結:


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2370/viewspace-2815942/,如需轉載,請註明出處,否則將追究法律責任。

相關文章