1. 程式人生 > 其它 >@Transactional事務失效的常見的場景

@Transactional事務失效的常見的場景

在《Spring Boot事務管理》中,小編介紹了註解@Transactional的基本屬性和使用方法,這裡介紹事務失效的八種場景,使大家對註解@Transactional有一個更深刻的認知。

  被註解修飾的方法為非public型別。之所以會失效,是因為在Spring AOP 代理中,TransactionInterceptor (事務攔截器)在目標方法執行前後進行攔截,DynamicAdvisedInterceptor(CglibAopProxy 的內部類)的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法會間接呼叫AbstractFallbackTransactionAttributeSource的 computeTransactionAttribute 方法,獲取Transactional 註解的事務配置資訊。

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

computeTransactionAttribute方法會檢查目標方法的修飾符是否為 public,不是 public則不會獲取@Transactional 的屬性配置資訊。

  異常被catch塊吃掉,導致回滾失敗。

  異常丟擲型別錯誤,例如屬性rollbackFor預設回滾的是RuntimeException,而程式碼丟擲了其父類的異常Exception,這時是不可以回滾的。如果丟擲了RuntimeException的子類異常,如NullPointerException,則可以回滾。

  本類方法直接呼叫。比如有一個類Test,它裡面有兩個方法,方法A沒有宣告註解事務,而public型別的B方法有,而且是A呼叫了B。則外部呼叫方法A之後,方法B的事務是不會起作用的。此時會用this關鍵字直接請求B方法,沒有經過 Spring AOP的代理類去呼叫方法,從而沒有開啟事務管理,預設只有在外部呼叫事務才會生效。這也是經常犯錯誤的一個地方。

  Bean沒有被spring容器管理

  資料庫引擎不支援事務。以 MySQL 為例,其 MyISAM 引擎是不支援事務操作的,InnoDB 才支援,一般要支援事務都會使用 InnoDB。

  資料來源沒有配置事務管理器。實現介面方法,使得返回資料庫事務管理器:

@Bean 
PlatformTransactionManager transactionManager(DataSource dataSource) {
       return new DataSourceTransactionManager(dataSource);
}

  方法事務傳播行為設定不支援事務:propagation = Propagation.NOT_SUPPORTED or TransactionDefinition.PROPAGATION_NEVER。

TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。所以,在當前沒有事務的場景下使用此傳播行為屬性,則以非事務的方式繼續執行。

Reference

Spring事務失效的 8 大原因,這次可以吊打面試官了