Spring事務傳播屬性
事務傳播行為類型 | 說明 |
PROPAGATION_REQUIRED | 如果目前沒有事務,就建立一個事務,如果已經存在一個事務中,加入到這個事務中。Spring的預設事務傳播類型 |
PROPAGATION_SUPPORTS | 支援目前事務,如果目前沒有事務,就以非事務方式執行。 |
PROPAGATION_MANDATORY | 使用目前的事務,如果目前沒有事務,就抛出異常。 |
PROPAGATION_REQUIRES_NEW | 建立事務,如果目前存在事務,把目前事務挂起(暫停)。 |
PROPAGATION_NOT_SUPPORTED | 以非事務方式執行操作,如果目前存在事務,就把目前事務挂起。 |
PROPAGATION_NEVER | 以非事務方式執行,如果目前存在事務,則抛出異常。 |
PROPAGATION_NESTED | 如果目前存在事務,則在嵌套事務内執行。如果目前沒有事務,則執行與PROPAGATION_REQUIRED類似的操作。 |
Spring 事務是通過AOP實作的,如果是我們自己寫一個AOP控制事務,該怎麼做呢?
// 僞代碼
public Object invokeWithinTransaction() {
// 開啟事務
connection.beginTransaction();
try {
// 反射執行方法
Object result = invoke();
// 送出事務
connection.commit();
return result;
} catch(Exception e) {
// 發生異常時復原
connection.rollback();
throw e;
}
}
源碼入手
要閱讀事務傳播相關的源碼,我們先來了解下Spring 事務管理的核心接口與類
- TransactionDefinition該接口定義了事務的所有屬性(隔離級别,傳播類型,逾時時間等等),我們日常開發中經常使用的 @Transactional 其實最終會被轉化為 TransactionDefinition
- TransactionStatus事務的狀态,以最常用的實作 DefaultTransactionStatus 為例,該類存儲了目前的事務對象,savepoint,目前挂起的事務,是否完成,是否僅復原等等
- TransactionManager這是一個空接口,直接繼承他的 interface 有 PlatformTransactionManager(我們平時用的就是這個,預設的實作類DataSourceTransactionManager)以及ReactiveTransactionManager(響應式事務管理器,由于不是本文重點,我們不多說)
從上述兩個接口來看,TransactionManager 的主要作用
- 通過TransactionDefinition開啟一個事務,傳回TransactionStatus
- 通過TransactionStatus 送出、復原事務(實際開啟事務的Connection通常存儲在TransactionStatus中)
public interface PlatformTransactionManager extends TransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
- **TransactionInterceptor事務攔截器,事務AOP的核心類(**支援響應式事務,程式設計式事務,以及我們常用的标準事務),由于篇幅原因,本文隻讨論标準事務的相關實作
下面我們從事務邏輯的入口 TransactionInterceptor 入手,來看下Spring事務管理的核心邏輯以及事務傳播的實作
TransactionInterceptor
TransactionInterceptor 實作了MethodInvocation(這是實作AOP的一種方式),
其核心邏輯在父類TransactionAspectSupport 中,方法位置:TransactionInterceptor::invokeWithinTransaction
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
// 目前事務的屬性 TransactionAttribute extends TransactionDefinition
final **TransactionAttribute** txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 事務屬性中可以定義目前使用哪個事務管理器
// 如果沒有定義就去Spring上下文找到一個可用的 TransactionManager
final TransactionManager tm = determineTransactionManager(txAttr);
// 省略了響應式事務的處理 ...
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
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.
// 如果有下一個攔截器則執行,最終會執行到目标方法,也就是我們的業務代碼
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 當捕獲到異常時完成目前事務 (送出或者復原)
**completeTransactionAfterThrowing**(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 根據事務的狀态送出或者復原
**commitTransactionAfterReturning**(txInfo);
return retVal;
}
// 省略了程式設計式事務的處理 ...
}
這裡代碼很多,根據注釋的位置,我們可以把核心邏輯梳理出來
- 擷取目前事務屬性,事務管理器(以注解事務為例,這些都可以通過@Transactional來定義)
- createTransactionIfNecessary,判斷是否有必要建立事務
- invocation.proceedWithInvocation 執行攔截器鍊,最終會執行到目标方法
- completeTransactionAfterThrowing當抛出異常後,完成這個事務,送出或者復原,并抛出這個異常
- commitTransactionAfterReturning 從方法命名來看,這個方法會送出事務。但是深入源碼中會發現,該方法中也包含復原邏輯,具體行為會根據目前TransactionStatus的一些狀态來決定(也就是說,我們也可以通過設定目前TransactionStatus,來控制事務復原,并不一定隻能通過抛出異常),詳見AbstractPlatformTransact ionManager::commit
我們繼續,來看看createTransactionIfNecessary做了什麼
TransactionAspectSupport::createTransactionIfNecessary
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
// If no name specified, apply method identification as transaction name.
if (txAttr != null && txAttr.getName() == null) {
txAttr = new DelegatingTransactionAttribute(txAttr) {
@Override
public String getName() {
return joinpointIdentification;
}
};
}
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
// 通過事務管理器開啟事務
status = tm.getTransaction(txAttr);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
"] because no transaction manager has been configured");
}
}
}
return **prepareTransactionInfo**(tm, txAttr, joinpointIdentification, status);
}
createTransactionIfNecessary中的核心邏輯
- 通過PlatformTransactionManager(事務管理器)開啟事務
- prepareTransactionInfo 準備事務資訊,這個具體做了什麼我們稍後再講
繼續來看PlatformTransactionManager::getTransaction,該方法隻有一個實作 AbstractPlatformTransactionManager::getTransaction
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
// Use defaults if no transaction definition given.
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
// 擷取目前事務,該方法有繼承 AbstractPlatformTransactionManager 的子類自行實作
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
// 如果目前存在事務
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
// Check definition settings for new transaction.
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// 傳播類型PROPAGATION_MANDATORY, 要求目前必須有事務
// No existing transaction found -> check propagation behavior to find out how to proceed.
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
// PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, PROPAGATION_NESTED 不存在事務時建立事務
else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
SuspendedResourcesHolder suspendedResources = suspend(null);
if (debugEnabled) {
logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
}
try {
// 開啟事務
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
// Create "empty" transaction: no actual transaction, but potentially synchronization.
// 建立一個空事務:非真正的事務,而是可能的事務同步
if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
logger.warn("Custom isolation level specified but no actual transaction initiated; " +
"isolation level will effectively be ignored: " + def);
}
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
代碼很多,重點關注注釋部分即可
- doGetTransaction擷取目前事務
- 如果存在事務,則調用handleExistingTransaction處理,這個我們稍後會講到
接下來,會根據事務的傳播決定是否開啟事務
- 如果事務傳播類型為PROPAGATION_MANDATORY,且不存在事務,則抛出異常
- 如果傳播類型為 PROPAGATION_REQUIRED, PROPAGATION_REQUIRES_NEW, PROPAGATION_NESTED,且目前不存在事務,則調用startTransaction建立事務
- 當不滿足 3、4時,例如 PROPAGATION_NOT_SUPPORTED,此時會執行事務同步,但是不會建立真正的事務
Spring 如何管理目前的事務
接下來講講上面提到的doGetTransaction、handleExistingTransaction,這兩個方法是由不同的TransactionManager自行實作的
我們以SpringBoot預設的TransactionManager,DataSourceTransactionManager為例
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
結合 AbstractPlatformTransactionManager::getTransaction 一起來看,doGetTransaction 其實擷取的是目前的Connection。判斷目前是否存在事務,是判斷DataSourceTransactionObject 對象中是否包含connection,以及connection是否開啟了事務。
我們繼續來看下TransactionSynchronizationManager.getResource(obtainDataSource())擷取目前connection的邏輯
TransactionSynchronizationManager::getResource
private static final ThreadLocal<Map<Object, Object>> resources =
new NamedThreadLocal<>("Transactional resources");
@Nullable
// TransactionSynchronizationManager::getResource
public static Object getResource(Object key) {
// DataSourceTransactionManager 調用該方法時,以資料源作為key
// TransactionSynchronizationUtils::unwrapResourceIfNecessary 如果key為包裝類,則擷取被包裝的對象
// 我們可以忽略該邏輯
Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);
Object value = doGetResource(actualKey);
if (value != null && logger.isTraceEnabled()) {
logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +
Thread.currentThread().getName() + "]");
}
return value;
}
/**
* Actually check the value of the resource that is bound for the given key.
*/
@Nullable
private static Object doGetResource(Object actualKey) {
Map<Object, Object> map = resources.get();
if (map == null) {
return null;
}
Object value = map.get(actualKey);
// Transparently remove ResourceHolder that was marked as void...
if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
map.remove(actualKey);
// Remove entire ThreadLocal if empty...
if (map.isEmpty()) {
resources.remove();
}
value = null;
}
return value;
}
看到這裡,我們能明白DataSourceTransactionManager是如何管理線程之間的Connection,ThreadLocal 中存儲一個Map,key為資料源對象,value為該資料源在目前線程的Connection
DataSourceTransactionManager 在開啟事務後,會調用TransactionSynchronizationManager::bindResource将指定資料源的Connection綁定到目前線程
AbstractPlatformTransactionManager::handleExistingTransaction
我們繼續回頭看,如果存在事務的情況,如何處理
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
// 如果事務的傳播要求以非事務方式執行 抛出異常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
// PROPAGATION_NOT_SUPPORTED 如果存在事務,則挂起目前事務,以非事務方式執行
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
// 挂起目前事務
Object suspendedResources = suspend(transaction);
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 建構一個無事務的TransactionStatus
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
// PROPAGATION_REQUIRES_NEW 如果存在事務,則挂起目前事務,建立一個事務
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;
}
}
// PROPAGATION_NESTED 内嵌事務,就是我們開頭舉得例子
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() + "]");
}
// 非JTA事務管理器都是通過savePoint實作的内嵌事務
// savePoint:關系型資料庫中事務可以建立還原點,并且可以復原到還原點
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.
DefaultTransactionStatus status =
prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
// 建立還原點
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.
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// 如果執行到這一步傳播類型一定是,PROPAGATION_SUPPORTS 或者 PROPAGATION_REQUIRED
// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
if (debugEnabled) {
logger.debug("Participating in existing transaction");
}
// 校驗目前方法中的事務定義和已存在的事務定義是否一緻
if (isValidateExistingTransaction()) {
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)"));
}
}
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);
// 建構一個TransactionStatus,但不開啟事務
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
這裡代碼很多,邏輯看上述注釋即可。這裡終于看到了期待已久的挂起事務和内嵌事務了,我們還是看一下DataSourceTransactionManager的實作
- 挂起事務:通過TransactionSynchronizationManager::unbindResource 根據資料源擷取目前的Connection,并在resource中移除該Connection。之後會将該Connection存儲到TransactionStatus對象中
// DataSourceTransactionManager::doSuspend
@Override
protected Object doSuspend(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
txObject.setConnectionHolder(null);
return TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
在事務送出或者復原後,調用 AbstractPlatformTransactionManager::cleanupAfterCompletion會将TransactionStatus 中緩存的Connection重新綁定到resource中
- 内嵌事務:通過關系型資料庫的savePoint實作,送出或復原的時候會判斷如果目前事務為savePoint則釋放savePoint或者復原到savePoint,具體邏輯參考AbstractPlatformTransactionManager::processRollback 和 AbstractPlatformTransactionManager::processCommit
至此,事務的傳播源碼分析結束
prepareTransactionInfo
上文留下了一個問題,prepareTransactionInfo 方法做了什麼,我們先來看下TransactionInfo的結構
protected static final class TransactionInfo {
@Nullable
private final PlatformTransactionManager transactionManager;
@Nullable
private final TransactionAttribute transactionAttribute;
private final String joinpointIdentification;
@Nullable
private TransactionStatus transactionStatus;
@Nullable
private TransactionInfo oldTransactionInfo;
// ...
}
該類在Spring中的作用,是為了内部傳遞對象。ThreadLocal中存儲了最新的TransactionInfo,通過目前TransactionInfo可以找到他的oldTransactionInfo。每次建立事務時會建立一個TransactionInfo(無論有沒有真正的事務被建立)存儲到ThreadLocal中,在每次事務結束後,會将目前ThreadLocal中的TransactionInfo重置為oldTransactionInfo,這樣的結構形成了一個連結清單,使得Spring事務在邏輯上可以無限嵌套下去
源碼跟蹤流程
@EnableTransactionManagement
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
// ......
}
TransactionManagementConfigurationSelector
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
/**
* Returns {@link ProxyTransactionManagementConfiguration} or
* {@code AspectJ(Jta)TransactionManagementConfiguration} for {@code PROXY}
* and {@code ASPECTJ} values of {@link EnableTransactionManagement#mode()},
* respectively.
*/
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {AutoProxyRegistrar.class.getName(),
ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
}
以JDK動态代理為例:
AutoProxyRegistrar:向BeanRegistry注冊JDK動态代理所需的BeanDefinition
ProxyTransactionManagementConfiguration
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource);
advisor.setAdvice(transactionInterceptor);
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource);
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
TransactionInterceptor
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
/**
* Create a new TransactionInterceptor.
* @param ptm the default transaction manager to perform the actual transaction management
* @param tas the attribute source to be used to find transaction attributes
* @since 5.2.5
* @see #setTransactionManager
* @see #setTransactionAttributeSource
*/
public TransactionInterceptor(TransactionManager ptm, TransactionAttributeSource tas) {
setTransactionManager(ptm);
setTransactionAttributeSource(tas);
}
@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
// Work out the target class: may be {@code null}.
// The TransactionAttributeSource should be passed the target class
// as well as the method, which may be from an interface.
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
// Adapt to TransactionAspectSupport's invokeWithinTransaction...
// 調用父類方法
return **invokeWithinTransaction**(invocation.getMethod(), targetClass, invocation::proceed);
}
}
TransactionAspectSupport:
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
@Nullable
private TransactionManager transactionManager;
@Nullable
private TransactionAttributeSource transactionAttributeSource;
@Nullable
private BeanFactory beanFactory;
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final TransactionManager tm = determineTransactionManager(txAttr);
// 反應式程式設計事務處理
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
throw new TransactionUsageException(
"Unsupported annotated transaction on suspending function detected: " + method +
". Use TransactionalOperator.transactional extensions instead.");
}
ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
if (adapter == null) {
throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
method.getReturnType());
}
return new ReactiveTransactionSupport(adapter);
});
return txSupport.invokeWithinTransaction(
method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
}
// 指令式程式設計事務處理
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
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.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
Object result;
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
try {
Object retVal = invocation.proceedWithInvocation();
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
return retVal;
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
}
}