Spring事務@Transactional標籤深刻學習

事務管理是應用系統開發中必不可少的一部分.Spring爲事務管理提供了豐富的功能支持.Spring事務管理分爲編碼式和聲明式spring

兩種方式.編碼式事務指的是經過編碼方式實現事務;聲明式事務基於AOP,將具體業務邏輯與事務處理解耦.聲明式事務管理使框架

業務代碼邏輯不受污染,所以在實際使用中聲明式事務用的比較多.聲明式事務有兩種方式,一種是在配置文件(xml)中作相關事務ui

規則聲明,另外一種是基於@Transactional註解的方式.註解配置是目前流行的使用方式,所以下面將着重介紹基於@Transactionalthis

註解的事務管理.編碼

@Transactional註解管理事務的實現步驟spa

使用@Transactional註解管理事務的實現步驟分爲兩步.第一步,在xml配置文件中添加以下事務配置信息代理

<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

也能夠經過@EnableTransactionManagement註解也能夠啓用事務管理功能.code

第二步,將@Transactional註解添加到合適的方法上,並配置合適的屬性信息. @Transactional註解的屬性說明以下:orm

屬性名 說明
name 當在配置文件中有多個TransactionManager,可使用該屬性指定選擇哪一個事務管理器.
propagation 事務的傳播行爲,默認值REQUIRED.
isolation 事務的隔離度,默認值採用DEFAULT
timeout 事務的超時時間,默認值爲-1.若是超過該時間限制但事務尚未完成,則自動回滾事務.
read-only 指定事務是否爲只讀事務,默認值爲false;爲了忽略那些不須要事務的方法,好比讀取數據,能夠設置read-only爲true.
rollbackFor 用於指定可以觸發事務回滾的異常類型,若是有多個異常類型須要指定,各種型之間能夠經過逗號分隔.
no-rollback-for 拋出no-rollback-for指定的異常類型,不回滾事務.

除此之外,@Transactional註解也能夠添加到類級別上.當把@Transactional註解放到類級別時,表示全部該類的公共方法都配置xml

相同的事務屬性.當類級別配置了@Transactional,方法級別也配置了@Transactional,應用程序會以方法級別的事務屬性信息來

管理事務,方法級別的事務屬性信息會覆蓋類級別的相關配置信息.

Spring的註解方式事務實現機制

在應用系統調用聲明@Transactional的目標方法時,Spring Framework默認使用AOP代理,在代碼運行時生成一個代理對象,根據

@Transactional的屬性配置信息,這個代理對象決定該聲明@Transactional的目標方法是否由攔截器TransactionInterceptor來

使用攔截,在TransactionInterceptor攔截時,會在目標方法開始執行以前建立並加入事務,並執行目標方法的邏輯,最後根據執行

狀況是否出現異常,利用抽象事務管理器AbstractPlatformTransactionManager操做數據源DataSource提交或回滾事務.以下圖

所示:

image001

Spring AOP代理有CglibAopProxy和JdkDynamicAopProxy兩種,對於CglibAopProxy,須要調用其內部類的DynamicAdviseInterceptor

的intercept方法.對於JdkDynamicAopProxy,須要調用invoke方法.

正如上文提到的,事務管理的框架是由抽象事務管理器(AbstractPlatformTransactionManager)來提供的,而具體的底層事務處理實現,由

PlatformTransactionManager的具體實現類來實現,如事務管理器DataSourceTransactionManager管理JDBC的Connection.其類結構:


image002

在使用註解方式的事務使用注意事項

正確設置@Transactional的propagation屬性

須要注意下面三種propagation能夠不啓動事務,原本指望目標方法進行事務管理,但如果錯誤的配置這三種propagation,事務將

不會發生回滾.

  1. TransactionDefinition.PROPAGATION_SUPPORTS:若是當前存在事務,則加入該事務;若是當前沒有事務,則以非事務的方式繼續運行.
  2. TransactionDefinition.PROPAGATION_NOT_SUPPORTS:以非事務方式運行,若是當前存在事務,則把當前事務掛起.
  3. TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,若是當前存在事務,則拋出異常.

正確設置@Transactional的rollbackFor屬性

默認狀況下,若是在事務中拋出了未檢查異常(繼承自RuntimeException的異常)或者Error,則Spring將回滾事務;除此以外,Spring不會

回滾事務.若是在事務中拋出其餘類型的異常,並指望Spring可以回滾事務,能夠指定rollbackFor.經過分析Spring源碼能夠知道,若在目標

方法中拋出的異常時rollbackFor指定異常的子類,事務一樣會回滾 .RollbackRuleAttribute的getDepth方法:

private int getDepth(Class<?> exceptionClass, int depth) { if (exceptionClass.getName().contains(this.exceptionName)) { // Found it!
            return depth; } // If we've gone as far as we can go and haven't found it...
        if (exceptionClass == Throwable.class) { return -1; } return getDepth(exceptionClass.getSuperclass(), depth + 1); }

@Transactional只能應用到public方法纔有效

只有@Transactional註解應用到public方法,才能進行事務管理.這是由於在使用Spring AOP代理時,Spring在使用TransactionInterceptor攔截

目標方法執行先後時,DynamicAdvisedInterceptor(CglibAopProxy 的內部類)的的 intercept 方法或 JdkDynamicAopProxy 的 invoke 方法會間接調用

AbstractFallbackTransactionAttributeSource(Spring 經過這個類獲取表 1. @Transactional 註解的事務屬性配置屬性信息)的 computeTransactionAttribute

方法。

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

這個方法會檢查目標方法的修飾符是否是public,若不是public,就不會獲取@Transactional的屬性配置信息,最終會形成不會用TransactionInterceptor來攔截該

目標方法進行事務管理.

避免Spring的AOP的自調用問題

在Spring的AOP代理下,只有目標方法由外部調用,目標方法才由Spring生成的代理對象來管理,這會形成自調用問題.若同一類中的其餘沒有@Transactional註解

的方法內部調用有@Transactional註解的方法,有@Transactional註解的方法的事務被忽略,不會發生回滾.

可使用AspectJ替代Spring AOP代理解決這兩個問題(public與自調用問題).

------------引自他人博客

相關文章
相關標籤/搜索