spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework 。
链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。
1 执行入口
在 声明式事务中XML配置及注解方式的注册入口 中,已经详细列举了事务注入入口的源码。
其中主要有三个比较关键的类:
- BeanFactoryTransactionAttributeSourceAdvisor 增强类,其中封装了Advice,以及TransactionAttributeSource
- TransactionAttributeSource 元数据检索的策略接口,对@Transactional的解析类支持,就在这里面封装。
- TransactionInterceptor Advice实现,也是一个MethodInterceptor,具体的通知方法的执行就在这里面定义的。
在AOP生成代理实例时,会将所有搜集、或转换封装好的Advisor,缓存到AdvisedSupport.advisors中。
在第一次执行代理方法的时候,会遍历所有的Advisor,根据PointCut对方法进行匹配。匹配成功的,就添加到执行链,并缓存到AdvisedSupport.methodCache。后面再调用代理方法,就会优先从缓存中获取。
那么,BeanFactoryTransactionAttributeSourceAdvisor中,一定封装了PointCut。源码中是这样定义的:
1
2
3
4
5
6
7
8
9
10
|
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
private TransactionAttributeSource transactionAttributeSource;
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
}
|
如果一个方法开启了事务,最终在getBean的时候,获取到的一定是代理对象。当第一次调用时,会生成执行链,并按执行链中的节点索引顺序来执行。事务的MethodInterceptor就是其中的一个节点。
既然 TransactionInterceptor 是一个 MethodInterceptor,那它一定实现了 invoke(),事务的执行入口,就在这个invoke()里面。
以下是 invoke() 的源码:
1
2
3
4
5
6
7
8
9
|
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// 执行事务逻辑
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}
}
|
2 主流程概览
进入到 invokeWithinTransaction() 的源码:
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
|
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
/*
* TODO 其中事务传播行为的特点(这些特点,仔细分析代码是可以看出来的。相对比较烧脑。一般先了解特点,后面才会看源码):
* PROPAGATION_REQUIRED 如果当前存在事务,假如当前事务。如果不存在事务,新建事务。
* PROPAGATION_REQUIRES_NEW 如果当前存在事务,则挂起当前事务,新建一个事务。如果不存在事务,新建一个事务。使用频率高
* PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前不存在事务,则和PROPAGATION_REQUIRED一样新建事务。
* 特点:外围事务回滚,嵌套事务全部回滚。嵌套事务回滚,如果在外围中捕获了,则仅仅回滚嵌套事务。
* PROPAGATION_MANDATORY 以事务方式运行,如果当前不存在事务,则抛出异常
* PROPAGATION_NEVER 以非事务方式运行,如果当前存在事务,则抛出异常
* PROPAGATION_SUPPORTEDS 支持事务。如果当前存在事务,加入当前事务。如果不存在事务,则以非事务方式运行。
* PROPAGATION_NOT_SUPPORTED 以非事务方式运行。如果当前存在事务,挂起当前事务。
*/
// 事务属性的获取
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
// TODO getTransactionAttribute中是获取事务注解属性的具体逻辑。
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 获取事务管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// TODO 重点:如果有必要,创建事务
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// 上层方法中传入的回调函数,这里面是AOP执行链,火炬传递,直到调用了业务方法
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 业务方法执行出现异常
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// TODO 清除事务信息,将当前事务清除,如果存在旧的事务对象,将旧的事务对象设置为当前持有的事务
// 存储在TransactionAspectSupport.transactionInfoHolder中,这是一个静态TrheadLocal常量。
cleanupTransactionInfo(txInfo);
}
// TODO 提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
} else {
// 此处省略...
}
}
}
|
上面源码中,注释了前文中列举的spring声明式事务中的七种事务传播行为,以及它们的表现形式。
从源码中可以看出事务的主要流程:
- 获取到 TransactionAttributeSource。这个类封装了事务注解的解析操作。
- 根据第一步获取的结果,调用 getTransactionAttribute(),获取方法中的事务属性。
- 获取到方法的定义,实际上就是当前方法的全路径名。方法的描述在 TransactionAttribute 中有封装。
- 如果有必要,就创建事务。是否有必要、要看方法上是否有 @Transactional 注解,以及传播行为配置。当然,
<tx:advice/>
这种全局配置也是。
- 执行被代理方法,即真正的业务方法。
- 如果抛出异常,按照抛出异常的处理方式,处理提交或回滚事务,将异常向上抛出。(抛出异常只是有可能会回滚,默认Error和RuntimeException会回滚,可以配置。)
- 清楚事务信息。如果存在旧的事务对象,将旧的事务对象设置为当前持有的事务对象。
- 提交事务。
如果看源码细节的话,这是一个很长的流程,要整体串联起来看。
3 传播行为的实现原理
进入到 createTransactionIfNecessary(),看一下源码中怎么做的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// 省略...
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// TODO 重点:获取TransactionStatus对象
// 无论被代理对象的方法是否需要事务,在通过代理对象调用方法时,总会创建一个TransactionStatus,讲一些信息绑定到
// TrheadLocal的缓存变量中。这是为了在执行完方法的时候,可以回溯到调用方法存在的事务对象。类似责任链。
// 如果挂起了存在的事务,则当前方法执行的事务状态对象中会存储SuspendedResourcesHolder,及挂起的事务信息,
// 当方法执行完后,将这个挂起从新设置到当前事务中来。
status = tm.getTransaction(txAttr);
}
// 省略...
}
// TODO 重点:将上面获取到的对象封装成TransactionInfo对象
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
}
|
源码内容很简单,首先获取事务,封装成 TransactionStatus,然后将 TransactionStatus 封装成 TransactionInfo 返回。
3.1 前一个方法未开启事务时的处理
重点来到 getTransaction(),这里定义了针对不同的传播行为,做了不同的处理:
源码如下:
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
|
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 获取事务对象
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 判断是否已经存在事务。如果当前事务对象已经持有了链接,并且事务是活跃状态,则表示已经存在事务。
// 如果当前已经存在事务,按照已存在事务的方式判断传播行为,进行处理
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
// TODO 如果当前已存在事务,会走到此方法逻辑进行处理。
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// TODO 以下是针对前一个方法未开启事务的情况的处理。
// 检测事务的超时时间设置是否正确
// Check definition settings for new transaction.
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// 如果传播属性是PROPAGATION_MANDATORY,且当前不存在事务,则抛出异常
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}// 如果传播属性是PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED时,会走到这里
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 因为以上三种事务传播属性的特性,这里会挂起(如果当前存在事务)
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建事务状态对象
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// TODO 重点:开启事务。按照当前测试代码注册的事务管理器,使用的是DataSourceTransactionManager
doBegin(transaction, definition);
// 如果是新开启的事务,设置事务管理器相关属性。其实走到这里的代码,一定是新启的事务。
// 因为前面已经判断了,如果存在事务,就走handleExistingTransaction方法
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// 以非事务方式运行 NEVER SUPPORTS NOT_SUPPORTED,在外围未开启事务时,会走这里。
// Create "empty" transaction: no actual transaction, but potentially synchronization.
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + definition);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
}
|
从上面源码中可以看到,getTransaction() 主要分为两个部分:
- 针对前一个方法(调用当前代理方法的方法),已经开启了事务的处理方式。
- 针对前一个方法,未开启事务的处理方式。
先看前一个方法未开启事务时,看以上源码中是怎么处理的。
- 检测事务的超时时间设置是否正确。(不能小于-1)
- 如果传播行为是 PROPAGATION_MANDATORY,直接抛出异常。(这也验证了,传播行为是 MADATORY 时,如果外围方法未开启事务,就抛出异常的行为。)
- 如果传播行为是 PROPAGATION_REQUIRED/PROPAGATION_REQUIRES_NEW/PROPAGATION_NESTED时,就挂起前一个事务(注意方法参数是null,也就是并没有事务挂起),然后调用 doBegin(),开启新的事务。
这三种传播行为,在前一个方法未开启事务时,都会新启一个事务。
- 如果传播行为是其余几种,则以非事务方式运行。所以参数中的事务对象传递的是null。
还有一个 prepareSynchronization 处理,这个是事务同步器的内容。它是对事务功能的扩展,可以在事务提交、异常回滚、及其他动作节点插入自定义的操作。在别的文章中列举。
3.2 判断前一个方法是否开启事务
上面源码中第一个方法 doGetTransaction(),是创建一个 DataSourceTransactionObject,在其中封装 ConnectionHolder,这个 ConnectionHolder 是从 TransactionSynchronizationManager中一个线程绑定的变量中获取的。
如果前一个方法开启了事务,它是有值的。
判断前一个方法中是否开启了事务正式基于此,如果 ConnectionHolder 有值,且 active 是true,说明它是开启了事务的。
以下是 doGetTransaction() 源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
public abstract class TransactionSynchronizationManager {
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
}
|
resource是一个与线程绑定的map,之所以要用map,是因为一个线程多个方法调用栈内,可能有多个数据源,它的键值就跟数据源相关。
判断前一个方法是否开启了事务的源码:
1
2
3
4
5
6
7
|
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
}
|
doGetTransaction() 中创建了一个DataSourceTransactionObject,内部封装了 ConnectionHolder,这个 ConnectionHolder 与线程绑定,所以在这里根据获取到的 ConnectionHolder,判断是否存在,且事务状态活跃。根据判断结果来确定前一个方法是否存在事务。
3.3 前一个方法开启事务时的处理
这段逻辑在 handleExistingTransaction(),源码如下:
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
|
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 如果当前方法传播属性为从不开启事务,直接抛出异常。
// PROPAGATION_NEVER特性决定,如果当前存在事务,则抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// PROPAGATION_NOT_SUPPORTED特性:如果当前存在事务,挂起当前事务,以非事务方式运行
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 挂起事务
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 返回事务状态对象
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// TODO 重点:PROPAGATION_REQUIRES_NEW特性:无论当前是否存在事务,都新建一个事务。
// 如果存在事务,将会把当前事务挂起,被挂起的事务会存储到新的事务状态对象中。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 挂起当前事务,由于PROPAGATION_REQUIRES_NEW的特性,需要使用新的事务,所以要将当前事务挂起,当新的事务执行完毕时,会恢复这个挂起的事务。
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// TODO 可以看到,这里创建事务对象时,构造函数中的参数newTransaction为true。
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// PROPAGATION_REQUIRES_NEW表示总是新启一个事务,这里会新开启事务。
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
// TODO PROPAGATION_NESTED嵌套事务,如果存在事务,则在嵌套事务中运行。如果不存在事务,则新建一个事务。
// 嵌套事务是用savePoint来实现的。具体过程:
// 1.新建事务状态对象时,会设置一个保存点(或者叫回滚点)。
// 2.如果业务方法执行抛出异常,则会被事务切面捕获,如果存在保存点,则会回滚值保存点。
// 3.正常执行完业务方法,如果这个方法对应的事务状态对象中具有保存点,则会擦除这个保存点。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
// 是否使用保存点,在测试中用到的事务管理器来看,总是返回true
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 创建savePoint,保存点(或者叫回滚点)
status.createAndHoldSavepoint();
return status;
}
else {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, null);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
}
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
// 省略无关代码...
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建事务状态对象,如果是新创建的事务,则设置事务管理器的相关属性。
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
}
|
源码中的流程:
- 如果方法中事务传播行为设置的是 PROPAGATION_NEVER,就抛出异常。(这也验证了,NEVER 传播行为,如果当前存在事务就抛出异常的行为。)
- 如果传播行为是 PROPAGATION_NOT_SUPPORTED,就挂起已存在的事务,创建TransactionStatus时,事务对象参数传递的是null。
- 如果传播行为是 PROPAGATION_REQUIRES_NEW,就挂起已存在的事务,并创建新的 TransactionStatus,这个TransactionStatus中封装了SuspendedResourcesHolder,这是前一个方法的事务信息,会在当前方法执行完毕后,还原为原来的事务对象。这里开启新的事务对象,是会重新获取连接的。
- 如果传播行为是 PROPAGATION_NESTED,创建 TransactionStatus 时,将已存在的事务封装进去,并标记一个回滚点。设置了回滚点的TransactionStatus,回滚时,只会回滚到这个标记处。
- 如果传播行为是其他的类型,调用prepareTransactionStatus,使用已存在的事务对象,包装成TransactionStatus,即加入到已存在的事务中。
4 事务的开启
从上面的代码中,已经知道了事务开启是通过 doBegin()。
以下是 doBegin() 源码:
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
|
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
implements ResourceTransactionManager, InitializingBean {
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
// 如果当前事务对象没有持有链接,就获取一个,并设置到链接持有变量中。
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
// 设置事务同步为true,标识使用了事务。
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
// 获取数据库连接对象。
con = txObject.getConnectionHolder().getConnection();
// 设置事务隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// TODO 重点:开启事务核心点:将事务自动提交关闭。即手动提交事务(由spring控制事务提交)
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
// 如果Transaction中配置了只读,这里会将事务设置为只读属性
prepareTransactionalConnection(con, definition);
// 在事务链接持有对象中,设置事务活跃状态为true
txObject.getConnectionHolder().setTransactionActive(true);
// 查找配置的事务超时时间,如果未配置,会使用默认的。默认值为-1,表示永不超时。
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
// 在链接持有对象中设置超时时间,从这里可以看出,单位是秒。
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// 如果事务对象是在当前代理方法中new的,则绑定到ThreadLocal变量中。
// Bind the connection holder to the thread.
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
// 如果出现异常,释放数据库连接对象。
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
}
|
方法第一次执行时,肯定是没有连接的。首先,获取到一个数据库连接。并将这个链接封装成 ConnectionHolder,添加到 DataSourceTransactionObject 中。
获取到链接对象,设置事务隔离级别、超时时间等信息。最关键的一行代码是 con.setAutoCommit(false)
,将自动提交关闭,改为手动提交事务。在后面的流程,调用代理方法后,根据执行结果进行事务提交或回滚。