1.引
上一节分析了Spring实现事物管理的步骤,本篇分析Spring事物的创建过程。
2.事物创建方法简析
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr,
final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
// 1. 如果没有指定名称,则应用方法标识作为事务名称。
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
// 2.获取TransactionStatus对象
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 重点: 根据指定的传播行为,返回当前活动的事务或创建新事务。
status = tm.getTransaction(txAttr);
} else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 3.创建TransactionInfo对象
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
最重要的是TransactionStatus对象的获取过程,以及创建TransactionInfo对象,下面分别单独介绍。
3.获取TransactionStatus对象,即Spring事物创建过程简析
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 1.获取当前事物对象(如果当前已经存在了事物)
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
// 如果TransactionDefinition为空,默认创建DefaultTransactionDefinition对象
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 2.如果当前已经存在事物
// 重点:
// 如果当前已经存在启动的事物,则根据本次要新建的事物传播特性进行评估,以决定对新事物的后续处理
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 3.如果当前不存在事物
// Check definition settings for new transaction.
// 3.1 如果事物定义的超时时间,小于默认的超时时间,抛出异常,TransactionDefinition.TIMEOUT_DEFAULT --> -1
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
// 3.2 如果当前事物特性为PROPAGATION_MANDATORY,则抛出异常(因为当前事物还没创建结束并开启...)
// PROPAGATION_MANDATORY --> 使用当前事物,如果当前没有事物,则抛出异常。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 3.3 如果事物传播特性为以下三种,则创建新的事物:
// PROPAGATION_REQUIRED --> 如果当前没有事物,则新建一个事物;如果已经存在一个事物,则加入到这个事物中。
// PROPAGATION_REQUIRES_NEW --> 新建事物,如果当前已经存在事物,则挂起当前事物。
// PROPAGATION_NESTED --> 如果当前存在事物,则在嵌套事物内执行;如果当前没有事物,则与PROPAGATION_REQUIRED传播特性相同
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED
|| definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW
|| definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
// 从日志打印,也可以看见当前要创建一个名为definition.getName()的新事物了...
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建DefaultTransactionStatus对象实例
DefaultTransactionStatus status = newTransactionStatus(
definition,
transaction,
true,
newSynchronization,
debugEnabled,
suspendedResources);
// 开启事物
doBegin(transaction, definition);
// 初始化事务同步。
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
// 3.4 对于其他的三种传播特性,无需开启新的事物
// PROPAGATION_SUPPORTS --> 支持当前事物,如果当前没有事物,则以非事物方式执行
// PROPAGATION_NOT_SUPPORTED --> 以非事物方式执行,如果当前存在事物,则挂起当前事物
// PROPAGATION_NEVER --> 以非事物方式执行,如果当前存在事物,则抛出异常
else {
// 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);
}
}
该方法可以说是Spring事物最最关键、最最核心的方法了。对于这里比较重要的的方法,逐个分析。。。
3.1获取当前事物对象(如果当前已经存在了事物)
对于不同的事物管理器,获取的方法也是不同的,本例使用的是DataSourceTransactionManager
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
// 是否允许使用保存点
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 从当前线程中获取ConnectionHolder对象
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
3.2 如果当前已经存在事物
这里,涉及到事物嵌套,留在后面单独分析。。。
3.3 如果当前不存在事物
这里就不会涉及到事物的嵌套处理了,分析起来也比较简单点,接下来的处理就是要根据我们配置的事物传播特性,去逐个分析了
3.3.1 超时时间处理
很简单,如果自定义的超时时间小于默认的超时时间,则抛出异常
3.3.2 处理PROPAGATION_MANDATORY传播特性
如果我们定义的事物传播特性为PROPAGATION_MANDATORY,那么这里会抛出异常,因为当前没有事物,或者说事物还在创建中。而PROPAGATION_MANDATORY特性是:使用当前事物,如果当前没有事物,则抛出异常。
3.3.3 处理PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED传播特性
先来回顾一下这三种传播特性:
PROPAGATION_REQUIRED --> 如果当前没有事物,则新建一个事物;如果已经存在一个事物,则加入到这个事物中。
PROPAGATION_REQUIRES_NEW --> 新建事物,如果当前已经存在事物,则挂起当前事物。
PROPAGATION_NESTED --> 如果当前存在事物,则在嵌套事物内执行;如果当前没有事物,则与PROPAGATION_REQUIRED传播特性相同
因为当前不存在事物,根据这几种特性,在这里就要新建事物了,代码片段:
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 创建DefaultTransactionStatus对象实例
DefaultTransactionStatus status = newTransactionStatus(
definition,
transaction,
true,
newSynchronization,
debugEnabled,
suspendedResources);
// 开启事物
doBegin(transaction, definition);
// 初始化事务同步。
prepareSynchronization(status, definition);
return status;
}
小分支太多了,下面单独在开一篇介绍吧。。。
3.3.4 处理PROPAGATION_SUPPORTS、PROPAGATION_NOT_SUPPORTED、PROPAGATION_NEVER传播特性
回顾一下这三种特性:
PROPAGATION_SUPPORTS --> 支持当前事物,如果当前没有事物,则以非事物方式执行
PROPAGATION_NOT_SUPPORTED --> 以非事物方式执行,如果当前存在事物,则挂起当前事物
PROPAGATION_NEVER --> 以非事物方式执行,如果当前存在事物,则抛出异常
因为当前不存在事物,根据这几种特性,无需开启真正的事物。
4.创建TransactionInfo对象
这里我们假设事物已经创建完成了(上一步没有分析事物具体的创建过程,留在下一篇介绍),接下来就要创建TransactionInfo对象了,该对象持有了上一步创建的事物信息。
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr,
String joinpointIdentification,
@Nullable TransactionStatus status) {
// 创建TransactionInfo对象
TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
// 如果事物标签不为空,则将TransactionStatus对象赋予TransactionInfo
if (txAttr != null) {
// We need a transaction for this method...
if (logger.isTraceEnabled()) {
logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// The transaction manager will flag an error if an incompatible tx already exists.
txInfo.newTransactionStatus(status);
} else {
// The TransactionInfo.hasTransaction() method will return false. We created it only
// to preserve the integrity of the ThreadLocal stack maintained in this class.
if (logger.isTraceEnabled()) {
logger.trace("Don't need to create transaction for [" + joinpointIdentification + "]: This method isn't transactional.");
}
}
// We always bind the TransactionInfo to the thread, even if we didn't create
// a new transaction here. This guarantees that the TransactionInfo stack
// will be managed correctly even if no transaction was created by this aspect.
// 这里:不论是否开启了新的事物,都将TransactionInfo绑定到当前线程,以保证TransactionInfo堆栈的完整性。
txInfo.bindToThread();
return txInfo;
}
基本上就是简单的赋值操作,并在最后将创建的TransactionInfo绑定到当前线程。注意,在绑定过程中,当前事物信息是会获取已有的事物信息并一起绑定到transactionInfoHolder变量的。这样就可能会形成一个事物链。
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing TransactionStatus
// for restoration after this transaction is complete.
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}
其中transactionInfoHolder是个ThreadLocal类型的变量:
private static final ThreadLocal transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction");
本篇的分析就到此了,因为这里的分支实在是太多,还是多开几篇吧!