转载

mysql事务管理及spring声明式事务中主动异常抛出使数据库回滚

mysql的引擎常用的有两个,一个MyISAM,另一个是InnoDB,mysql默认的为MyISAM,而InnoDB才是支持事务的。所以一般需要修改下,如何修改就不说了。

事务需要依赖数据库,好久没使用声明式事务,今天试了下。关键配置如下。

<tx:advice id="transactionAdvice" transaction-manager="transactionManager">   <tx:attributes>    <tx:method name="add*" propagation="REQUIRED" />    <tx:method name="append*" propagation="REQUIRED" />    <tx:method name="insert*" propagation="REQUIRED" />    <tx:method name="save*" propagation="REQUIRED" />    <tx:method name="update*" propagation="REQUIRED" />    <tx:method name="modify*" propagation="REQUIRED" />    <tx:method name="edit*" propagation="REQUIRED" />    <tx:method name="delete*" propagation="REQUIRED" />    <tx:method name="remove*" propagation="REQUIRED" />    <tx:method name="tx*" propagation="REQUIRED" />    <tx:method name="repair" propagation="REQUIRED" />    <tx:method name="delAndRepair" propagation="REQUIRED"   />     <tx:method name="get*" propagation="SUPPORTS" />    <tx:method name="find*" propagation="SUPPORTS" />    <tx:method name="load*" propagation="SUPPORTS" />    <tx:method name="search*" propagation="SUPPORTS" />    <tx:method name="datagrid*" propagation="SUPPORTS" />     <tx:method name="*" propagation="SUPPORTS" />   </tx:attributes>  </tx:advice>  <aop:config>   <aop:pointcut id="transactionPointcut" expression="execution(* com.wondersgroup.employeeBenefits.*.*.service..*Impl.*(..))" />      <!-- com.wondersgroup.benefit.*.core.service..*Impl.*(..) -->   <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" />  </aop:config>

事务配置好之后再service中手动抛了个exception,结果没有回滚,service方法如下

@Override     public int saveBudgetApplyInfo(BudgetApplyInfo budgetApplyInfo) throws Exception {          budgetApplyInfoMapper.insert(budgetApplyInfo);         if(1==1){              throw new Exception();         }         return 1;     }

跟着断点一步步进去查看原因

TransactionAspectSupport中发现这样一个方法
/**   * Handle a throwable, completing the transaction.   * We may commit or roll back, depending on the configuration.   * @param txInfo information about the current transaction   * @param ex throwable encountered   */  protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {   if (txInfo != null && txInfo.hasTransaction()) {    if (logger.isTraceEnabled()) {     logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +       "] after exception: " + ex);    }    if (txInfo.transactionAttribute.rollbackOn(ex)) {     try {      txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());     }     catch (TransactionSystemException ex2) {      logger.error("Application exception overridden by rollback exception", ex);      ex2.initApplicationException(ex);      throw ex2;     }     catch (RuntimeException ex2) {      logger.error("Application exception overridden by rollback exception", ex);      throw ex2;     }     catch (Error err) {      logger.error("Application exception overridden by rollback error", ex);      throw err;     }    }    else {     // We don't roll back on this exception.     // Will still roll back if TransactionStatus.isRollbackOnly() is true.     try {      txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());     }     catch (TransactionSystemException ex2) {      logger.error("Application exception overridden by commit exception", ex);      ex2.initApplicationException(ex);      throw ex2;     }     catch (RuntimeException ex2) {      logger.error("Application exception overridden by commit exception", ex);      throw ex2;     }     catch (Error err) {      logger.error("Application exception overridden by commit error", ex);      throw err;     }    }   }  }

上面的方法中有这么一段

txInfo.transactionAttribute.rollbackOn(ex),这里是判断是否需要执行回滚操作的,跟踪rollbackOn方法最后会执行到
DefaultTransactionAttribute中的rollbackOn方法
/**   * The default behavior is as with EJB: rollback on unchecked exception.   * Additionally attempt to rollback on Error.   * <p>This is consistent with TransactionTemplate's default behavior.   */  public boolean rollbackOn(Throwable ex) {   return (ex instanceof RuntimeException || ex instanceof Error);  }

看到这里,应该都清楚了。。。自己主动抛异常Exception是不对的。这里只捕获运行时异常

RuntimeException 及Error,所以我们测试时不可以直接抛Exception,而应该换成
RuntimeException 。当然。也可在xml中指定rollback-for
<tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />

最后:个人还是比较喜欢基于注解的事务处理

正文到此结束
Loading...