事務管理是應用系統開發中必不可少的一部分.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提交或回滾事務.以下圖
所示:
Spring AOP代理有CglibAopProxy和JdkDynamicAopProxy兩種,對於CglibAopProxy,須要調用其內部類的DynamicAdviseInterceptor
的intercept方法.對於JdkDynamicAopProxy,須要調用invoke方法.
正如上文提到的,事務管理的框架是由抽象事務管理器(AbstractPlatformTransactionManager)來提供的,而具體的底層事務處理實現,由
PlatformTransactionManager的具體實現類來實現,如事務管理器DataSourceTransactionManager管理JDBC的Connection.其類結構:
在使用註解方式的事務使用注意事項
正確設置@Transactional的propagation屬性
須要注意下面三種propagation能夠不啓動事務,原本指望目標方法進行事務管理,但如果錯誤的配置這三種propagation,事務將
不會發生回滾.
正確設置@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與自調用問題).
------------引自他人博客