Spring事務傳播行為REQUIRED,REQUIRES_NEW做實驗
阿新 • • 發佈:2020-10-26
一直對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捕獲之後連內層都不回滾。