Spring 源碼分析之事務(wù)
Spring 源碼分析之事務(wù)2 TransactionStatus與TransactionInfo
Spring 源碼分析之事務(wù)3 事務(wù)的提交與回滾
我們回顧一下事務(wù)處理的入口邏輯,代碼如下:
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
......
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
//一:創(chuàng)建事務(wù)
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//二:調(diào)用業(yè)務(wù):
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
//三:目標(biāo)方法發(fā)生異常的處理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//四:恢復(fù)當(dāng)前的事務(wù)信息對象也就是TransactionInfo
cleanupTransactionInfo(txInfo);
}
......
//五:提交事務(wù)
commitTransactionAfterReturning(txInfo);
return retVal;
}
......
}
今天我們重點(diǎn)關(guān)注第三、四、五步所到的事情。
一、第三步目標(biāo)方法發(fā)生異常的處理completeTransactionAfterThrowing(txInfo, ex)
這里的業(yè)務(wù)邏輯比較簡單:主要就是判斷目標(biāo)發(fā)生發(fā)生的異常類型是不是RuntimeException || ex instanceof Error,如果是就回滾事務(wù),如果不是,則繼續(xù)提交事務(wù)。
源碼如下:
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
//如果txInfo.transactionAttribute.rollbackOn(ex)為true,就回滾,否則進(jìn)入else語塊,執(zhí)行commit操作
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
......
}
}
txInfo.transactionAttribute.rollbackOn(ex)源碼如下:
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
二、第四步恢復(fù)當(dāng)前的事務(wù)信息對象也就是TransactionInfo,cleanupTransactionInfo()
不管目標(biāo)方法執(zhí)行是否正常不管拋不拋異常,都進(jìn)入finally,恢復(fù)TransactionInfo
源碼如下:
/**
* Reset the TransactionInfo ThreadLocal.
* <p>Call this in all cases: exception or normal return!
* @param txInfo information about the current transaction (may be {@code null})
*/
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
這個時候調(diào)用的就是當(dāng)前TransactionInfo 的restoreThreadLocalStatus方法。源碼如下:
private void restoreThreadLocalStatus() {
// Use stack to restore old transaction TransactionInfo.
// Will be null if none was set.
transactionInfoHolder.set(this.oldTransactionInfo);
}
不清楚TransactionInfo 的可以看看我寫的spring源碼分析之事務(wù)2
三、第五步提交事務(wù)commitTransactionAfterReturning(txInfo);
如果目標(biāo)方法執(zhí)行沒有問題,則會進(jìn)入事務(wù)的最后一個階段:提交事務(wù)。
commitTransactionAfterReturning()邏輯如下,看到commit方法我們就放心了:
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
查看commit源碼
@Override
public final void commit(TransactionStatus status) throws TransactionException {
......
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//一、如果當(dāng)前事務(wù)設(shè)置了回滾,那么這里就執(zhí)行事務(wù)的回滾操作。
if (defStatus.isLocalRollbackOnly()) {
processRollback(defStatus, false);
return;
}
//二、查看全局事務(wù)是否標(biāo)記為了回滾,如果標(biāo)記了則回滾,
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
// 三、提交事務(wù)
processCommit(defStatus);
}
重點(diǎn)看第三步驟processCommit()
/**
* Process an actual commit.
* Rollback-only flags have already been checked and applied.
* @param status object representing the transaction
* @throws TransactionException in case of commit failure
*/
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
prepareForCommit(status);
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
//業(yè)務(wù)執(zhí)行完畢之后,如果設(shè)置有回滾點(diǎn),先釋放回滾點(diǎn),業(yè)務(wù)執(zhí)行ok,回滾點(diǎn)也沒有存在的意義了。
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) { // 判斷當(dāng)前事務(wù)是否是新事務(wù),如果是新事務(wù),就提交事務(wù)
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
//此處提交事務(wù),跟進(jìn)doCommit方法內(nèi)部,會發(fā)現(xiàn)調(diào)用的是java.sql.Connection對象的commit方法。
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
......
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
//事務(wù)提交之后的一些回調(diào)
try {
triggerAfterCommit(status);
}
finally {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
//事務(wù)處理完畢之后做一些清除或恢復(fù)工作
cleanupAfterCompletion(status);
}
}
看下cleanupAfterCompletion()方法。
/**
* Clean up after completion, clearing synchronization if necessary,
* and invoking doCleanupAfterCompletion.
* @param status object representing the transaction
* @see #doCleanupAfterCompletion
*/
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
//第一步:設(shè)置當(dāng)前事務(wù)狀態(tài)已經(jīng)完成
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
//第二步:如果是提交事務(wù)完畢,則移除當(dāng)前線程所持有的Connection 連接,即釋放連接
doCleanupAfterCompletion(status.getTransaction());
}
//第三步:如果是當(dāng)前事務(wù)中有掛起的資源,則在當(dāng)前事務(wù)執(zhí)行完畢之后,恢復(fù)掛起的資源
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());
}
}
至此spring 事務(wù)的分析也差不多完成了,細(xì)節(jié)方面的自己看下源碼就清楚了。