前言
Spring在TransactionDefinition接口中規(guī)定了7種類型的事務(wù)傳播行為,它們規(guī)定了事務(wù)方法和事務(wù)方法發(fā)生嵌套調(diào)用時(shí)事務(wù)如何進(jìn)行傳播,即協(xié)調(diào)已經(jīng)有事務(wù)標(biāo)識(shí)的方法之間的發(fā)生調(diào)用時(shí)的事務(wù)上下文的規(guī)則(是否要有獨(dú)立的事務(wù)隔離級(jí)別和鎖)。
概述
當(dāng)我們調(diào)用一個(gè)基于Spring的Service接口的事務(wù)方法(如UserService#addUser())時(shí),它將運(yùn)行于Spring管理的事務(wù)環(huán)境中,Service接口方法可能會(huì)在內(nèi)部調(diào)用其它的Service接口方法以共同完成一個(gè)完整的業(yè)務(wù)操作,因此就會(huì)產(chǎn)生服務(wù)接口方法嵌套調(diào)用的情況, Spring通過事務(wù)傳播行為控制當(dāng)前的事務(wù)如何傳播到被嵌套調(diào)用的目標(biāo)服務(wù)接口方法中。
事務(wù)傳播是Spring進(jìn)行事務(wù)管理的重要概念,其重要性怎么強(qiáng)調(diào)都不為過。但是事務(wù)傳播行為也是被誤解最多的地方,在本文里,我們將詳細(xì)分析不同事務(wù)傳播行為的表現(xiàn)形式,掌握它們之間的區(qū)別。
事務(wù)傳播行為種類
PROPAGATION_REQUIRED:如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù),如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中。這是最常見的選擇。
配置方式:TransactionDefinition.PROPAGATION_REQUIREDPROPAGATION_SUPPORTS:支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。
配置方式:TransactionDefinition.PROPAGATION_SUPPORTSPROPAGATION_MANDATORY:使用當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。
配置方式:TransactionDefinition.PROPAGATION_MANDATORYPROPAGATION_REQUIRES_NEW:新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。
配置方式:TransactionDefinition.PROPAGATION_REQUIRES_NEWPROPAGATION_NOT_SUPPORTED:以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。
配置方式:TransactionDefinition.PROPAGATION_NOT_SUPPORTEDPROPAGATION_NEVER:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。
配置方式:TransactionDefinition.PROPAGATION_NEVERPROPAGATION_NESTED:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則執(zhí)行與PROPAGATION_REQUIRED類似的操作。
配置方式:TransactionDefinition.PROPAGATION_NESTED

