目录
  1. commit
  2. rollback
Spring-TX【四】commit和rollback

提交和回滚的流程依然定义在AbstractPlateformTransactionManager中,具体的提交操作和回滚操作由其子类调用数据源后取得连接实现。

commit

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
/**
* 提交的这个实现处理参与现有事务和编程式回滚请求。
* 委托给 {@code isRollbackOnly}, {@code doCommit} and {@code rollback}.
*
* @see TransactionStatus#isRollbackOnly()
* @see #doCommit
* @see #rollback
*/
@Override
public final void commit(TransactionStatus status) throws TransactionException {
//事务已经完成—不要在每个事务中调用commit或rollback超过一次
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;
//通过检查这个事务状态确定只回滚标志。默认时false,
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);
}

在提交之前会检查事务状态的回滚标志,如果是请求回滚,则执行回滚操作,如果没有回滚,则执行提交操作:

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
79
80
81
82
83
84
85
86
/**
* 处理实际提交。
* 仅回滚 标志 已经被检查和应用。
*
* @param status 表示事务的对象
* @throws TransactionException 如果提交失败
*/
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;

try {
boolean unexpectedRollback = false;
//准备提交,在beforeCommit同步回调发生之前执行。
prepareForCommit(status);
//触发beforeCommit回调
triggerBeforeCommit(status);
//触发beforeCompletion回调。
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;

if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
//释放事务保存点
status.releaseHeldSavepoint();
} else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
//启动事务提交
doCommit(status);
} else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}

// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
//事务悄悄地回滚,因为它被标记为仅回滚
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
} catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
// 触发 afterCompletion回调。
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
} catch (TransactionException ex) {
// can only be caused by doCommit
if (isRollbackOnCommitFailure()) {
//调用{@code doRollback},正确处理回滚异常。
doRollbackOnCommitException(status, ex);
} else {
//触发{@code afterCompletion}回调。
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
} catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
//触发{@code beforeCompletion}回调。
triggerBeforeCompletion(status);
}
//调用{@code doRollback},正确处理回滚异常。
doRollbackOnCommitException(status, ex);
throw ex;
}

// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
//触发{@code afterCommit}回调。
triggerAfterCommit(status);
} finally {
//触发{@code afterCompletion}回调。
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}

} finally {
//完成后进行清理,必要时清除同步,并在完成后调用doCleanupAfterCompletion。
cleanupAfterCompletion(status);
}
}

这个方法有各种分支,各种回调,这里只看新的事务的提交操作:doCommit(DefaultTransactionStatus status),
这个方法由其子类实现,这里看DataSourceTransactionManager中的实现:

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

这里就是调用了JDBC中的commit方法。有时间一定把JDBC的源码好好看看。

rollback

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
* 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, false);
}

/**
* 处理实际回滚。已检查完成的标志。
*
* @param status 表示事务的对象
* @param unexpected 意外的,想不到的
* @throws TransactionException 以防回滚失败
*/
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;

try {
//对所有当前注册的同步触发{@code 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 {
// Participating in larger transaction
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");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
} catch (RuntimeException | Error ex) {
//实际调用给定Spring事务同步对象的{@code afterCompletion}方法。
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}

//实际调用给定Spring事务同步对象的{@code afterCompletion}方法。
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 {
//完成后进行清理,必要时清除同步,并在完成后调用doCleanupAfterCompletion。
cleanupAfterCompletion(status);
}
}

其中的 doRollback(DefaultTransactionStatus status)方法也由子类实现:

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

从上面两个流程可以看出来,spring对于事务的提交和回滚只起到协调作用,最终还是由具体的数据源所实现。

tencent.jpg

文章作者: ClawHub
文章链接: https://www.clawhub.club/posts/2019/08/22/Spring%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/Spring-TX%E3%80%90%E5%9B%9B%E3%80%91commit%E5%92%8Crollback/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ClawHub的博客
打赏
  • 微信
  • 支付宝
扫一扫关注ClawHub公众号,专注Java、技术分享、面试资源。