回到上一章的invokeWithinTransaction方法,我們來看看事物的回滾方法completeTransactionAfterThrowing
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
//當(dāng)拋出異常時(shí)首先判斷當(dāng)前是否存在事務(wù)
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
//rollbackOn (ex instanceof RuntimeException || ex instanceof Error);
//判斷異常類型
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
//根據(jù) TransactionStatus 信息進(jìn)行回滾處理
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
//如果不滿足回滾條件即使拋出異常也同樣會提交
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException | Error ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
}
}
}
這里看一個(gè)rollbackOn方法行冰,這個(gè)方法用來判斷異常類型
默認(rèn)情況下Spring中的亊務(wù)異常處理機(jī)制只對RuntimeException和Error兩種情況感興趣肛走,我們可以利用注解方式來改變葫男,例如:
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
@Override
public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}
然后看看rollback方法
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
//如果事務(wù)已經(jīng)完成.那么同次回滾會拋出異常
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, false);
}
再看看processRollback方法
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
try {
boolean unexpectedRollback = unexpected;
try {
//激活
triggerBeforeCompletion(status);
//如果有保存點(diǎn) 當(dāng)前事務(wù)為單獨(dú)的線程則會退到保存點(diǎn)
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Rolling back transaction to savepoint");
}
status.rollbackToHeldSavepoint();
}
//如果當(dāng)前事務(wù)為獨(dú)立的新事務(wù) 鱼响,則直接回退
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction rollback");
}
doRollback(status);
}
else {
// Participating in larger transaction
//如果不是獨(dú)立的事務(wù),那么只標(biāo)記狀態(tài),等到事務(wù)鏈執(zhí)行完畢后統(tǒng)一回滾
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");
}
// Unexpected rollback only matters here if we're asked to fail early
if (!isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = false;
}
}
}
catch (RuntimeException | Error ex) {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
throw ex;
}
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
// Raise UnexpectedRollbackException if we had a global rollback-only marker
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction rolled back because it has been marked as rollback-only");
}
}
finally {
//清空記錄 并將掛起的資源恢復(fù)
cleanupAfterCompletion(status);
}
}
首先直接看下doRollback方法
@Override
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
//數(shù)據(jù)庫的回滾方法
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
可以看到事務(wù)的回滾,其實(shí)底層還是依靠的數(shù)據(jù)庫的回滾操作