1. 程式人生 > 其它 >Springboot @Transactional 事務不回滾

Springboot @Transactional 事務不回滾

一、異常捕獲的原因

  1. 這裡Exception異常,他又分為執行時異常RuntimeException和非執行時異常
  2. 可查的異常(checked exceptions):Exception下除了RuntimeException外的異常
  3. 不可查的異常(unchecked exceptions):RuntimeException及其子類和錯誤(Error)
  4. 異常checked例外也回滾:在整個方法前加上 @Transactional(rollbackFor=Exception.class)
  5. 異常unchecked例外不回滾: @Transactional(notRollbackFor=RunTimeException.class)
  6. 如果異常被try{}catch{}了,事務就不回滾了,如果想讓事務回滾必須再往外拋try{}catch{throw Exception}

二、資料庫引擎不支援回滾(使用MYSQL就很可能是這個原因)

  1. Mysql資料庫有兩種引擎,注意要使用支援事務的引擎,比如innodb,如果是MyISAM,事務是不起作用的。
  2. 使用springboot的jpa自動建立庫表的時候,預設使用MyISAM引擎,可以檢查庫表檢視引擎。
  3. 修改配置:
    spring:  
      jpa:
        hibernate:
          ddl-auto: update
          naming:
            physical
    -strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl #按欄位名字建表 show-sql: true database: mysql database-platform: org.hibernate.dialect.MySQL5InnoDBDialect #使用innodb引擎建表

三、發生了自呼叫情況

spring的資料庫事務呼叫的實現原理是AOP,而AOP的原理是動態代理,
在自呼叫的過程中,是類自身的呼叫,而不是代理物件去呼叫,那麼不會產生AOP,沒有AOP,意味著@Transactional不會被切面捕獲,
這樣spring就不能把你的程式碼植入到約定的流程中,於是就產生了事務回滾失敗。

解決方案:

1、將涉及到事務的處理都放入一個方法中,由其他類呼叫。

2、如果非要在本類中呼叫,那麼需要在本類中生成本類的bean物件,由這個bean物件來呼叫,實現方式也有多種:

  • 自注入
  • 通過SpringContextHolder獲取bean,即注入ApplicationContext,從ApplicationContext獲取bean
  • 通過AopContext獲取當前類的代理物件,注意此種方式需要開啟expose-proxy="true",可通過註解開啟@EnableAspectJAutoProxy(exposeProxy =true)

最後一種方式的虛擬碼:

@Service
public class OrderService {
 
  public void insert() {
 
    OrderService proxy = (OrderService) AopContext.currentProxy();
       proxy.insertOrder();
    }
 
    @Transactional
    public void insertOrder() {
        //SQL操作
       }
}
因為AopContext預設是不暴露當前代理類的,所以要@EnableAspectJAutoProxy(exposeProxy =true)
或者<aop:aspectj-autoproxy expose-proxy="true"/>:

四、補充:

在Spring 的AOP實現有兩種代理方式:

  • Java動態代理 :通過反射生成一個實現了代理方法的匿名類來完成代理
  • cglib代理 :通過Asm修改位元組碼檔案,生成一個子類來完成代理

Spring在專案中會根據被代理物件是否實現了介面來自動切換上述兩種代理方式

所以private方法也不能實現事務