1.引
上一節(jié)分析了Spring實現(xiàn)事物管理的步驟纸型,本篇分析Spring事物的創(chuàng)建過程叫编。
2.事物創(chuàng)建方法簡析
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr,
final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
// 1. 如果沒有指定名稱援雇,則應(yīng)用方法標識作為事務(wù)名稱枷莉。
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) {
// 重點: 根據(jù)指定的傳播行為臣嚣,返回當前活動的事務(wù)或創(chuàng)建新事務(wù)净刮。
status = tm.getTransaction(txAttr);
} else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
// 3.創(chuàng)建TransactionInfo對象
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
最重要的是TransactionStatus對象的獲取過程,以及創(chuàng)建TransactionInfo對象硅则,下面分別單獨介紹淹父。
3.獲取TransactionStatus對象,即Spring事物創(chuàng)建過程簡析
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
// 1.獲取當前事物對象(如果當前已經(jīng)存在了事物)
Object transaction = doGetTransaction();
// Cache debug flag to avoid repeated checks.
boolean debugEnabled = logger.isDebugEnabled();
// 如果TransactionDefinition為空,默認創(chuàng)建DefaultTransactionDefinition對象
if (definition == null) {
// Use defaults if no transaction definition given.
definition = new DefaultTransactionDefinition();
}
// 2.如果當前已經(jīng)存在事物
// 重點:
// 如果當前已經(jīng)存在啟動的事物,則根據(jù)本次要新建的事物傳播特性進行評估,以決定對新事物的后續(xù)處理
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,則拋出異常(因為當前事物還沒創(chuàng)建結(jié)束并開啟...)
// PROPAGATION_MANDATORY --> 使用當前事物怎虫,如果當前沒有事物暑认,則拋出異常。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
}
// 3.3 如果事物傳播特性為以下三種,則創(chuàng)建新的事物:
// PROPAGATION_REQUIRED --> 如果當前沒有事物大审,則新建一個事物蘸际;如果已經(jīng)存在一個事物,則加入到這個事物中徒扶。
// PROPAGATION_REQUIRES_NEW --> 新建事物粮彤,如果當前已經(jīng)存在事物,則掛起當前事物姜骡。
// PROPAGATION_NESTED --> 如果當前存在事物导坟,則在嵌套事物內(nèi)執(zhí)行;如果當前沒有事物圈澈,則與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) {
// 從日志打印,也可以看見當前要創(chuàng)建一個名為definition.getName()的新事物了...
logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
}
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 創(chuàng)建DefaultTransactionStatus對象實例
DefaultTransactionStatus status = newTransactionStatus(
definition,
transaction,
true,
newSynchronization,
debugEnabled,
suspendedResources);
// 開啟事物
doBegin(transaction, definition);
// 初始化事務(wù)同步惫周。
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
// 3.4 對于其他的三種傳播特性,無需開啟新的事物
// PROPAGATION_SUPPORTS --> 支持當前事物,如果當前沒有事物康栈,則以非事物方式執(zhí)行
// PROPAGATION_NOT_SUPPORTED --> 以非事物方式執(zhí)行闯两,如果當前存在事物,則掛起當前事物
// PROPAGATION_NEVER --> 以非事物方式執(zhí)行谅将,如果當前存在事物,則拋出異常
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事物最最關(guān)鍵重慢、最最核心的方法了饥臂。對于這里比較重要的的方法,逐個分析似踱。隅熙。。
3.1獲取當前事物對象(如果當前已經(jīng)存在了事物)
對于不同的事物管理器核芽,獲取的方法也是不同的囚戚,本例使用的是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 如果當前已經(jīng)存在事物
這里,涉及到事物嵌套轧简,留在后面單獨分析驰坊。。哮独。
3.3 如果當前不存在事物
這里就不會涉及到事物的嵌套處理了拳芙,分析起來也比較簡單點察藐,接下來的處理就是要根據(jù)我們配置的事物傳播特性,去逐個分析了
3.3.1 超時時間處理
很簡單舟扎,如果自定義的超時時間小于默認的超時時間分飞,則拋出異常
3.3.2 處理PROPAGATION_MANDATORY傳播特性
如果我們定義的事物傳播特性為PROPAGATION_MANDATORY,那么這里會拋出異常睹限,因為當前沒有事物譬猫,或者說事物還在創(chuàng)建中。而PROPAGATION_MANDATORY特性是:使用當前事物羡疗,如果當前沒有事物染服,則拋出異常。
3.3.3 處理PROPAGATION_REQUIRED顺囊、PROPAGATION_REQUIRES_NEW肌索、PROPAGATION_NESTED傳播特性
先來回顧一下這三種傳播特性:
PROPAGATION_REQUIRED --> 如果當前沒有事物,則新建一個事物特碳;如果已經(jīng)存在一個事物诚亚,則加入到這個事物中。
PROPAGATION_REQUIRES_NEW --> 新建事物午乓,如果當前已經(jīng)存在事物站宗,則掛起當前事物。
PROPAGATION_NESTED --> 如果當前存在事物益愈,則在嵌套事物內(nèi)執(zhí)行梢灭;如果當前沒有事物,則與PROPAGATION_REQUIRED傳播特性相同
因為當前不存在事物蒸其,根據(jù)這幾種特性敏释,在這里就要新建事物了,代碼片段:
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 創(chuàng)建DefaultTransactionStatus對象實例
DefaultTransactionStatus status = newTransactionStatus(
definition,
transaction,
true,
newSynchronization,
debugEnabled,
suspendedResources);
// 開啟事物
doBegin(transaction, definition);
// 初始化事務(wù)同步摸袁。
prepareSynchronization(status, definition);
return status;
}
小分支太多了钥顽,下面單獨在開一篇介紹吧。靠汁。蜂大。
3.3.4 處理PROPAGATION_SUPPORTS捐下、PROPAGATION_NOT_SUPPORTED锁保、PROPAGATION_NEVER傳播特性
回顧一下這三種特性:
PROPAGATION_SUPPORTS --> 支持當前事物寂汇,如果當前沒有事物蚊丐,則以非事物方式執(zhí)行
PROPAGATION_NOT_SUPPORTED --> 以非事物方式執(zhí)行桌粉,如果當前存在事物绷雏,則掛起當前事物
PROPAGATION_NEVER --> 以非事物方式執(zhí)行紊遵,如果當前存在事物窄绒,則拋出異常
因為當前不存在事物,根據(jù)這幾種特性耳高,無需開啟真正的事物扎瓶。
4.創(chuàng)建TransactionInfo對象
這里我們假設(shè)事物已經(jīng)創(chuàng)建完成了(上一步?jīng)]有分析事物具體的創(chuàng)建過程,留在下一篇介紹)泌枪,接下來就要創(chuàng)建TransactionInfo對象了概荷,該對象持有了上一步創(chuàng)建的事物信息。
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr,
String joinpointIdentification,
@Nullable TransactionStatus status) {
// 創(chuàng)建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;
}
基本上就是簡單的賦值操作误证,并在最后將創(chuàng)建的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");
本篇的分析就到此了蓝谨,因為這里的分支實在是太多,還是多開幾篇吧青团!