1. 程式人生 > 實用技巧 >Spring事務傳播行為REQUIRED,REQUIRES_NEW做實驗

Spring事務傳播行為REQUIRED,REQUIRES_NEW做實驗

  一直對REQUIRES_NEW心存疑惑,只是心裡知道概念,掛起當前的事務,同時建立新事務。今天我就做個實驗,看看外層是REQUIRED,內層是REQUIRES_NEW的場景下,幾種執行情況

  我們的程式碼如下

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addUser(User user) {
        
        userMapper.insert(user);
        addUserScore();
//        int t = 1/0;
        
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addUserScore() {
        
        UserScore score = new UserScore();
        score.setUserId("1234");
        score.setScore(50);
        userScoreMapper.insert(score);
//        int t = 1/0;
    }

  正常場景就不測了,沒必要。分別測試幾種異常場景。

  場景一:內層拋寫執行時異常,並且不進行捕獲

@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addUser(User user) {
        
        userMapper.insert(user);
        addUserScore();
//        int t = 1/0;
        
    }
 @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    
public void addUserScore() { UserScore score = new UserScore(); score.setUserId("1234"); score.setScore(50); userScoreMapper.insert(score); int t = 1/0; }

  結論一,兩個方法都不會插入資料,因為內層方法拋異常外層捕獲異常,spring會自動回滾。

  場景二:內層拋寫執行時異常,並且進行捕獲

 @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addUser(User user) {
        
        userMapper.insert(user);
        try {
            addUserScore();
        }catch(Exception e) {
            
        }
//        int t = 1/0;
        
    }
@Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addUserScore() {
        
        UserScore score = new UserScore();
        score.setUserId("1234");
        score.setScore(50);
        userScoreMapper.insert(score);
        int t = 1/0;
    }

  結論二:神奇的事情發生了,記憶體提交成功了,外層也成功了。這裡外層提交成功不難理解,難理解的是為啥內層也成功了。這個要等到分析spring原始碼才能知道了。

  場景三:外層拋異常

@Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void addUser(User user) {
        
        userMapper.insert(user);
        addUserScore();
        int t = 1/0;
        
    }
 @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addUserScore() {
        
        UserScore score = new UserScore();
        score.setUserId("1234");
        score.setScore(50);
        userScoreMapper.insert(score);
//        int t = 1/0;
    }

結論三:內層方法和外層方法都沒有提交成功

場景四:把內層的@Transactional(propagation = Propagation.REQUIRES_NEW)去掉,外層還拋異常

  從日誌來看,

DEBUG - Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b7d3a38] from current transaction
DEBUG - ==>  Preparing: insert into t_score (user_id, user_score) values (?, ?) 
DEBUG - ==> Parameters: 1234(String), 50(Integer)
DEBUG - <==    Updates: 1
DEBUG - {conn-10001, pstmt-20001} enter cache
DEBUG - Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b7d3a38]
DEBUG - Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b7d3a38]
DEBUG - Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b7d3a38]
DEBUG - Initiating transaction rollback
DEBUG - Rolling back JDBC transaction on Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@21ba0741]

如果不寫@Transactional,方法也是獲取當前的session,外層拋了異常,內層肯定也不會成功了。

  這裡面我最意外的是場景二,內層拋了異常,竟然內層也成功了。接下來我會好好分析spring原始碼,重點看看為啥外層try捕獲之後連內層都不回滾。