首先我們要明確幾點(diǎn)基本知識(shí):
1、事務(wù)傳播機(jī)制只適用于不同bean之間方法的調(diào)用,如果一個(gè)bean中的兩個(gè)方法互相調(diào)用并不會(huì)使用到事務(wù)傳播。比如,一個(gè)bean的method1的事務(wù)傳播級(jí)別為Required,method2的事務(wù)傳播級(jí)別為Never,我們在method1里面調(diào)用method2。首先method1會(huì)開啟一個(gè)事務(wù),而method2也沒有報(bào)錯(cuò)并正確執(zhí)行了,而且也在method1開啟的事務(wù)之中,說明事務(wù)傳播機(jī)制在一個(gè)bean自己的方法互相調(diào)用中并不起作用,只要一個(gè)方法開啟了事務(wù),那這個(gè)在方法里調(diào)用當(dāng)前bean的其他方法都在這個(gè)事務(wù)中運(yùn)行,而不管其他方法的事務(wù)傳播機(jī)制是如何配置的。
2、事務(wù)方法里如果拋RuntimeException,則會(huì)導(dǎo)致所有相關(guān)事務(wù)回滾,個(gè)別事務(wù)傳播機(jī)制有點(diǎn)特殊,我們下面會(huì)講到。
3、事務(wù)方法里如果拋Throwable或者Exception,默認(rèn)不會(huì)導(dǎo)致相關(guān)事務(wù)回滾,一般都會(huì)在出異常的地方提交,就有可能出現(xiàn)部分提交的問題。但可以配置rollback-for屬性來控制。
源碼解析:AbstractPlatformTransactionManager
- 事務(wù)的傳播特性源碼主要位于AbstractPlatformTransactionManager類的handleExistingTransaction方法中。
PROPAGATION_NEVER
- 該特性規(guī)定了以非事物方式執(zhí)行,如果當(dāng)前存在事物,則拋出異常。
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 1.PROPAGATION_NEVER --> 以非事物方式執(zhí)行,如果當(dāng)前存在事物,則拋出異常。
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
......
}
PROPAGATION_NOT_SUPPORTED
- 該特性規(guī)定了以非事物方式執(zhí)行,如果當(dāng)前存在事物,則掛起當(dāng)前事物。
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 重點(diǎn):掛起已有事物
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 創(chuàng)建新事物,注意:transaction參數(shù)為null,所以這里創(chuàng)建的不是一個(gè)真正的事物
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
......
}
這里又涉及到一個(gè)概念,事務(wù)掛起(這個(gè)前面沒有介紹,因?yàn)榍懊娑际菃蝹€(gè)事物)。下面分析一下事物掛起的流程:
@Nullable
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
// 1.如果存在事物同步回調(diào)接口
if (TransactionSynchronizationManager.isSynchronizationActive()) {
// 1.1 掛起事務(wù)同步回調(diào)接口
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
// 掛起事物
Object suspendedResources = null;
if (transaction != null) {
suspendedResources = doSuspend(transaction);
}
// 獲取已有事物名稱
String name = TransactionSynchronizationManager.getCurrentTransactionName();
// 清空已有事物名稱
TransactionSynchronizationManager.setCurrentTransactionName(null);
// 獲取已有事物的readOnly屬性值
boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
// 將已有事物的readOnly屬性值設(shè)置為false
TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);
// 獲取已有事物數(shù)據(jù)庫事物隔離級(jí)別
Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
// 清空已有事物數(shù)據(jù)庫事物隔離級(jí)別
TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);
// 獲取已有事物激活標(biāo)識(shí)
boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();
// 將當(dāng)前事物激活標(biāo)識(shí)設(shè)置為false
TransactionSynchronizationManager.setActualTransactionActive(false);
//將上面獲取到的一系列事物屬性,重新封裝至SuspendedResourcesHolder對(duì)象,并返回
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
// 不存在事物同步回調(diào)接口,且當(dāng)前事物不為空
else if (transaction != null) {
// Transaction active but no synchronization active.
// 事物已經(jīng)被激活,但是沒有事物同步回調(diào),則直接掛起當(dāng)前事物即可
Object suspendedResources = doSuspend(transaction);
// 返回掛起的事物資源
return new SuspendedResourcesHolder(suspendedResources);
}
// 處理沒有事物的情況...
else {
// Neither transaction nor synchronization active.
return null;
}
}
首先來看事物同步回調(diào)接口,該接口會(huì)在prepareSynchronization方法中設(shè)置,即使我們沒有自定義事物同步回調(diào)接口,Spring默認(rèn)也會(huì)為當(dāng)前事物創(chuàng)建一個(gè)空的事物同步回調(diào)接口。關(guān)于該接口的使用,可以參考上一節(jié)中的例子。(注意:事物同步回調(diào)接口是與當(dāng)前線程綁定的)。下面看事物同步接口是如何掛起的:
private List<TransactionSynchronization> doSuspendSynchronization() {
// 1.獲取當(dāng)前線程的所有事物同步回調(diào)
List<TransactionSynchronization> suspendedSynchronizations =
TransactionSynchronizationManager.getSynchronizations();
// 2.循環(huán)并掛起所有同步回調(diào)接口
for (TransactionSynchronization synchronization : suspendedSynchronizations) {
synchronization.suspend();
}
// 3.清除資源
TransactionSynchronizationManager.clearSynchronization();
return suspendedSynchronizations;
}
其次來看掛起事物的流程,注釋里已經(jīng)寫了很清楚了,最后會(huì)將已有的事物屬性封裝到SuspendedResourcesHolder對(duì)象中,該類就持有了被掛起事物的屬性。接下來調(diào)用prepareTransactionStatus方法并將suspendedResources入?yún)?,這樣一來,新創(chuàng)建的事物就持有了被掛起事物的的屬性,就會(huì)形成一個(gè)事物鏈。而且新創(chuàng)建的事物transaction參數(shù)為null,所以PROPAGATION_NOT_SUPPORTED特性是不會(huì)真正開啟事物的。
// 創(chuàng)建新事物,注意:transaction參數(shù)為null,所以這里創(chuàng)建的不是一個(gè)真正的事物
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
PROPAGATION_REQUIRES_NEW
- 該特性下會(huì)掛起已有事物并新建一個(gè)事物。
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
// 掛起已有事物
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
......
}
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 創(chuàng)建事物
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 開啟事物
doBegin(transaction, definition);
// 初始化事物同步屬性
prepareSynchronization(status, definition);
return status;
}
PROPAGATION_NESTED
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 如果不允許嵌套事物,則拋出異常
if (!isNestedTransactionAllowed()) {
throw new NestedTransactionNotSupportedException(
"Transaction manager does not allow nested transactions by default - " +
"specify 'nestedTransactionAllowed' property with value 'true'");
}
if (debugEnabled) {
logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
}
//下面對(duì)JtaTransactionManager和AbstractPlatformTransactionManager分別進(jìn)行處理
//useSavepointForNestedTransaction(),是否為嵌套事務(wù)使用保存點(diǎn)
// 1.對(duì)于JtaTransactionManager-->返回false
// 2.對(duì)于AbstractPlatformTransactionManager-->返回true
if (useSavepointForNestedTransaction()) {
// Create savepoint within existing Spring-managed transaction,
// through the SavepointManager API implemented by TransactionStatus.
// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
// 創(chuàng)建保存點(diǎn)在現(xiàn)有spring管理事務(wù),通過TransactionStatus SavepointManager API實(shí)現(xiàn)。
// 通常使用JDBC 3.0保存點(diǎn)。永遠(yuǎn)不要激活Spring同步。
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 創(chuàng)建保存點(diǎn)
status.createAndHoldSavepoint();
return status;
}
else {
// Nested transaction through nested begin and commit/rollback calls.
// Usually only for JTA: Spring synchronization might get activated here
// in case of a pre-existing JTA transaction.
// 通過嵌套的開始,提交調(diào)用,及回滾調(diào)用進(jìn)行嵌套事務(wù)。
// 只對(duì)JTA有效,如果已經(jīng)存在JTA事務(wù),這里可能會(huì)激活Spring同步。
return startTransaction(definition, transaction, debugEnabled, null);
}
}
......
}
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// 創(chuàng)建事物
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 開啟事物
doBegin(transaction, definition);
// 初始化事物同步屬性
prepareSynchronization(status, definition);
return status;
}
這里對(duì)AbstractPlatformTransactionManager和JtaTransactionManager分別做了不同的處理,重點(diǎn)看前者。AbstractPlatformTransactionManager是允許使用保存點(diǎn)的。接下來看保存點(diǎn)的創(chuàng)建過程:
public abstract class AbstractTransactionStatus implements TransactionStatus {
// 創(chuàng)建保存點(diǎn)
public void createAndHoldSavepoint() throws TransactionException {
setSavepoint(getSavepointManager().createSavepoint());
}
}
public class DefaultTransactionStatus extends AbstractTransactionStatus {
// 獲取SavepointManager
@Override
protected SavepointManager getSavepointManager() {
Object transaction = this.transaction;
if (!(transaction instanceof SavepointManager)) {
throw new NestedTransactionNotSupportedException(
"Transaction object [" + this.transaction + "] does not support savepoints");
}
// SavepointManager就是當(dāng)前事物
return (SavepointManager) transaction;
}
}
public abstract class JdbcTransactionObjectSupport implements SavepointManager, SmartTransactionObject {
// 創(chuàng)建保存點(diǎn)
@Override
public Object createSavepoint() throws TransactionException {
// 獲取ConnectionHolder
ConnectionHolder conHolder = getConnectionHolderForSavepoint();
try {
// 如果當(dāng)前連接不支持保存點(diǎn),拋出異常
if (!conHolder.supportsSavepoints()) {
throw new NestedTransactionNotSupportedException(
"Cannot create a nested transaction because savepoints are not supported by your JDBC driver");
}
// 如果當(dāng)前連接的RollbackOnly已經(jīng)被標(biāo)記為true,拋出異常
if (conHolder.isRollbackOnly()) {
throw new CannotCreateTransactionException(
"Cannot create savepoint for transaction which is already marked as rollback-only");
}
// 創(chuàng)建保存點(diǎn)
return conHolder.createSavepoint();
}
catch (SQLException ex) {
throw new CannotCreateTransactionException("Could not create JDBC savepoint", ex);
}
}
}
總體來講創(chuàng)建保存點(diǎn)的過程比較簡單,最終會(huì)調(diào)用數(shù)據(jù)庫驅(qū)動(dòng)的底層方法去創(chuàng)建保存點(diǎn),感興趣的可以自己跟蹤查看。創(chuàng)建完保存點(diǎn)之后將結(jié)果設(shè)置到TransactionStatus對(duì)象中。
該特性下會(huì)將新事物在原有事物內(nèi),以嵌套的方式運(yùn)行,該特性也不會(huì)開啟一個(gè)新的事物。
PROPAGATION_SUPPORTS和PROPAGATION_REQUIRED
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
if (isValidateExistingTransaction()) {
// 驗(yàn)證事物隔離級(jí)別
// 如果當(dāng)前事物的隔離級(jí)別不為默認(rèn)隔離級(jí)別,則比較當(dāng)前事物隔離級(jí)別與已有事物隔離級(jí)別,
// 如不同,則拋出事物隔離級(jí)別不兼容異常
if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
Constants isoConstants = DefaultTransactionDefinition.constants;
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] specifies isolation level which is incompatible with existing transaction: " +
(currentIsolationLevel != null ?
isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
"(unknown)"));
}
}
// 驗(yàn)證事物只讀屬性
// 如果當(dāng)前事物可寫,但是已有的事物是只讀,則拋出異常
if (!definition.isReadOnly()) {
if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
throw new IllegalTransactionStateException("Participating transaction with definition [" +
definition + "] is not marked as read-only but existing transaction is");
}
}
}
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
isValidateExistingTransaction()該函數(shù)的作用是指定新事物參與已有事物時(shí),新舊兩個(gè)事物的驗(yàn)證級(jí)別。該屬性值默認(rèn)為false,寬松范圍的驗(yàn)證,也就是不驗(yàn)證。如果將該屬性值改為true的話,那么將會(huì)驗(yàn)證新舊兩個(gè)事物的數(shù)據(jù)庫事物隔離級(jí)別、事物只讀屬性是否相同。對(duì)于PROPAGATION_MANDATORY,從Spring的注釋上沒有看到對(duì)改屬性的處理,但是該屬性也會(huì)走這個(gè)分支,即使用已有事物,由于到這里肯定是已經(jīng)存在事物的,該特性在這里不會(huì)拋出異常。
該特性也不會(huì)開啟一個(gè)新的事物,而是繼續(xù)在原有事物中運(yùn)行或者以非事物方式運(yùn)行