一、場景再現
@Override @Transactional public void updateById(String userId,String username) throws Exception { sysUserDao.UpdatedById(userId,username); if (1==1) { throw new Exception("故意拋出測試..."); } sysUserDao.UpdatedById(userId,username+"final"); }
以上就是不起作用的代碼,經分析,問題就出在這段代碼中。(applicationContext.xml 是標准配置,相信你不會配錯)
二、問題分析
上述代碼日志打出來后,竟然發現出異常后,事務盡然是commit;
2017-04-07 09:42:16,746 DEBUG-> Creating a new SqlSession
2017-04-07 09:42:16,754 DEBUG-> Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27c35069]
2017-04-07 09:42:16,766 DEBUG-> JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@592f13f0] will be managed by Spring
2017-04-07 09:42:16,855 DEBUG-> Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27c35069]
2017-04-07 09:42:16,857 DEBUG-> Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27c35069]
2017-04-07 09:42:16,857 DEBUG-> Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27c35069]
2017-04-07 09:42:16,857 DEBUG-> Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@27c35069]
后來查看文檔發現這么一段
If no rules are relevant to the exception, it will be treated like DefaultTransactionAttribute
(rolling back on runtime exceptions).
理解為:默認情況下,事務遇到運行時異常會回滾;而非運行期異常,事務是不會回滾的。
三、解決辦法
解決辦法很簡單,告訴事務管理器,遇到非運行期異常,也同樣需要回滾。
@Override @Transactional(rollbackFor = {RuntimeException.class,Exception.class}) public void updateById(String userId,String username) throws Exception { sysUserDao.UpdatedById(userId,username); if (1==1) { throw new Exception("故意拋出測試..."); } sysUserDao.UpdatedById(userId,username+"final"); }
題外話:園子里可能很多還是奮戰在.net領域的同學,作為一個在一線開發+管理多年經驗的老鳥來看,同經驗同水平的.net員比java員薪水低20%,級別越高,差距越大,結論就是,如果你想在后端發展,能轉java盡早轉,不能轉創造條件轉,.net可以作為興趣來研究,java才是養家糊口的利器。