Spring 声明事务中transactionAttributes属性 + - Exception 实现逻辑

下面是一段典型的spring 声明事务的配置:

  1. <bean id="userDAOProxy"  
  2.     class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">  
  3.     <property name="transactionManager">  
  4.         <ref bean="transactionManager" />  
  5.     </property>  
  6.     <property name="target">  
  7.         <ref local="userDAO" />  
  8.     </property>  
  9.     <property name="transactionAttributes">  
  10.         <props>  
  11.             <prop key="insert*">PROPAGATION_REQUIRED</prop>  
  12.             <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>  
  13.             <prop key="save*">PROPAGATION_REQUIRED,-ApplicationException,+BusinessException</prop>  
  14.         </props>  
  15.     </property>  
  16. </bean>  

在Spring声明事务中,我们可以自定义方法的哪些Exception需要回滚,哪些Exception可以直接提交。

通过下面的配置:

  1. <prop key="save*">PROPAGATION_REQUIRED,-ApplicationException,+BusinessException</prop>  

- 表示抛出该异常时需要回滚

+表示即使抛出该异常事务同样要提交

-ApplicationException :表示抛出ApplicationException 时,事务需要回滚。但不是说只抛出ApplicationException 异常时,事务才回滚,如果程序抛出RuntimeException和Error时,事务一样会回滚,即使这里没有配置。因为Spring中默认对所有的RuntimeException和Error都会回滚事务

Spring中是如何实现这段逻辑的:

调用的是

org.springframework.transaction.interceptor.RuleBasedTransactionAttribute.rollbackOn(Throwable ex)

  1. public boolean rollbackOn(Throwable ex) {  
  2.         if (logger.isTraceEnabled()) {  
  3.             logger.trace("Applying rules to determine whether transaction should rollback on " + ex);  
  4.         }  
  5.   
  6.         RollbackRuleAttribute winner = null;  
  7.         int deepest = Integer.MAX_VALUE;  
  8.   
  9.         //配置文件中的回滚异常列表,当然去掉了-,只有name,commit的规则是另外一个对象  
  10.         if (this.rollbackRules != null) {  
  11.             for (RollbackRuleAttribute rule : this.rollbackRules) {  
  12.                 //使用抛出exception的className(全路径className)进行indexOf match  
  13.                 //如果没有match上会继续搜索superClass name进行match,到Throwable class为止  
  14.                 int depth = rule.getDepth(ex);  
  15.                 if (depth >= 0 && depth < deepest) {  
  16.                     deepest = depth;  
  17.                     winner = rule;  
  18.                 }  
  19.             }  
  20.         }  
  21.   
  22.         if (logger.isTraceEnabled()) {  
  23.             logger.trace("Winning rollback rule is: " + winner);  
  24.         }  
  25.   
  26.         // User superclass behavior (rollback on unchecked) if no rule matches.  
  27.         if (winner == null) {  
  28.             logger.trace("No relevant rollback rule found: applying default rules");  
  29.             //如果没有match上,调用此方法继续match,判断instance of RuntimeException or Error  
  30.             return super.rollbackOn(ex);  
  31.         }  
  32.   
  33.         return !(winner instanceof NoRollbackRuleAttribute);  
  34.     }  

rule.getDepth方法代码

        因为使用的是className的全路径进行indexOf匹配,所以如果自定义异常是:com.abc.ApplicationException,你在xml配置文件中定义为:-abc,同样会match上,事务也会回滚,这一点需要注意。

       另外一点,如何在xml中定义的是-Exception,这样只要class的全路径中包含Exception字段,如包名,也会匹配上。

  1.        public int getDepth(Throwable ex) {  
  2.     return getDepth(ex.getClass(), 0);  
  3. }  
  4.   
  5.   
  6. private int getDepth(Class exceptionClass, int depth) {  
  7.     if (exceptionClass.getName().indexOf(this.exceptionName) != -1) {  
  8.         // Found it!  
  9.         return depth;  
  10.     }  
  11.     // If we've gone as far as we can go and haven't found it...  
  12.     if (exceptionClass.equals(Throwable.class)) {  
  13.         return -1;  
  14.     }  
  15.     return getDepth(exceptionClass.getSuperclass(), depth + 1);  
  16. }  

super.rollbackOn(Throwable ex ) 方法代码

很简单的一行代码,这就是为什么RuntimeException和Error也会回滚啦。

  1. public boolean rollbackOn(Throwable ex) {  
  2.         return (ex instanceof RuntimeException || ex instanceof Error);  
  3.     }  


