摘要:事務嵌套影響首先經過實驗,結論一仍然成立,即,當不加上的時候,無論內外報,都會回滾無論內外報非錯誤,都不會回滾。結論結論一對于可以保證錯誤的回滾,如果想保證非錯誤的回滾,需要加上參數。
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對回滾這個事本身沒有什么影響,結論一照樣成立。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的能力。
try catch和事務嵌套 共同影響在結論一二三成立的條件下,探索共同影響的問題就簡單多了,由于情況太多,就不進行過多的代碼展示了。
結論結論一:對于@Transactional可以保證RuntimeException錯誤的回滾,如果想保證非RuntimeException錯誤的回滾,需要加上rollbackFor = Exception.class 參數。
結論二:try catch只是對異常是否可以被@Transactional 感知 到有影響。如果錯誤拋到切面可以感知到的地步,那就可以起作用。
結論三:由于REQUIRED屬性,“兩個事務”其實是一個事務,處理能力看報錯時刻,是否添加了處理非RuntimeException的能力。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/74647.html
摘要:否則事務不起作用。第二種情況同一個類中方法嵌套方法方法有,方法內都沒有,事務起作用。總結要想事務起作用,必須是主方法名上有注解,方法體內不能用如果用,則中必須用注解應該只被應用到方法上,不要用在等方法上,即使用了也將被忽略,不起作用。 代碼方法示例 @Transactional public void saveAA() { ????try { ...
摘要:前言在接口中規定了種類型的事務傳播行為。事務傳播行為是框架獨有的事務增強特性,他不屬于的事務實際提供方數據庫行為。本文對七種事務傳播行為做詳細介紹,內容主要代碼示例的方式呈現。 前言 Spring在TransactionDefinition接口中規定了7種類型的事務傳播行為。事務傳播行為是Spring框架獨有的事務增強特性,他不屬于的事務實際提供方數據庫行為。這是Spring為我們提供...
摘要:使用需要使用作為事務管理器。兩個事務互不影響。這是默認的隔離級別,使用數據庫默認的事務隔離級別下邊的四個與的隔離級別相對應這是事務最低的隔離級別,它充許另外一個事務可以看到這個事務未提交的數據。這種事務隔離級別可 Spring事務整理 工作了幾年了,今天抽時間整理一下spring的事務,說起spring的事務是面試的時候面試官經常提及的問題,接下來結合網上資料再總結下spring的事務...
摘要:引言對于追求數據強一致性的系統,事務扮演者十分重要的角色最近在項目中遇到一個事務失效的問題,在此分享給大家。情景回放問題分析初步分析這是事務獲取鎖超時導致的錯誤,奇怪的是拋出異常但是事務沒有回滾。唯一的解釋是事務失效了。 引言 對于追求數據強一致性的系統,事務扮演者十分重要的角色.最近在項目中遇到一個事務失效的問題,在此分享給大家。 情景回放 ### Cause: com.mysql....
摘要:在嵌套事務場景中,內層事務的和外層事務的會在外層事務結束時進行提交或回滾。解決方案如果希望內層事務拋出異常時中斷程序執行,直接在外層事務的代碼塊中拋出如果希望程序正常執行完畢,并且希望外層事務結束時全部提交,需要在內層事務中做異常捕獲處理。 前言 最近在項目中發現了一則報錯:org.springframework.transaction.UnexpectedRollbackExcept...
閱讀 1906·2021-11-22 14:44
閱讀 1672·2021-11-02 14:46
閱讀 3657·2021-10-13 09:40
閱讀 2601·2021-09-07 09:58
閱讀 1586·2021-09-03 10:28
閱讀 1658·2019-08-29 15:30
閱讀 976·2019-08-29 15:28
閱讀 1469·2019-08-26 12:20