<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Spring 事務註解 @Transactional 本來可以保證原子性,如果事務內有報錯的話,整個事務可以保證回滾,但是加上try catch或者事務巢狀,可能會導致事務回滾失敗。測試一波。
建兩張表,模擬兩個資料操作
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT NULL, `age` smallint(3) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT, `role_name` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
根據排列組合原理,我們進行四種測試:1、無try catch、無巢狀;2、有try catch、無巢狀;3、無try catch、有巢狀;4、都有。
如果我們單純@Transactional,事務可以正常回滾嗎?
@GetMapping("/saveNormal0") @Transactional public void saveNormal0() throws Exception { int age = random.nextInt(100); User user = new User().setAge(age).setName("name:"+age); userService.save(user); throw new RuntimeException(); }
如果事務內報了RuntimeException錯誤,事務可以回滾。
@GetMapping("/saveNormal0") @Transactional public void saveNormal0() throws Exception { int age = random.nextInt(100); User user = new User().setAge(age).setName("name:"+age); userService.save(user); throw new Exception(); }
如果事務內報了Exception錯誤(非RuntimeException錯誤),事務不可以回滾。
@GetMapping("/saveNormal0") @Transactional( rollbackFor = Exception.class) public void saveNormal0() throws Exception { int age = random.nextInt(100); User user = new User().setAge(age).setName("name:"+age); userService.save(user); throw new Exception(); }
如果是Exception錯誤(非RuntimeException),加上 rollbackFor = Exception.class 引數也可以實現回滾。
結論一:對於@Transactional可以保證RuntimeException錯誤的回滾,如果想保證非RuntimeException錯誤的回滾,需要加上rollbackFor = Exception.class 引數。
經過博主多種情況測試,發現try catch對回滾這個事本身沒有什麼影響,結論一照樣成立。try catch只是對異常是否可以被@Transactional 感知 到有影響。如果錯誤拋到切面可以感知到的地步,那就可以起作用。
@GetMapping("/saveTryCatch") @Transactional( rollbackFor = Exception.class) public void saveTryCatch() throws Exception{ try{ int age = random.nextInt(100); User user = new User().setAge(age).setName("name:"+age); userService.save(user); throw new Exception(); }catch (Exception e){ throw e; } }
比如上面一段程式碼就回滾了。
@GetMapping("/saveTryCatch") @Transactional( rollbackFor = Exception.class) public void saveTryCatch() throws Exception{ try{ int age = random.nextInt(100); User user = new User().setAge(age).setName("name:"+age); userService.save(user); throw new Exception(); }catch (Exception e){ } }
然而,將catch中的錯誤不繼續網上拋,切面無法感知到錯誤,無法進行處理,那麼事務就無法回滾了。
結論二:
try catch只是對異常是否可以被@Transactional 感知 到有影響。如果錯誤拋到切面可以感知到的地步,那就可以起作用。
首先經過實驗,結論一仍然成立,即,當不加上rollbackFor = Exception.class 的時候,無論內外報RuntimeException,都會回滾;無論內外報 非RuntimeException 錯誤,都不會回滾。如果加上rollbackFor = Exception.class,無論內外怎麼報錯,都會回滾。這些程式碼就不給出了
接下來,試下下面兩種情況:
@GetMapping("/out") @Transactional( rollbackFor = Exception.class) public void out() throws Exception{ innerService.inner(); int age = random.nextInt(100); User user = new User().setAge(age).setName("name:" + age); userService.save(user); throw new Exception(); } @Transactional public void inner() throws Exception{ Role role = new Role(); role.setRoleName("roleName:"+new Random().nextInt(100)); roleService.save(role); // throw new Exception(); }
情況一,外面事務加上rollbackFor = Exception.class,裡面事務不加,測試內外分別報錯的情況(為了簡化程式碼量,只給出了外面報錯的程式碼),都可以回滾。因為,無論如何,錯誤都拋給了外面那個事務進行處理,而外面那個加上了rollbackFor = Exception.class,具備處理非RuntimeException錯誤的能力,所以都可以讓事務進行正常回滾。
下面看情況二,裡面的事務加上rollbackFor = Exception.class,外面不加,外面報錯。
@GetMapping("/out") @Transactional public void out() throws Exception{ innerService.inner(); int age = random.nextInt(100); User user = new User().setAge(age).setName("name:" + age); userService.save(user); throw new Exception(); } @Transactional( rollbackFor = Exception.class) public void inner() throws Exception{ Role role = new Role(); role.setRoleName("roleName:"+new Random().nextInt(100)); roleService.save(role); }
事務都無法回滾,這是我們有個疑問,裡面的事務明明有很強的處理能力啊,為什麼和外面一起回滾失敗呢,彆著急,等等聊這個。
然後試下里面報錯:
@GetMapping("/out") @Transactional public void out() throws Exception{ innerService.inner(); int age = random.nextInt(100); User user = new User().setAge(age).setName("name:" + age); userService.save(user); } @Transactional( rollbackFor = Exception.class) public void inner() throws Exception{ Role role = new Role(); role.setRoleName("roleName:"+new Random().nextInt(100)); roleService.save(role); throw new Exception(); }
咦,這回都進行了正常的回滾。我的天,這回外面沒有處理能力,為什麼接受裡面丟擲來的錯誤,也進行了回滾!!!看上去,就好像裡外事務總是同生共死的對不對?原來,@Transactional還有個引數,看下原始碼,這個註解還有預設值:
Propagation propagation() default Propagation.REQUIRED;
REQUIRED的意思是說,事務巢狀的時候,如果發現已經有事務存在了,就加入這個事務,而不是新建一個事務,所以根本就不存在兩個事務,一直只有一個!至於,此引數其他值,本文不進行測試。回到上面的問題,當外面報錯的時候,此時檢視事務,沒有增加rollbackFor = Exception.class引數,即沒有處理非RuntimeException能力,所以程式碼走完,貌似“兩個事務”,都回滾失敗了。當裡面報錯的時候,事務已經新增上了處理非RuntimeException能力,所以,程式碼走完就回滾成功了。
結論三:由於REQUIRED屬性,“兩個事務”其實是一個事務,處理能力看報錯時刻,是否新增了處理非RuntimeException的能力。
在結論一二三成立的條件下,探索共同影響的問題就簡單多了,由於情況太多,就不進行過多的程式碼展示了。
結論一:對於@Transactional可以保證RuntimeException錯誤的回滾,如果想保證非RuntimeException錯誤的回滾,需要加上rollbackFor = Exception.class 引數。
結論二:try catch只是對異常是否可以被@Transactional 感知 到有影響。如果錯誤拋到切面可以感知到的地步,那就可以起作用。
結論三:由於REQUIRED屬性,“兩個事務”其實是一個事務,處理能力看報錯時刻,是否新增了處理非RuntimeException的能力。
到此這篇關於Java 事務註解@Transactional回滾(try catch、巢狀)問題的文章就介紹到這了,更多相關Java @Transactional回滾 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45