几次测试输出的debug日志

  1. [08/24 03:35:39] [DEBUG] RuleBasedTransactionAttribute: Applying rules to determine whether transaction should rollback on usertest.exception.BusinessException: Error  
  2. [08/24 03:35:39] [DEBUG] RuleBasedTransactionAttribute: Winning rollback rule is: RollbackRuleAttribute with pattern [BusinessException]  
  3. [08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Triggering beforeCompletion synchronization  
  4. [08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Initiating transaction rollback  
  5. [08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2]  
  6. [08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Triggering afterCompletion synchronization  
  7. [08/24 03:35:39] [DEBUG] TransactionSynchronizationManager: Clearing transaction synchronization  
  8. [08/24 03:35:39] [DEBUG] TransactionSynchronizationManager: Removed value [org.springframework.jdbc.datasource.ConnectionHolder@1833eca] for key [org.apache.commons.dbcp.BasicDataSource@4aa0ce] from thread [main]  
  9. [08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2] after transaction  
  10. [08/24 03:35:39] [DEBUG] DataSourceUtils: Returning JDBC Connection to DataSource  
  11.   
  12.   
  13.   
  14.   
  15. [08/24 03:39:16] [DEBUG] TransactionInterceptor: Completing transaction for [usertest.dao.UsersDAO.testInsertAndUpdate] after exception: java.lang.Exception: Error  
  16. [08/24 03:39:16] [DEBUG] RuleBasedTransactionAttribute: Applying rules to determine whether transaction should rollback on java.lang.Exception: Error  
  17. [08/24 03:39:16] [DEBUG] RuleBasedTransactionAttribute: Winning rollback rule is: null  
  18. [08/24 03:39:16] [DEBUG] RuleBasedTransactionAttribute: No relevant rollback rule found: applying superclass default  
  19. [08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Triggering beforeCommit synchronization  
  20. [08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Triggering beforeCompletion synchronization  
  21. [08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Initiating transaction commit  
  22. [08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2]  
  23. [08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Triggering afterCommit synchronization  
  24.   
  25.   
  26. [08/24 03:41:40] [DEBUG] TransactionInterceptor: Completing transaction for [usertest.dao.UsersDAO.testInsertAndUpdate] after exception: usertest.exception.BusinessException: Error  
  27. [08/24 03:41:40] [DEBUG] RuleBasedTransactionAttribute: Applying rules to determine whether transaction should rollback on usertest.exception.BusinessException: Error  
  28. [08/24 03:41:40] [DEBUG] RuleBasedTransactionAttribute: Winning rollback rule is: RollbackRuleAttribute with pattern [Exception]  
  29. [08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Triggering beforeCompletion synchronization  
  30. [08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Initiating transaction rollback  
  31. [08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2]  
  32. [08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Triggering afterCompletion synchronization  
  33. [08/24 03:41:40] [DEBUG] TransactionSynchronizationManager: Clearing transaction synchronization  
[08/24 03:35:39] [DEBUG] RuleBasedTransactionAttribute: Applying rules to determine whether transaction should rollback on usertest.exception.BusinessException: Error
[08/24 03:35:39] [DEBUG] RuleBasedTransactionAttribute: Winning rollback rule is: RollbackRuleAttribute with pattern [BusinessException]
[08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Triggering beforeCompletion synchronization
[08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Initiating transaction rollback
[08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2]
[08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Triggering afterCompletion synchronization
[08/24 03:35:39] [DEBUG] TransactionSynchronizationManager: Clearing transaction synchronization
[08/24 03:35:39] [DEBUG] TransactionSynchronizationManager: Removed value [org.springframework.jdbc.datasource.ConnectionHolder@1833eca] for key [org.apache.commons.dbcp.BasicDataSource@4aa0ce] from thread [main]
[08/24 03:35:39] [DEBUG] DataSourceTransactionManager: Releasing JDBC Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2] after transaction
[08/24 03:35:39] [DEBUG] DataSourceUtils: Returning JDBC Connection to DataSource




[08/24 03:39:16] [DEBUG] TransactionInterceptor: Completing transaction for [usertest.dao.UsersDAO.testInsertAndUpdate] after exception: java.lang.Exception: Error
[08/24 03:39:16] [DEBUG] RuleBasedTransactionAttribute: Applying rules to determine whether transaction should rollback on java.lang.Exception: Error
[08/24 03:39:16] [DEBUG] RuleBasedTransactionAttribute: Winning rollback rule is: null
[08/24 03:39:16] [DEBUG] RuleBasedTransactionAttribute: No relevant rollback rule found: applying superclass default
[08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Triggering beforeCommit synchronization
[08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Triggering beforeCompletion synchronization
[08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Initiating transaction commit
[08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2]
[08/24 03:39:16] [DEBUG] DataSourceTransactionManager: Triggering afterCommit synchronization


[08/24 03:41:40] [DEBUG] TransactionInterceptor: Completing transaction for [usertest.dao.UsersDAO.testInsertAndUpdate] after exception: usertest.exception.BusinessException: Error
[08/24 03:41:40] [DEBUG] RuleBasedTransactionAttribute: Applying rules to determine whether transaction should rollback on usertest.exception.BusinessException: Error
[08/24 03:41:40] [DEBUG] RuleBasedTransactionAttribute: Winning rollback rule is: RollbackRuleAttribute with pattern [Exception]
[08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Triggering beforeCompletion synchronization
[08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Initiating transaction rollback
[08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Rolling back JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@1db05b2]
[08/24 03:41:40] [DEBUG] DataSourceTransactionManager: Triggering afterCompletion synchronization
[08/24 03:41:40] [DEBUG] TransactionSynchronizationManager: Clearing transaction synchronization

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值