TransactionManager的第4部分,分析commit及rollback方法。

commit

commit方法也是在AbstactPlantformTransactionManager中定义的。

可以看到commit方法的参数是TransactionStatus,前面开启事务getTransaction的返回也是这个对象。

首先判断事务状态如果是已完成的话抛异常。

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");
        }

然后判断当前事务是否被设置为只能rollback,是的话调用processRollback方法回滚。否则,调用processCommit方法提交事务。

DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
        if (defStatus.isLocalRollbackOnly()) {
            if (defStatus.isDebug()) {
                logger.debug("Transactional code has requested rollback");
            }
            processRollback(defStatus, false);
            return;
        }
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);

processCommit

processCommit方法仍然在AbstractPlantformTransactionManager中。

Process an actual commit. Rollback-only flags have already been checked and applied.
Params:
status – object representing the transaction
Throws:
TransactionException – in case of commit failure

执行真正的commit,如果设置了回滚标识的话则回滚事务

可见运行到processCommit之后,事务仍然有可能被回滚。

调用prepareForCommit做提交前准备,调用triggerBeforeCommit/triggerBeforeCompletion触发提交前监听。

try {
            boolean beforeCompletionInvoked = false;

            try {
                boolean unexpectedRollback = false;
                prepareForCommit(status);
                triggerBeforeCommit(status);
                triggerBeforeCompletion(status);
                beforeCompletionInvoked = true;

查看了一下prepareForCommit,在AbstarctPlantformTransactionManager中没有任何代码实现,他的子类也没有做实现。所以这个方法可能是为了扩展预留的。

所有的提交前、提交后监听器处理,我们就不做分析了,个人认为不太重要,很少有适用的场景。

所以我们继续往下看,检查status中是否有savepoint,有的话,释放savepoint,这里需要留一个小疑问,在传播机制设置为嵌套的情况下,已开启事务会设置savepoint,代码逻辑应该会走到这里来,但是这里只是释放savepoint,后续并没有调用commit,这是不应该的。暂存疑问(今天看半年前的文章,感觉半年以来在阅读源码、持续学习上还是应该继续坚持的......这个疑问今天其实可以打消了,因为当前的方法是commit,马上要准备提交事务了,savepoint释放掉之后,意思就是savePoint之前的、和之后的可以一起提交了。其实savePoint需要特殊处理的地方是rollback,后面会提到)。

if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        logger.debug("Releasing transaction savepoint");
                    }
                    unexpectedRollback = status.isGlobalRollbackOnly();
                    status.releaseHeldSavepoint();
                }

接下来,才调用到了真正的事务提交方法doCommit,注意status的isNewTransaction必须为true,事务才能被提交。

else if (status.isNewTransaction()) {
                    if (status.isDebug()) {
                        logger.debug("Initiating transaction commit");
                    }
                    unexpectedRollback = status.isGlobalRollbackOnly();
                    doCommit(status);
                }

之后就是事务提交的后处理了,判断如果发生提交时异常则回滚事务,然后还有就是提交后的监听处理,这部分就不再详细分析了。

doCommit

commit方法的最终提交真相都在这里。我们已经知道,他一定是在DataSourceTransactionManager中实现的。

到这里,该铺垫的、该准备的都已经完成了,提交方法本身反而非常简单了。

通过TransactionStatus获取事务对象transaction,在通过其持有的ConnectionHolder获取到数据库连接Connection,然后,就是Connection的commit方法。

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 translateException("JDBC commit", ex);
        }
    }

前面的getTransaction,以及commit方法在调用到doCommit方法之前的一堆准备操作,相当于是在弯弓搭箭,最后这一下con.commit才最终射向数据库。把最复杂的事务提交(其实包括事务开启、sql语句在事务下执行等等)甩锅给数据库去处理了。

commit方法分析完毕。

rollback

其实,分析完commiit方法之后,rollback方法就没有什么秘密了。

rollback方法也是在AbstractPlatformTranactionManager中,结构与commit几乎一样,区别之处在processRollback中判断事务有保存点的话:

if (status.hasSavepoint()) {
                    if (status.isDebug()) {
                        logger.debug("Rolling back transaction to savepoint");
                    }
                    status.rollbackToHeldSavepoint();
                }

调用TransactionStatus的rollbackToHeldSavepoint,回滚到保存点。

其他的代码结构就和commit几乎一样了,调用doRollback方法,之后就是回滚的后处理。

doRollback方法同样在DataSourcePlantformTransactionManager中实现,获取数据库连接并调用数据库连接的rollback:

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 translateException("JDBC rollback", ex);
        }
    }

OK了,TransactionMnaager的3大方法:启动事务、提交事务、回滚事务分析完毕。

后面有关Spring事务管理的相关支持还有事务启用机制(@EnableTransactionManagement)以及事务控制(@Transactional),可以看作是Spring事务框架的具体应用了。

有机会再做详细分析。

上一篇 Spring事务框架之TransactionManager(3)
下一篇 启用Spring事务管理@EnableTransactionManagement(1)


45 声望17 粉丝