目录
  1. 前言
  2. 清理事务信息
    1. TransactionInfo
    2. 清理过程
  3. 提交事务
    1. doCommit
    2. doRollbackOnCommitException
    3. cleanupAfterCompletion
spring事务(6) spring提交事务源码分析

前言

spring事务入口及整体流程这一节,我们提到了spring事务整体流程的第三部分和第四部分分别是是清理事务信息和提交事务。由于清理事务信息内容较少,就和提交事务合并起来。

清理事务信息

在spring创建事务结束后其实返回的是一个事务信息(TransactionInfo),我们来看一下这个事务信息中都有些什么样的东西。

TransactionInfo

TransactionInfo中有这样一些属性:

1
2
3
4
5
private final PlatformTransactionManager transactionManager;
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
private TransactionStatus transactionStatus;
private TransactionInfo oldTransactionInfo;

可以看到里面封装了

  • 事务管理器,我们此处使用的是DataSourceTransactionManager
  • 事务属性,例如传播属性、隔离级别等
  • 连接点,在spring事务(2) spring事务入口及整体流程中有讲到,就是类似于study.cayun.login.service.impl.UserServiceImpl.insertUser这样的一个字符串
  • 事务状态,包含当前事务对象、是否新事务、是否新同步等
  • 旧的事务信息

清理过程

代码如下,比较短。

1
2
3
4
5
protected void cleanupTransactionInfo(TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
1
2
3
4
5
6
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<TransactionInfo>("Current aspect-driven transaction");

private void restoreThreadLocalStatus() {
transactionInfoHolder.set(this.oldTransactionInfo);
}

可以从上面的源码中看到清理事务信息其实就是将当前事务信息与线程解绑,并将旧的事务信息绑定到线程。

注:txInfo变量本身并没有改变。

提交事务

打开源码如下,

1
2
3
4
5
6
7
8
9
10
// 该方法在TransactionAspectSupport类中

protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
if (txInfo != null && txInfo.hasTransaction()) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}

里面调用了该方法调用了AbstractPlatformTransactionManager类中的commit方法,我们继续打开commit的源码,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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;
if (defStatus.isLocalRollbackOnly()) {
processRollback(defStatus);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
processRollback(defStatus);
if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
return;
}

processCommit(defStatus);
}

在这段代码中可以看到里面首先也和spring异常回滚中一样,都做了一个已完成标记的判断。接着可以看到,此处对于那些已经设置为rollbackOnly的事务会进行回滚操作,而不是提交。

我们此处就直接来看最后一步processCommit吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
// 空实现
prepareForCommit(status);
// 回调TransactionSynchronization的beforeCommit方法
triggerBeforeCommit(status);
// 回调TransactionSynchronization的beforeCompletion方法
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
boolean globalRollbackOnly = false;
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);
}
if (globalRollbackOnly) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// 回调TransactionSynchronization的afterCompletion方法
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by 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;
}

try {
// 回调TransactionSynchronization的afterCommit方法
triggerAfterCommit(status);
}
finally {
// 回调TransactionSynchronization的afterCompletion方法
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}

}
finally {
cleanupAfterCompletion(status);
}
}

大概比较需要关注的就是doCommit、doRollbackOnCommitException和cleanupAfterCompletion这三个方法。

doCommit

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}
}

提交的最终操作可以看到与回滚一样,都是直接调用的数据库的接口来执行的。

doRollbackOnCommitException

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}
}

可以看到异常回滚部分,主要做了这样两件事:

  • 回滚/设置rollbackOnly标记
  • 触发TransactionSynchronization的afterCompletion方法

其中我们可以从triggerAfterCompletion参数中理解TransactionSynchronization.STATUS_*所代表的意义。

cleanupAfterCompletion

这个在spring异常回滚源码分析的最后一段已经分析过了。

文章作者: 谷河
文章链接: https://www.lyytaw.com/spring/spring_tx_commitTransaction/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 谷河|BLOG