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<TransactionInfo> transactionInfoHolder = new NamedThreadLocal<>("Current aspect-driven transaction");
本篇的分析就到此了,因为这里的分支实在是太多,还是多开几篇吧!