本文分析下:事务回滚和事务提交
1.事务回滚方法completeTransactionAfterThrowing(txInfo, ex)
/**
* 处理一个throwable,完成事务。
* 我们可能会提交或回滚,具体取决于配置。
* @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.
// 我们不需要对该异常回滚
// 如果TransactionStatus.isRollbackOnly()为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;
}
}
}
}
- a.首先是rollbackOn(ex)方法;该方法用于判断异常是否需要回滚,默认情况下方法实现为DefaultTransactionAttribute.rollbackOn(Throwable ex)方法;可以看到只有RuntimeException和Error才会回滚
-
@Override public boolean rollbackOn(Throwable ex) { return (ex instanceof RuntimeException || ex instanceof Error); }
- 我们可以通过@Transactional(rollbackFor = Exception.class,noRollbackFor = NoPermissionException.class)这种方式决定哪些异常回滚哪些异常不会滚;此时调用的方法是RuleBasedTransactionAttribute类的rollbackOn方法
- b. 如果对于该异常需要回滚;方法被委托给事务管理器的rollback
- c,如果是不需要回滚的异常,则提交事务;方法委托给事务管理器的commit方法
2.AbstractPlatformTransactionManager.rollback方法
/**
* This implementation of rollback handles participating in existing
* transactions. Delegates to {@code doRollback} and
* {@code doSetRollbackOnly}.
* @see #doRollback
* @see #doSetRollbackOnly
*/
@Override
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);
}
/**
* 处理实际的回滚
* 完成标识已经检查了
* @param status object representing the transaction
* @throws TransactionException in case of rollback failure
*/
private void processRollback(DefaultTransactionStatus status) {
try {
try {
//触发所有注册的TransactionSynchronization的beforeCompletion方法,做些骚操作
triggerBeforeCompletion(status);
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
//如果有保存点,当前事务回退到保存点
status.rollbackToHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
//如果当前事务为新的事务,回滚
doRollback(status);
}
else if (status.hasTransaction()) {
//不是独立的事务,仅仅设置事务对象的回滚标志
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
}
doSetRollbackOnly(status);
}
else {
if (status.isDebug()) {
logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
}
catch (RuntimeException ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
catch (Error err) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw err;
}
//回调TransactionSynchronization的afterCompletion方法
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
finally {
cleanupAfterCompletion(status);
}
}
- a.trggerxxxxx方法:对于自定义TransactionSynchronization接口实现的调用:在回滚前,完成回滚,回滚出现异常情况下都会调用哎嘿嘿;我们可以通过
- TransactionSynchronizationManager.registerSynchronization注册
- b.当前事务信息中有没有保存点;如果有的话,使用SavepointManager回滚保存点;比如
-
@Override public void rollbackToSavepoint(Object savepoint) throws TransactionException { ConnectionHolder conHolder = getConnectionHolderForSavepoint(); try { conHolder.getConnection().rollback((Savepoint) savepoint); } catch (Throwable ex) { throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex); } }
- c.对于新事务,委托doRollback方法给不同的事务管理器比如DataSourceTransactionManager.doRollback
-
@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); } }
- d.事务并不独立,判断下是否需要设置rollbackOnly标识
-
@Override protected void doSetRollbackOnly(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); if (status.isDebug()) { logger.debug("Setting JDBC transaction [" + txObject.getConnectionHolder().getConnection() + "] rollback-only"); } txObject.setRollbackOnly(); }
- e.回滚后,清理事务信息归还占用的connection并唤醒挂起的资源
-
/** * 完成后清理,必要时清除同步, * 并调用doCleanupAfterCompletion * @param status object representing the transaction * @see #doCleanupAfterCompletion */ private void cleanupAfterCompletion(DefaultTransactionStatus status) { //设置完成标识 status.setCompleted(); if (status.isNewSynchronization()) { TransactionSynchronizationManager.clear(); } //当前事务为新事务;解除资源与线程绑定 还原connection属性 并归还给连接池 if (status.isNewTransaction()) { doCleanupAfterCompletion(status.getTransaction()); } //当前事务挂起的资源不为Null if (status.getSuspendedResources() != null) { if (status.isDebug()) { logger.debug("Resuming suspended transaction after completion of inner transaction"); } //恢复挂起的资源 resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources()); } } @Override protected void doCleanupAfterCompletion(Object transaction) { //事务object DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction; // Remove the connection holder from the thread, if exposed. // 解除数据库连接与当前事务的绑定 if (txObject.isNewConnectionHolder()) { TransactionSynchronizationManager.unbindResource(this.dataSource); } // Reset connection. // 释放连接 Connection con = txObject.getConnectionHolder().getConnection(); try { if (txObject.isMustRestoreAutoCommit()) { con.setAutoCommit(true); } DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel()); } catch (Throwable ex) { logger.debug("Could not reset JDBC Connection after transaction", ex); } if (txObject.isNewConnectionHolder()) { if (logger.isDebugEnabled()) { logger.debug("Releasing JDBC Connection [" + con + "] after transaction"); } //释放连接 DataSourceUtils.releaseConnection(con, this.dataSource); } txObject.getConnectionHolder().clear(); } /** * Resume the given transaction. Delegates to the {@code doResume} * template method first, then resuming transaction synchronization. * * 恢复给定的事务。 首先委托{@code doResume}模板方法,然后恢复事务同步。 * @param transaction the current transaction object * @param resourcesHolder the object that holds suspended resources, * as returned by {@code suspend} (or {@code null} to just * resume synchronizations, if any) * @see #doResume * @see #suspend */ protected final void resume(Object transaction, SuspendedResourcesHolder resourcesHolder) throws TransactionException { if (resourcesHolder != null) { //挂起的资源 Object suspendedResources = resourcesHolder.suspendedResources; if (suspendedResources != null) { //模板方法留给子类实现 doResume(transaction, suspendedResources); } List<TransactionSynchronization> suspendedSynchronizations = resourcesHolder.suspendedSynchronizations; if (suspendedSynchronizations != null) { //恢复挂起的事务信息 TransactionSynchronizationManager.setActualTransactionActive(resourcesHolder.wasActive); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(resourcesHolder.isolationLevel); TransactionSynchronizationManager.setCurrentTransactionReadOnly(resourcesHolder.readOnly); TransactionSynchronizationManager.setCurrentTransactionName(resourcesHolder.name); doResumeSynchronization(suspendedSynchronizations); } } }
3.AbstractPlatformTransactionManager.commitTransactionAfterReturning方法提交事务方法
/**
* 成功完成调用后执行,但在处理异常后不执行。
* 如果我们没有创建事务,则不执行任何操作
* @param txInfo information about the current transaction
*/
protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
//事务信息不为null 并且包含事务
if (txInfo != null && txInfo.hasTransaction()) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
//委托给事务管理器提交事务
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
委托commit方法给AbstractTransactionManager.commit()
/**
* commit方法的实现,处理参与已存在的事务并且程序化的回滚请求
* Delegates to {@code isRollbackOnly}, {@code doCommit}
* and {@code rollback}.
* @see org.springframework.transaction.TransactionStatus#isRollbackOnly()
* @see #doCommit
* @see #rollback
*/
@Override
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");
}
//事务status
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//在嵌套事务中已被标记为回滚,回滚
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
//事务回滚
processRollback(defStatus);
return;
}
//不应该在设置了globalRollbackOnly的情况下提交 并且 事务状态该需要回滚
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
//回滚操作
processRollback(defStatus);
// Throw UnexpectedRollbackException only at outermost transaction boundary
// or if explicitly asked to.
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
return;
}
//提交事务
processCommit(defStatus);
}
4.实际提交事务的处理逻辑processCommit
/**
* 实际提交事务的逻辑
* 仅回滚标志已被检查并应用.
* @param status object representing the transaction
* @throws TransactionException in case of commit failure
*/
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
//TODO 扩展点 提交之前准备
prepareForCommit(status);
//调用TransactionSynchronization 的beforeCommit方法
triggerBeforeCommit(status);
//调用TransactionSynchronization beforeCompletion
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
boolean globalRollbackOnly = false;
//新事物 或者 需要在全局标记为rollback-only的情况下是否提前失败
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
globalRollbackOnly = status.isGlobalRollbackOnly();
}
//事务有保存点
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
//释放保存点
status.releaseHeldSavepoint();
}
//是否为新事物
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
//提交事务
doCommit(status);
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
//如果我们只有全局回滚标记,则抛出UnexpectedRollbackException
//但仍然没有从提交中获得相应的异常
if (globalRollbackOnly) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by doCommit
//doCommit失败后是否应该执行回滚操作
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
catch (Error err) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, err);
throw err;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
- a.事务状态总有保存点,不提交事务;仅仅是releaseSavePoint()
-
/** * This implementation releases the given JDBC 3.0 Savepoint. * @see java.sql.Connection#releaseSavepoint */ @Override public void releaseSavepoint(Object savepoint) throws TransactionException { ConnectionHolder conHolder = getConnectionHolderForSavepoint(); try { conHolder.getConnection().releaseSavepoint((Savepoint) savepoint); } catch (Throwable ex) { logger.debug("Could not explicitly release JDBC savepoint", ex); } }
- b.真正提交事务的代码,交给了子类实现DataSourceTransactionManager.doCommit,可以看到最终还是基于connection提交了事务
-
@Override protected void doCommit(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Committing JDBC transaction on Connection [" + con + "]"); } try { con.commit(); } catch (SQLException ex) { throw new TransactionSystemException("Could not commit JDBC transaction", ex); } }
- c.提交失败了Spring对TransactionException 、RuntimeException、Error、类型的异常会进行事务回滚;真的是贴心呢。
private void doRollbackOnCommitException(DefaultTransactionStatus status, Throwable ex) throws TransactionException {
try {
if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback after commit exception", ex);
}
doRollback(status);
}
else if (status.hasTransaction() && isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug("Marking existing transaction as rollback-only after commit exception", ex);
}
doSetRollbackOnly(status);
}
}
catch (RuntimeException rbex) {
logger.error("Commit exception overridden by rollback exception", ex);
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw rbex;
}
catch (Error rberr) {
logger.error("Commit exception overridden by rollback exception", ex);
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw rberr;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
5.清楚当前线程绑定的事务信息
/**
* 重置TransactionInfo ThreadLocal。
* <p>在所有情况下都要调用它:异常或正常返回!
* @param txInfo information about the current transaction (may be {@code null})
*/
protected void cleanupTransactionInfo(TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}