事务的回滚
如果获取事务属性不为空,并且抛出的异常是RuntimeException或者Error类型,调用事务管理器中的rollback方法进行回滚
如果事务属性为空或者抛出的异常不是RuntimeException,也不是Error,将继续提交事务
1 | public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean { |
rollback方法在AbstractPlatformTransactionManager中实现,主要分为以下三种情况:
- 判断事务是否设置了保存点,如果设置了将事务回滚到保存点
- 如果是一个独立的新事务,直接回滚即可
- 如果既没有设置保存点,也不是一个新事务,说明可能处于嵌套事务中,此时只设置回滚状态rollbackOnly为true,当它的外围事务进行提交时,如果发现回滚状态为true,则不提交
以上步骤执行完毕,调用cleanupAfterCompletion方法进行资源的清理已经挂起事务的恢复。
1 | public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable { |
回滚处理
rollbackToHeldSavepoint回滚至保存点
rollbackToHeldSavepoint方法在AbstractTransactionStatus中实现,它调用了getSavepointManager方法获取保存点管理器,调用SavepointManager的rollbackToSavepoint方法进行回滚的:
1 | public abstract class AbstractTransactionStatus implements TransactionStatus { |
SavepointManager是一个接口,它的继承关系如下:
DefaultTransactionStatus中获取SavepointManager的方法:
- 获取transaction对象,前面的知识可知这里是一个DataSourceTransactionObject
- 由继承关系可知DataSourceTransactionObject也是SavepointManager子类,所以将DataSourceTransactionObject转为SavepointManager返回
1
2
3
4
5
6
7
8
9
10
11
12
13public class DefaultTransactionStatus extends AbstractTransactionStatus {
protected SavepointManager getSavepointManager() {
// 前面的知识可知这里是一个DataSourceTransactionObject
Object transaction = this.transaction;
if (!(transaction instanceof SavepointManager)) {
throw new NestedTransactionNotSupportedException(
"Transaction object [" + this.transaction + "] does not support savepoints");
}
// 将DataSourceTransactionObject转为SavepointManager
return (SavepointManager) transaction;
}
}
DataSourceTransactionObject是DataSourceTransactionManager的内部类,它继承了JdbcTransactionObjectSupport,rollbackToSavepoint方法在JdbcTransactionObjectSupport中实现:
- 获取ConnectionHolder,ConnectionHolder持有数据库连接
- 调用底层的rollback方法将事务回滚至保存点
1 | public class DataSourceTransactionManager extends AbstractPlatformTransactionManager |
doRollback事务回滚
回滚事务时先获取数据库连接,然后调用底层的rollback进行回滚:
1 | public class DataSourceTransactionManager extends AbstractPlatformTransactionManager |
doSetRollbackOnly设置回滚状态
doSetRollbackOnly方法在DataSourceTransactionManager中实现:
将事务转为DataSourceTransactionObject对象,前面讲过DataSourceTransactionObject持有了数据库连接对象ConnectionHolder
将ConnectionHolder的rollbackOnly属性置为true,先标记事务的回滚状态,交由外围事务进行判断统一进行回滚
1 | public class DataSourceTransactionManager extends AbstractPlatformTransactionManager |
资源清理
在事务回滚之后,需要清理相关的资源以及恢复被挂起的事务:
- 如果事务的newSynchronization状态为true,清除当前线程绑定的事务相关信息
- 在TransactionSynchronizationManager的clear方法中实现,清理了当前线程绑定的事务名称、事务隔离级别等信息
- 如果是一个新事务,清除当前线程与数据库连接的绑定关系,在DataSourceTransactionManager的doCleanupAfterCompletion方法中实现
- 如果挂起的事务不为空,恢复挂起的事务
- 获取数据源,恢复数据源与挂起事务的绑定关系
- 恢复挂起事务与当前线程的同步信息
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
/**
* 回滚之后的清除操作
* @see #doCleanupAfterCompletion
*/
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
// 清除当前线程绑定的信息
TransactionSynchronizationManager.clear();
}
// 如果是一个新事务
if (status.isNewTransaction()) {
// 清除当前线程与数据库连接的绑定关系
doCleanupAfterCompletion(status.getTransaction());
}
// 如果挂起的事务不为空
if (status.getSuspendedResources() != null) {
if (status.isDebug()) {
logger.debug("Resuming suspended transaction after completion of inner transaction");
}
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
// 恢复挂起的事务
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
/**
* 恢复挂起的事务
* @see #doResume
* @see #suspend
*/
protected final void resume(@Nullable Object transaction, @Nullable 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);
}
}
}
}
// DataSourceTransactionManager
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
// 主要是清除当前线程与数据库连接的绑定关系
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// Remove the connection holder from the thread, if exposed.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
// 获取数据库连接
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
// 自动提交置为true
con.setAutoCommit(true);
}
// 重置数据库连接的相关设置
DataSourceUtils.resetConnectionAfterTransaction(
con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
}
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();
}
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
// 获取数据源,并与挂起的事务进行绑定
TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}
}
// TransactionSynchronizationManager
public abstract class TransactionSynchronizationManager {
// 保存了线程绑定的数据库资源信息,Map中Key为数据源构建的KEY,value为对应的ConnectionHolder
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
// 保存了线程绑定的事务同步信息TransactionSynchronization
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
// 保存了线程绑定的事务名称
private static final ThreadLocal<String> currentTransactionName =
new NamedThreadLocal<>("Current transaction name");
// 保存了线程绑定的事务只读状态
private static final ThreadLocal<Boolean> currentTransactionReadOnly =
new NamedThreadLocal<>("Current transaction read-only status");
// 保存了线程绑定的事务隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel =
new NamedThreadLocal<>("Current transaction isolation level");
// 保存了线程绑定的事务活跃状态
private static final ThreadLocal<Boolean> actualTransactionActive =
new NamedThreadLocal<>("Actual transaction active");
/**
* 清理事务与当前线程的各种同步状态
*/
public static void clear() {
// 清除当前线程绑定的事务同步信息TransactionSynchronization
synchronizations.remove();
// 清除当前线程绑定的事务名称
currentTransactionName.remove();
// 清除线程绑定的事务只读状态
currentTransactionReadOnly.remove();
// 清除线程绑定的事务隔离级别
currentTransactionIsolationLevel.remove();
// 清除线程绑定的事务活跃状态
actualTransactionActive.remove();
}
}
总结
参考
Spring版本:5.2.5.RELEASE