sping事務失效的幾種場景


一.數據庫引擎不支持事務

spring的事務需要底層數據庫引擎的支持

這里以 MySQL 為例,其 MyISAM 引擎是不支持事務操作的,InnoDB 才是支持事務的引擎,一般要支持事務都會使用 InnoDB。

根據 MySQL 的官方文檔:

http://dev.mysql.com/doc/refman/5.6/en/storage-engines.html

從 MySQL 5.5.5 開始的默認存儲引擎是:InnoDB,之前默認的都是:MyISAM,所以這點要值得注意,底層引擎不支持事務再怎么搞都是白搭。

MySQL的幾種引擎可以了解 https://www.cnblogs.com/zluckiy/p/13793799.html

二.在非public修飾的方法使用

以下來自 Spring 官方文檔:

When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

大概意思就是 @Transactional 只能用於 public 的方法上,否則事務不會失效,如果要用在非 public 方法上,可以開啟 AspectJ 代理模式。

代碼中解釋:

@Transactional注解使用的是AOP,在使用動態代理的時候只能針對public方法進行代理,源碼依據在AbstractFallbackTransactionAttributeSource類中的computeTransactionAttribute方法中,如下:

1 protected TransactionAttribute computeTransactionAttribute(Method method,
2     Class<?> targetClass) {
3         // Don't allow no-public methods as required.
4         if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
5         return null;
6 }

此處如果不是標注在public修飾的方法上並不會拋出異常,但是會導致事務失效。

三.在try.catch代碼段中,沒有將異常拋出,導致事務無法回滾

1 @Transactional
2 public void method(){
3   try{//錯誤不會回滾
4     //插入一條數據
5     //更改一條數據
6   }catch(Exception ex){
7     return;
8   }
9 }

四.拋出的異常類型不對,默認為運行時異常RuntimeException

1 @Transactional
2 public void method(){
3   try{
4     //插入一條數據
5     //更改一條數據
6   }catch(Exception ex){
7     return;
8   }
9 }

這樣事務也是不生效的,因為默認回滾的是:RuntimeException,如果你想觸發其他異常的回滾,需要在注解上配置一下,如:

 1 @Transactional(rollbackFor = Exception.class)                                                                                                                             

五.方法中調用同類的方法

 1 public class Test{
 2   public void A(){
 3     //插入一條數據
 4     //調用B方法
 5     B();
 6   }
 7   
 8   @Transactional
 9   public void B(){
10     //插入數據
11   }
12 }

簡單的說就是一個類中的A方法(未標注聲明式事務)在內部調用了B方法(標注了聲明式事務),這樣會導致B方法中的事務失效。

為什么會失效呢?:其實原因很簡單,Spring在掃描Bean的時候會自動為標注了@Transactional注解的類生成一個代理類(proxy),當有注解的方法被調用的時候,實際上是代理類調用的,代理類在調用之前會開啟事務,執行事務的操作,但是同類中的方法互相調用,相當於this.B(),此時的B方法並非是代理類調用,而是直接通過原有的Bean直接調用,所以注解會失效。

六.配置錯誤導致事務失效

1.Propagation傳播行為配置錯誤

spring默認的事務傳播屬性是Propagation.REQUIRED,但是一旦配置了錯誤的傳播屬性,也是會導致事務失效,如下三種配置將會導致事務失效:

Propagation.SUPPORTS

Propagation.NOT_SUPPORTED

Propagation.NEVER

 

 

2代碼中我們一般通過spring管理,去實現事務,需要注意代碼塊有沒有被spring進行管理

3數據源沒有配置事務管理器等配置相關的問題導致

 

參考https://javastack.blog.csdn.net/article/details/103871083

  https://blog.csdn.net/qq_34162294/article/details/105803966


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM