(十一)Spring事務處理
阿新 • • 發佈:2019-01-30
Spring的宣告式事務處理的即開即用特性為使用者提供了很大的方便,在使用Spring時,我們絕大多數情況下還是使用其宣告式事務處理。宣告式事務處理涉及Spring框架對事務處理的統一管理,以及對併發事務和事務屬性的處理,是一個比較複雜的過程,下面瞭解一下Spring框架宣告式事務處理功能的具體實現。
一、事務的建立
前一篇文章講到對Spring事務攔截器TransactionInterceptor回撥方法invoke的原始碼分析中,我們瞭解到在進行事務處理前,首先根據是否是CallbackPreferringPlatformTransactionManager型別的事務處理器分別通過下面兩個方法建立事務資訊物件:
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
二、事務的掛起
如果當前執行緒存在事務,但事務傳播特性又要求開啟新事務時,需要將已有的事務進行掛起,事務的掛起涉及執行緒與事務資訊的儲存,實現原始碼如下:
protected final SuspendedResourcesHolder suspend(Object transaction) throws TransactionException { //如果事務是啟用的,且當前執行緒事務同步機制也是啟用狀態 if (TransactionSynchronizationManager.isSynchronizationActive()) { //掛起當前執行緒中所有同步的事務 List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization(); try { Object suspendedResources = null; //把掛起事務的操作交由具體的事務處理器處理 if (transaction != null) { suspendedResources = doSuspend(transaction); } //線上程中儲存與事務處理有關的資訊,並將執行緒裡有關的執行緒區域性變數重置 String name = TransactionSynchronizationManager.getCurrentTransactionName(); //重置當前執行緒中事務相關的執行緒區域性變數 TransactionSynchronizationManager.setCurrentTransactionName(null); boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly(); TransactionSynchronizationManager.setCurrentTransactionReadOnly(false); Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel(); TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null); boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive(); TransactionSynchronizationManager.setActualTransactionActive(false); //將當前執行緒中事務相關資訊儲存 return new SuspendedResourcesHolder( suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive); } //對事務掛起操作中產生異常和錯誤的處理 catch (RuntimeException ex) { doResumeSynchronization(suspendedSynchronizations); throw ex; } catch (Error err) { doResumeSynchronization(suspendedSynchronizations); throw err; } } //如果事務是啟用的,但是事務同步機制不是啟用的,則只需要儲存事務狀態,不 //需要重置事務相關的執行緒區域性變數 else if (transaction != null) { Object suspendedResources = doSuspend(transaction); return new SuspendedResourcesHolder(suspendedResources); } //事務和事務同步機制都不是啟用的,則不要想處理 else { return null; } }
三、事務的提交
當事務方法處理成功之後,需要將當前事務提交,將更改同步到資料庫中,事務提交的實現原始碼如下:
public final void commit(TransactionStatus status) throws TransactionException { //如果事務的執行狀態已經結束,則丟擲異常 if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; //如果事務執行狀態時回滾 if (defStatus.isLocalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Transactional code has requested rollback"); } //處理事務回滾 processRollback(defStatus); return; } //如果事務沒有被標記為回滾時提交,且事務狀態時全域性回滾 if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); } //回滾處理 processRollback(defStatus); //如果事務狀態時新事務,或者在全域性回滾時失敗 if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) { throw new UnexpectedRollbackException( "Transaction rolled back because it has been marked as rollback-only"); } return; } //處理提交 processCommit(defStatus); } //提交處理操作 private void processCommit(DefaultTransactionStatus status) throws TransactionException { try { boolean beforeCompletionInvoked = false; try { //事務提交的準備工作,有具體的事務處理器完成 prepareForCommit(status); triggerBeforeCommit(status); triggerBeforeCompletion(status); beforeCompletionInvoked = true; boolean globalRollbackOnly = false; //如果事務狀態是新事務,或者全域性回滾失敗 if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) { //設定事務全域性回滾 globalRollbackOnly = status.isGlobalRollbackOnly(); } //巢狀事務處理 if (status.hasSavepoint()) { if (status.isDebug()) { logger.debug("Releasing transaction savepoint"); } //釋放掛起事務儲存點 status.releaseHeldSavepoint(); } //如果當前事務是新事務 else if (status.isNewTransaction()) { if (status.isDebug()) { logger.debug("Initiating transaction commit"); } //呼叫具體事務處理器提交事務 doCommit(status); } //如果事務被標記為全域性回滾 if (globalRollbackOnly) { throw new UnexpectedRollbackException( "Transaction silently rolled back because it has been marked as rollback-only"); } } //提交過程中產生未預期的回滾異常,則回滾處理 catch (UnexpectedRollbackException ex) { triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK); throw ex; } //對提交過程中產生的事務異常處理 catch (TransactionException ex) { //如果回滾失敗,則進行回滾異常處理 if (isRollbackOnCommitFailure()) { doRollbackOnCommitException(status, ex); } else { triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN); } throw ex; } //對提交過程中產生的異常處理 catch (RuntimeException ex) { //如果不是在完成前呼叫的 if (!beforeCompletionInvoked) { //觸發完成前的回撥方法 triggerBeforeCompletion(status); } //進行回滾異常處理 doRollbackOnCommitException(status, ex); throw ex; } //對提交過程中產生的錯誤處理 catch (Error err) { if (!beforeCompletionInvoked) { triggerBeforeCompletion(status); } doRollbackOnCommitException(status, err); throw err; } //觸發提交之後的回撥操作 try { triggerAfterCommit(status); } finally { triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED); } } //提交完成之後清除事務相關狀態 finally { cleanupAfterCompletion(status); } }
四、事務的回滾
當在事務處理過程中產生異常,或者提交失敗時,往往需要對資料庫中已有的更改做回滾操作,即恢復到操作之前的狀態,回滾的實現程式碼如下:
public final void rollback(TransactionStatus status) throws TransactionException {
//如果事務狀態已完成,則丟擲異常
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
//處理回滾的操作
processRollback(defStatus);
}
//回滾操作
private void processRollback(DefaultTransactionStatus status) {
try {
try {
//觸發完成前的回撥操作
triggerBeforeCompletion(status);
//巢狀事務回滾處理
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
//回滾掛起在儲存點的事務
status.rollbackToHeldSavepoint();
}
//當前事務中建立新事務的回滾操作
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
//回滾處理,由具體的事務處理器實現
doRollback(status);
}
//如果在當前事務中沒有新建事務
else if (status.hasTransaction()) {
//如果當前事務狀態為本地回滾,或全域性回滾失敗
if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
if (status.isDebug()) {
logger.debug(
"Participating transaction failed - marking existing transaction as rollback-only");
}
//設定當前事務狀態為回滾
doSetRollbackOnly(status);
}
//當前事務狀態沒有設定為本地回滾,且沒有產生全域性回滾失敗,則
//由執行緒中的前一個事務來處理回滾,這個步驟任何處理
else {
if (status.isDebug()) {
logger.debug(
"Participating transaction failed - letting transaction originator decide on rollback");
}
}
}
//如果當前執行緒沒有事務
else {
logger.debug("Should roll back transaction but cannot - no transaction available");
}
}
//對回滾操作過程中的執行時異常和錯誤的處理
catch (RuntimeException ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
catch (Error err) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw err;
}
//回滾操作完成後,觸發回滾之後回撥操作
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
}
//清除回滾之後事務狀態資訊
finally {
cleanupAfterCompletion(status);
}
}