關於java同一個類互相調用,spring事務失效問題


記錄一次上線以后出現異常數據庫事務不會滾的情況

 

情況:接手別人祖傳代碼,代碼的邏輯 就是定時任務 中更新數據庫操作,在更新數據庫操作時候出現了異常,但是數據庫沒有回滾,導致的情況就是數據庫數據不一致了!!!

 

模擬當時代碼情況,定時任務是60s檢測更新一次,因為事務失效,導致添加了很多重復數據

 

@Service
public class TestTransactionService {

    @Autowired
    public TestTransactionMapper testTransactionMapper;


    @Scheduled(cron = "*/1 * * * * ?")
    public void callerMethod(){
        calledMethod();

    }

    @Transactional(rollbackFor = Exception.class)
    public void calledMethod(){

        //模擬.......很多表的更新添加等業務邏輯

        Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
        TestTransaction name = TestTransaction.builder()
                .name(integer + "次更新")
                .build();
        testTransactionMapper.insert(name);

        System.out.printf("更新成功:");

        System.out.printf(""+1/0);
    }
}

 

解決辦法:

1.最簡單的辦法就是在調用callerMethod() 上面 加入注解@Transactional(rollbackFor = Exception.class)

 

@Service
public class TestTransactionService {

    @Autowired
    public TestTransactionMapper testTransactionMapper;
    

    @Transactional(rollbackFor = Exception.class)
    @Scheduled(cron = "*/1 * * * * ?")
    public void callerMethod(){
        calledMethod();

    }

    @Transactional(rollbackFor = Exception.class)
    public void calledMethod(){

        //模擬.......很多表的更新添加等業務邏輯

        Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
        TestTransaction name = TestTransaction.builder()
                .name(integer + "次更新")
                .build();
        testTransactionMapper.insert(name);

        System.out.printf("更新成功:");

        System.out.printf(""+1/0);
    }
}

 

 

 

 

 

2.在當前類中注入自己代碼如下:

@Service
public class TestTransactionService {

    @Autowired
    public TestTransactionMapper testTransactionMapper;

    @Autowired
    public TestTransactionService testTransactionService;

    @Scheduled(cron = "*/1 * * * * ?")
    public void callerMethod(){
        testTransactionService.calledMethod();

    }

    @Transactional(rollbackFor = Exception.class)
    public void calledMethod(){

        //模擬.......很多表的更新添加等業務邏輯

        Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
        TestTransaction name = TestTransaction.builder()
                .name(integer + "次更新")
                .build();
        testTransactionMapper.insert(name);

        System.out.printf("更新成功:");

        System.out.printf(""+1/0);
    }
}

 

 

3.調用代理類的方式

 

@Service
public class TestTransactionService {

    @Autowired
    public TestTransactionMapper testTransactionMapper;


    @Transactional(rollbackFor = Exception.class)
    @Scheduled(cron = "*/1 * * * * ?")
    public void callerMethod(){
        TestTransactionService t=   (TestTransactionService) AopContext.currentProxy();

        t.calledMethod();
    }

    @Transactional(rollbackFor = Exception.class)
    public void calledMethod(){

        //模擬.......很多表的更新添加等業務邏輯

        Integer integer = testTransactionMapper.selectCount(new LambdaQueryWrapper<>());
        TestTransaction name = TestTransaction.builder()
                .name(integer + "次更新")
                .build();
        testTransactionMapper.insert(name);

        System.out.printf("更新成功:");

        System.out.printf(""+1/0);
    }
}

 記得還有一種方法是不需要在啟動類加的

如果啟動程序的時候報錯:Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.

需要在啟動類加上:@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)

 

 

4.將需要調用的方法,單獨寫到另一個Service中,在通過注入該Service進行調用

 

記錄這次線上的一次問題

在同一個類中 spring事務是AOP 動態代理實現,一個類中 方法調用是不走代理,只記錄問題 分析原因可以從事務的傳播機制,以及事務的實現方法着手!!!!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM