關于Spring中@Transactional事務回滾的注意事項
一、Spring 默認事務
Spring中 @Transactional
注解,默認情況下,只對拋出的 RuntimeException
異常,才會事務回滾。
如果事務的方法中拋出 unchecked異常(RuntimeException),事務會進行回滾( rollback);如果事務的方法中拋出是 checked異常(Exception),事務不會回滾。
也就是說,默認情況下, @Transactional
注解 只對拋出的 RuntimeException
異常和其子類異常 才有效,對 Exception 及 Exception 的子類異常無效。
偽代碼說明
// @Transactional 默認就是 RuntimeException 有效,拋出 RuntimeException時,事務會回滾。 @Transactional public void methodName1() { //... 各種的業(yè)務邏輯省略 throw new RuntimeException("RuntimeException"); } // @Transactional 默認就是 RuntimeException 有效,拋出 Exception 時,事務不會回滾。 @Transactional public void methodName22() { //... 各種的業(yè)務邏輯省略 throw new Exception("Exception"); } // @Transactional 指定回滾事務是 Exception時,遇到 RuntimeException 時,事務不會回滾 @Transactional( rollbackFor=Exception.class ) public void methodName3() { //... 各種的業(yè)務邏輯省略 throw new RuntimeException("RuntimeException"); } // @Transactional 指定回滾事務是 Exception時,遇到異常 Exception 時,事務會回滾, @Transactional( rollbackFor=Exception.class ) public void methodName4() { //... 各種的業(yè)務邏輯省略 throw new Exception("Exception"); }
@Transactional
相當于 @Transactional(rollbackFor=RuntimeException.class)
,只對拋出的 RuntimeException
異常,才會事務回滾。
1.1、拋出 unchecked 和 checked 異常都回滾
如果希望無論拋出是 RuntimeException (unchecked ) ,還是 Exception (checked),事務都要回滾。
@Transactional( rollbackFor = {RuntimeException.class, Exception.class} ) public void methodName5() { //... 業(yè)務省略 if(){ throw new RuntimeException("RuntimeException"); } //... 業(yè)務省略 if(){ throw new Exception("Exception"); } }
1.2、總結
- Spring 中
@Transactional
,默認只對拋出的RuntimeException
的出常,事務才會回滾。 - 如果希望無論拋出是 RuntimeException ,還是 Exception,事務都要回滾,請使用如下配置。
@Transactional(rollbackFor={RuntimeException.class, Exception.class})
二、使用 Spring中 @Transactional 注解的注意事項
@Transactional
注解只能應用到public
的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯, 但是這個被注解的方法將不會展示已配置的事務設置。- 配置
proxy-target-class
是指定基于接口的,還是基于類的代理被創(chuàng)建。如果proxy-target-class
=false
(默認值),那么標準的JDK基于接口的代理。 如果proxy-target-class
=true
,那么基于類的代理將起作用(需要CGLIB庫)。 @Transactional
注解 加在 具體方法(或類)上面 ,而不是接口上面。 在接口上使用 @Transactional 注解,只能當你設置了基于接口的代理時它才生效。 因為注解是 不能繼承 的,這就意味著如果正在使用基于類的代理時,那么事務的設置將不能被基于類的代理所識別,而且對象也將不會被事務代理所包裝。@Transactional
的事務是通過基于接口的,或者是基于類的代理才能被創(chuàng)建。在同一個類中一個方法調用另一個有事務注解的方法,事務是不會起作用的。
這條能理解嗎 ?下面是解釋說明。
偽代碼說明
@Serive public class XxxService{ public void aa(){ //業(yè)務... bb() //業(yè)務... } @Transactional public void bb(){ //業(yè)務... } } @Controller public class XxxController(){ @Autowired XxxService xxxService; @RquestMapping("/hello") public void hello(){ xxxService.aa(); } } XxxController.hello() 調用 XxxService 時,沒有開啟事務,在 aa()、 bb()發(fā)生的RuntimerException 不會事務回滾。 分析說明: (1)因為 aa() 沒有 @Transactional 注解,因此 XxxController 調用 XxxService 時 ,沒有開啟事務; (2)aa()中調有 bb() 只是方法的調用(代碼片段的調用)。類似于Thread中,開啟線程是通過start()方法,而不是直接調用run()方法。
spring 在掃描bean的時候會掃描方法上是否包含@Transactional
事務注解,如果包含,則 spring會為這個bean動態(tài)地生成一個子類(即代理類,proxy),代理類是繼承原來那個bean 。
當這個有事務注解的方法被調用的時候,實際上是由代理類來調用的,代理類在調用之前就會開啟事務(transaction
) 。
但是,如果先調用一個沒有事務的方法,然通這個方法再去有事務,由于該方法的調用并沒有通過代理類,而是直接通過原來的那個bean,所以就不會啟動transaction,我們看到的現象就是 @Transactional
注解無效。
總結: 同一個類中,一個沒有事務的方法A,去調用另一個有事務的方法B時,因為是直接調用,而不是調用的代理類,所以事務不起用的。
到此這篇關于關于Spring中@Transactional事務回滾的注意事項的文章就介紹到這了,更多相關Spring中@Transactional事務回滾內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
簡單了解SpringMVC緩存對靜態(tài)資源有什么影響
這篇文章主要介紹了簡單了解SpringMVC緩存對靜態(tài)資源有什么影響,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09SpringBoot整合redis+Aop防止重復提交的實現
Spring Boot通過AOP可以實現防止表單重復提交,本文主要介紹了SpringBoot整合redis+Aop防止重復提交的實現,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-07-07