SpringBoot系列:事物加载过程(一)
SpringBoot系列:事物创建过程(二)
SpringBoot系列:事物提交回滚过程(三)
上一节讲述了事物的加载过程,最后生成代理文件,放到spring容器中。
public class CloudDiskShareInfoDetailServiceImpl$$EnhancerBySpringCGLIB$$ec4fb618
extends CloudDiskShareInfoDetailServiceImpl
implements SpringProxy,Advised,Factory {
··· 省略
@Override
public final void aaa(Integer n) {
MethodInterceptor methodInterceptor = this.CGLIB$CALLBACK_0;
if (methodInterceptor == null) {
CloudDiskShareInfoDetailServiceImpl$$EnhancerBySpringCGLIB$$ec4fb618.CGLIB$BIND_CALLBACKS(this);
methodInterceptor = this.CGLIB$CALLBACK_0;
}
if (methodInterceptor != null) {
1、执行代理方法
Object object = methodInterceptor.intercept(this, CGLIB$aaa$0$Method, new Object[]{n}, CGLIB$aaa$0$Proxy);
return;
}
super.aaa(n);
}
··· 省略
}
代理类继承了 被代理类,
实现了两个SpringProxy
,Advised
,Factory
接口,
methodInterceptor
是DynamicAdvisedInterceptor
。
为什么实现了这三个接口?为什么是这个拦截器?
原理请跳转 :SpringAop解析的代码块十七之后
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
1、获取的被代理类,也就是原始类
TargetSource targetSource = this.advised.getTargetSource();
try {
2、是否对外暴露
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
3、获取符合条件的增强器 如事物的 TransactionInterceptor
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
4、没有增强器,直接执行 被代理方法
if (chain.isEmpty() && CglibMethodInvocation.isMethodProxyCompatible(method)) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = invokeMethod(target, method, argsToUse, methodProxy);
}
else {
5、递归调用process方法,处理所有的拦截器。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
6、最终返回值
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
3、获取符合条件的增强器 这儿在AOP加载过程中,获取符合条件的增强逻辑几乎一致,不再做讲解了。
事物的话就是获取的 TransactionInterceptor
,如果是我们常用的如@Before、@After、@Around
则会是对应的拦截器,在各自的拦截器内部再次调用process方法,完成整个拦截器链的调用。
5、递归调用process方法,处理所有的拦截器。
具体调用流程解析请跳转:
AOP系列之执行流程
public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
1、最后一个拦截器,直接调用目标方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
2、根据下标获取对应的拦截器,并执行
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
3、动态拦截器,判断是否匹配之后再调用
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
return proceed();
}
}
4、静态拦截器执行
else {
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
这儿我们只分析事物是怎么执行的。
public Object invoke(MethodInvocation invocation) throws Throwable {
1、被代理的原始类
Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);
return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
@Override
@Nullable
public Object proceedWithInvocation() throws Throwable {
return invocation.proceed();
}
@Override
public Object getTarget() {
return invocation.getThis();
}
@Override
public Object[] getArguments() {
return invocation.getArguments();
}
});
}
事物相关所有的流程都在 invokeWithinTransaction
中进行解析的。
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
1、AnnotationTransactionAttributeSource事物属性资源获取,也就是一开始注入的
TransactionAttributeSource tas = getTransactionAttributeSource();
1.1、获取事物的属性,@Transaction的属性,如隔离级别,超时等
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
2、确定事物管理器,这儿是jdbc的,也可自己设置
final TransactionManager tm = determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
···响应式事物的处理
}
3、获取事物管理器
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
3.1、com.zgf.service.impl.CloudDiskShareInfoDetailServiceImpl.aaa,得到方法的全路径
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
4、进入if,说明不是CallbackPreferringPlatformTransactionManager,也是声明式事物
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
5、创建并开启事务
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
6、再次回调process方法,有可能直接执行被代理方法。
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
7、事物异常的相关处理
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
8、清除一些事物的标记,如在ThreadLocal内的一些事物信息
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
9、事物正常执行的提交操作
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
···编程式事物处理流程
}
···省略一堆 catch
return result;
}
}
这儿有三种事物的处理方式:
1、声明式事物:@Transactiion
2、编程式事物
3、响应式事物:ReactiveTransactionManager,笔者也不太了解这种方式,有大佬的话请多多指点指点。
我们这儿只对声明式事务进行解析。
事物全流程
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
//标记名称
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) {
1、创建事物
status = tm.getTransaction(txAttr);
}
}
2、创建TransactionInfo,并将事物信息保存到ThreadLocal中
return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
throws TransactionException {
TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
1、获取一个事物对象
Object transaction = doGetTransaction();
boolean debugEnabled = logger.isDebugEnabled();
2、已经存在事物了,出现嵌套事务,根据事物隔离级别做出不同的处理
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(def, transaction, debugEnabled);
}
2.1、到这儿说明是第一次进来,还未开启事物
// Check definition settings for new transaction.
校验超时时间是否符合规则,也就是不能为负数,但-1是不设置超时
if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
}
// No existing transaction found -> check propagation behavior to find out how to proceed.
3、检查事物传播行为,到这儿说明之前没有事物,该传播行为需要有事物所以抛出异常
if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException(
"No existing transaction found for transaction marked with propagation 'mandatory'");
}
3.1、这三种传播行为都是需要创建新的事物
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 {
4、创建新的事物
return startTransaction(def, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error ex) {
resume(null, suspendedResources);
throw ex;
}
}
else {
5、否则,配置的事务的传播行为就是剩下的三种:PROPAGATION_SUPPORTS或PROPAGATION_NEVER或PROPAGATION_NOT_SUPPORTED,这三种都是以非事物的方式运行的
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);
}
5.1、 为给定参数创建一个新的TransactionStatus,并在适当时初始化事务同步,但是不会真正开启事务。
和startTransaction相比,其内部会调用newTransactionStatus和prepareSynchronization,但不会调用doBegin方法
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
}
}
@Override
protected Object doGetTransaction() {
1、初始化一个数据源对象,持有数据源信息以及事物信息
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
2、设置是否允许保存点,一般都是允许的,用于嵌套事物
txObject.setSavepointAllowed(isNestedTransactionAllowed());
3、第一次开启事物是null,后续会进行填充,若嵌套事物则不为null,所以嵌套事物用的都是同一个数据库链接
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
4、false:不是新的事物,后面会重新判断若是第一次会设置为true
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {
1、判断事物是否同步激活
if (TransactionSynchronizationManager.isSynchronizationActive()) {
2、执行挂起事物的同步回调方法,有具体的子类实现
List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();
try {
Object suspendedResources = null;
if (transaction != null) {
3、真正的挂起
suspendedResources = doSuspend(transaction);
}
4、清空一些同步信息:名称、只读状态、隔离级别、激活状态
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);
5、将上述信息进行包装返回
return new SuspendedResourcesHolder(
suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);
}
catch (RuntimeException | Error ex) {
// doSuspend failed - original transaction is still active...
doResumeSynchronization(suspendedSynchronizations);
throw ex;
}
}
else if (transaction != null) {
// Transaction active but no synchronization active.
6、事物不是激活状态,但是存在事物,直接挂起
Object suspendedResources = doSuspend(transaction);
return new SuspendedResourcesHolder(suspendedResources);
}
else {
// Neither transaction nor synchronization active.
7、没有事物,返回null
return null;
}
}
private List<TransactionSynchronization> doSuspendSynchronization() {
1、获取线程的所有同步事物
List<TransactionSynchronization> suspendedSynchronizations =
TransactionSynchronizationManager.getSynchronizations();
2、依次挂起事物
for (TransactionSynchronization synchronization : suspendedSynchronizations) {
synchronization.suspend();
}
3、清空同步事物
TransactionSynchronizationManager.clearSynchronization();
return suspendedSynchronizations;
}
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,
boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {
1、传播方式是无需事物,则新建标志设置为false
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
2、status:持有新事物的信息,以及之前挂起的事物信息
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
3、绑定TransactionSynchronizationManager内的一系列线程资源如:
名称、只读状态、隔离级别、激活状态等
prepareSynchronization(status, definition);
return status;
}
protected DefaultTransactionStatus newTransactionStatus(
TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,
boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {
1、newSynchronization:是否是新事物
2、第二个判断,因为之前挂起事物清空了同步信息,这儿也是未激活状态
boolean actualNewSynchronization = newSynchronization: &&
!TransactionSynchronizationManager.isSynchronizationActive();
3、返回全新的事物信息
return new DefaultTransactionStatus(
transaction, newTransaction, actualNewSynchronization,
definition.isReadOnly(), debug, suspendedResources);
}
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
1、是否存在链接,第一次开始事物是不存在的 || 事物同步状态 默认false下面创建完之后会设置ture
if (!txObject.hasConnectionHolder() ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = obtainDataSource().getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
1.1、设置链接,并标记为新的链接
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
2、设置隔离级别
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
3、设置只读模式
txObject.setReadOnly(definition.isReadOnly());
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
4、是否自动提交,改为手动
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
5、开启数据库事物的只读模式,会优化查询
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
6、设置超时时间
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
7、上面设置的新的链接标志
if (txObject.isNewConnectionHolder()) {
7.1、绑定资源,就是绑定TransactionSynchronizationManager的resources
前面用resources做了一系列处理,如事物挂起,就是获取的该资源进行依次挂起
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
}
catch (Throwable ex) {
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
接上述 6.2 中的 2,如果已经存在事物了如何处理。
private TransactionStatus handleExistingTransaction(
TransactionDefinition definition, Object transaction, boolean debugEnabled)
throws TransactionException {
1、非事物方式运行,不允许事物出现,直接抛出异常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
throw new IllegalTransactionStateException(
"Existing transaction found for transaction marked with propagation 'never'");
}
2、非事物方式运行,若存在事物,则挂起,执行完之后恢复事物继续执行
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
if (debugEnabled) {
logger.debug("Suspending current transaction");
}
2.1、挂起事物返回挂起信息
Object suspendedResources = suspend(transaction);
2.2、是否更新同步信息 TransactionSynchronizationManager内的一系列threadlocal属性
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
2.3、创建事物状态信息
return prepareTransactionStatus(
definition, null, false, newSynchronization, debugEnabled, suspendedResources);
}
3、每次都开启一个新的事物,挂起原来的事物
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
3.1、挂起原事物
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
3.2、开启新事物
return startTransaction(definition, transaction, debugEnabled, suspendedResources);
}
catch (RuntimeException | Error beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
}
4、如果当前有事物,则在事物内执行,通过保存点的方式进行回滚,但提交的话是交由外层事物提交。
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() + "]");
}
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);
4.2、创建保存点
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.
4.3、通常用于JTA:开启新事物
return startTransaction(definition, transaction, debugEnabled, null);
}
}
// 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");
}
}
}
5、剩下的传播行为就是PROPAGATION_SUPPORTS或者PROPAGATION_REQUIRED,不会有PROPAGATION_MANDATORY。
直接参与当前事务执行。
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
}
挂起之后都返回了挂起的资源,重新设置到事物信息中去。
public void createAndHoldSavepoint() throws TransactionException {
setSavepoint(getSavepointManager().createSavepoint());
}
设置的保存点:SAVEPOINT_ + 数字形式,如 SAVEPOINT_1
到这儿事物的创建已经解析完毕,下一章开始执行完本体方法之后的处理,回滚or提交。
1、事物是在AOP内执行的,递归的调用process方法
,从而进入对应拦截器的invoke方法
,事物进入的就是TransactionInterceptor
,事物之旅正式开启。
2、 获取一些事物属性,以及事物管理器,准备着手开始创建事物。
3、首先判断是否已经存在事物,若存在则是嵌套事物按照嵌套事物的处理方式进行处理。
3.1、根据不同的传播行为做出不同的处理方式,如PROPAGATION_REQUIRES_NEW
,策略就是挂起原事物,开启新的事物等,具体说明放在最后。
4、不存在事物,则准备开启事物,(不同的传播行为有的会抛出异常,有的创建事物,有的以空事物的方式运行)。
5、设置一系列的事物信息,如隔离级别、只读、手动提交、真正开启事物的方法doBegin方法
,从数据库连接池获取一个新的链接,正式开启事物,最终同步spring事物管理器的信息放到threadLocal
中,所以为什么说事物不支持多线程
。
事务传播行为类型 | 未开启事物 | 已开启事物 | 综合说明 |
---|---|---|---|
PROPAGATION_REQUIRED | 默认的传播行为,开启事物。 | 加入到前一个事物中 | 若存在事物加入到前一个事物中去,若不存在事物则开启新的事物 |
PROPAGATION_SUPPORTS | 空事物运行 | 加入到前一个事物 | 存在事物则加入到前一个事物中去,不存在事物则以空事物运行。 |
PROPAGATION_NOT_SUPPORTED | 创建空事物 | 将前一个事物挂起,空事物运行。 | 寸在事物则将事物挂起,创建空事物,不存在则创建空事物。 |
PROPAGATION_REQUIRES_NEW | 创建新事物 | 挂起前一个,创建新事物 | 无论是否存在事物,都开启新的事物 |
PROPAGATION_MANDATORY | 抛出异常 | 使用当前事物 | 存在事物则加入,不存在抛异常 |
PROPAGATION_NEVER | 空事物运行 | 抛出异常 | 存在事物抛出异常,不存在事物创建空事物 |
PROPAGATION_NESTED | 创建新事物 | 嵌套在内部,通过保存点的方式进行回滚,本质还是一个事物 | 存在事物,创建保存点加入到事物中,不存在开启新事物 |