1.引
通过前面的分析,已经成功的创建了事物,但是不要忘了,当前方法仍在方法拦截器链中。回顾一下代码片段:
// 2.处理声明式事物 if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. // 2.2 创建事物 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); System.out.println("==创建了名为:["+joinpointIdentification+"]的事物"); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. // 2.3 继续调用方法拦截器链,这里一般将会调用目标类的方法,如:com.lyc.cn.v2.day09.AccountServiceImpl.save方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception // 2.4 如果目标类方法抛出异常,则在此处理,例如:事物回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { // 2.5 清除上一步创建的事物信息 cleanupTransactionInfo(txInfo); } // 2.6 调用成功完成后执行,但不是在异常被处理后执行。如果我们不创建事务,就什么也不做。 commitTransactionAfterReturning(txInfo); return retVal; }
关于拦截器链的调用、目标方法的调用等不做过多的分析了,前面都有介绍。
那么接下来的处理也会分为两种情况,有异常和无异常两种情况,有异常的话,那么可能会执行回滚等操作;没有异常的话,可能会执行事物提交等操作,接下来对两种情况逐个分析。
2.业务方法发生异常之后的处理
/** * 处理异常以完成事物,基于配置该事物可能回滚也可能提交 * 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(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } // 1.回滚 /** * txInfo.transactionAttribute.rollbackOn(ex)判断回滚的条件: * * 1. 如果自定了RollbackRuleAttribute列表,如果当前异常匹配到了RollbackRuleAttribute其中的条目,则回滚 * 例如:可以通过rollbackFor指定触发回滚的异常@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class) * * 2. 否则如果异常是RuntimeException或者Error的类型,则回滚 * * 3. 其他的异常是不会回滚的,这里要注意一下... */ if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { // 执行回滚 System.out.println("==准备回滚"+txInfo.getJoinpointIdentification()); txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } } // 2.如果未能满足回滚条件,则有可能会提交事物,也有可能会回滚事物 // 注意:如果TransactionStatus.isRollbackOnly()为true,则仍然会执行回滚 else { // We don't roll back on this exception. // Will still roll back if TransactionStatus.isRollbackOnly() is true. try { System.out.println("==准备提交"+txInfo.getJoinpointIdentification()); txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by commit exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException | Error ex2) { logger.error("Application exception overridden by commit exception", ex); throw ex2; } } } }
2.1 判断回滚条件:
- 如果自定了RollbackRuleAttribute列表,如果当前异常匹配到了RollbackRuleAttribute其中的条目,则回滚
例如:可以通过rollbackFor指定触发回滚的异常@Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)。 - 否则如果异常是RuntimeException或者Error的类型,则回滚。
- 其他的异常是不会回滚的。
2.2 正常回滚
如果满足了if条件,那么当前事物会执行回滚操作
2.3 回滚或提交
如果未能满足if条件,那么当前事物可能会被提交、可能会被回滚。例如当前事物的rollbackOnly为true,依然会执行回滚操作。当然如果未能满足回滚条件的话,即使该事物抛出异常,依然会被提交。
接下来对正常回滚、回滚或提交逐个分析。
3.正常回滚
// 执行回滚前检查事物状态 public final void rollback(TransactionStatus status) throws TransactionException { if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; processRollback(defStatus, false); } // 执行回滚 private void processRollback(DefaultTransactionStatus status, boolean unexpected) { try { boolean unexpectedRollback = unexpected; try { // 1.事物完成之前的触发器调用 triggerBeforeCompletion(status); // 2.如果有保存点,则调用rollbackToHeldSavepoint回滚到保存点 if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Rolling back transaction to savepoint"); } status.rollbackToHeldSavepoint(); } // 3.如果当前事物是一个新的事物,则调用doRollback执行给定事物的回滚 else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction rollback"); } doRollback(status); } else { // Participating in larger transaction // 4.如果当前事物并非独立事物,则将当前事物的rollbackOnly属性标记为true,等到事物链完成之后,一起执行回滚 // 如果当前存在事物,但是 // 事物的rollbackOnly属性已经被标记为true // 或者globalRollbackOnParticipationFailure(返回是否仅在参与事务失败后才将现有事务全局标记为回滚)为true if (status.hasTransaction()) { if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) { if (status.isDebug()) { logger.debug("Participating transaction failed - marking existing transaction as rollback-only"); } System.out.println("==当前事物并非独立事物,且RollbackOnly为true\n"); // 则将ConnectionHolder中的rollbackOnly标记为true doSetRollbackOnly(status); } else { if (status.isDebug()) { logger.debug("Participating transaction failed - letting transaction originator decide on rollback"); } } } // 如果当前不存在事物,则不会回滚 // 例如配置了 @Transactional(propagation = Propagation.NOT_SUPPORTED) else { logger.debug("Should roll back transaction but cannot - no transaction available"); } // Unexpected rollback only matters here if we're asked to fail early if (!isFailEarlyOnGlobalRollbackOnly()) { unexpectedRollback = false; } } } catch (RuntimeException | Error ex) { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); throw ex; } // 5.事物完成之后的触发器调用 triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); // Raise UnexpectedRollbackException if we had a global rollback-only marker if (unexpectedRollback) { throw new UnexpectedRollbackException("Transaction rolled back because it has been marked as rollback-only"); } } finally { cleanupAfterCompletion(status); } }
- 事物完成前、完成后触发器的调用,例如:如果我们在业务方法里注册了TransactionSynchronizationAdapter,那么在这里会分别执行其beforeCompletion、afterCompletion,以完成一些额外的功能扩展。关于TransactionSynchronizationAdapter我们留在后面讲解,这里大家只需要了解会在事物完成前后调用一些额外的方法即可。
- 如果有保存点,则调用rollbackToHeldSavepoint回滚到保存点
- 如果当前事物是一个新的事物,则调用doRollback执行给定事物的回滚
- 如果当前事物并非独立事物,则将当前事物的rollbackOnly属性标记为true,等到事物链完成之后,一起执行回滚
大概的流程就是这样了,因为我们分析的是单service下的单个业务方法调用,所以这里我们还是只分析最简单的doRollback正常回滚调用(事物嵌套留在后面讲解)
关于doRollback的调用,对于不同的事物管理器分别有不同的调用方法,这里我们只看DataSourceTransactionManager的回滚方法:
@Override protected void doRollback(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Rolling back JDBC transaction on Connection [" + con + "]"); } try { con.rollback(); } catch (SQLException ex) { throw new TransactionSystemException("Could not roll back JDBC transaction", ex); } }
该方法很简单,从ConnectionHolder中拿到连接,执行回滚。这里涉及到具体的JDBC驱动的方法调用,感兴趣的同学可以自己深入分析下,就不多做介绍了。
4.回滚或提交
public final void commit(TransactionStatus status) throws TransactionException { // 如果当前事物已经被标记为完成,抛出异常 if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; // 如果rollbackOnly为true,则回滚 if (defStatus.isLocalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Transactional code has requested rollback"); } processRollback(defStatus, false); return; } // shouldCommitOnGlobalRollbackOnly --> 返回是否对标记为仅以全局方式回滚的事务调用 // defStatus.isGlobalRollbackOnly() --> 实现了SmartTransactionObject并且事物的rollbackOnly被标记为true if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); } processRollback(defStatus, true); return; } // 提交事物 processCommit(defStatus); }
关于回滚和提交的判断条件注释都写的很清晰了,对于rollbackOnly这里不做太多的介绍,留在后面的章节分析。大家只要记住,事物到了这里,可能会回滚也可能会提交即可。