1、spring - 事务 - spring事务原理与实现

本篇文章主要关注点,spring同类调用事务是否失效、spring开启事务、spring事务如何传播、spring事务失效场景、srpng事务如何回滚及回滚几次、spring事务挂起如何实现代表什么。如何看spring源码?spring源码规模很大,我们如何看?反正我是没有耐心看的,我调试源码的目的是找入口和相关类。然后再项目中断点哪个类调试的方式找到调用逻辑关系。这种方式看源码好处,代码调用逻辑链容易看出,调试中间变量容易看出。看源码只关心自己关心的部分而不是全部。

一、spring事务的本质

了解spring事务如何传播的的前提是了解spring实现事务的原理。spring是如何实现事务的?

1.1、spring本质不支持事务

spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,spring是无法提供事务功能的。对于纯JDBC操作数据库,想要用到事务可以按照下面代码的写法。 总结:spring本质是不支持事务的,只是控制事务提交回滚的时机。事务本质是什么?事务的本质就是 Connection、Commit、Rollback

private Connection conn = null;  
private PreparedStatement ps = null;  
try {  
    conn.setAutoCommit(false);  //将自动提交设置为false  
    ps.executeUpdate("修改SQL"); //执行修改操作  
    ps.executeQuery("查询SQL");  //执行查询操作  
    ps.executeUpdate("删除SQL"); //执行删除操作  
    conn.commit();      //当两个操作成功后手动提交  
} catch (Exception e) {  
    conn.rollback();    //一旦其中一个操作出错都将回滚,使三个操作都不成功  
    e.printStackTrace();  
}

1.2、spring是如何控制事务提交回滚

1.2.1、spring如何管理事务的?

spring在控制事务提交和回滚的前提是spring必须能管理事务。spring如何实现对事务的管理?答案就是spring aop技术。

1.2.1.1、事务扫描配置基于注解

思路:对注解打标的方法拦截

<!-- 定义事务管理器 -->
<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
</bean>
<!--使用注释事务 -->
<tx:annotation-driven  transaction-manager="transactionManager" />
@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class,timeout=1,isolation=Isolation.DEFAULT)
public void saveUser(Map<String, String> map) throws Exception {
         System.out.println("方法开始");
		for (int i = 0; i < 500000; i++) {
	            System.out.println("*");
	        }
		 System.out.println("进入保存");
		 userDao.saveUser(map);
		 System.out.println("退出保存");
}
1.2.1.2、事务扫描配置基于路径扫描配置

**思路:**对配置了扫描路径的方法且匹配了前缀的方法拦截。

<!-- 定义事务管理器 -->
<bean id="transactionManager"
		class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
</bean>
<!-- 下面使用aop切面的方式来实现 -->
<tx:advice id="TestAdvice" transaction-manager="transactionManager">
		<!--配置事务传播性,隔离级别以及超时回滚等问题 -->
		<tx:attributes>
			<tx:method name="save*" propagation="REQUIRED" />
			<tx:method name="del*" propagation="REQUIRED" />
			<tx:method name="update*" propagation="REQUIRED" />
			<tx:method name="add*" propagation="REQUIRED" />
			<tx:method name="*" rollback-for="Exception" />
		</tx:attributes>
</tx:advice>
<aop:config>
		<!--配置事务切点 -->
		<aop:pointcut id="services"
			expression="execution(* com.website.service.*.*(..))" />
		<aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
</aop:config>

1.3、spring如何管理事务的?

我们在上面搞懂spring事务的一个问题,spring是如何拦截需要事务处理的方法。在方法调用链中,spring如何将方法加入事务中,spring如何挂起事务,挂起是什么意识?spring如何知道什么时候提交回滚事务?

1.3.1、spring事务管理入口方法-事务拦截

//1、spring事务入口方法,利用AoP拦截注释方法 ReflectiveMethodInvocation.java
public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

		Object interceptorOrInterceptionAdvice =
				this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
		if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
			// Evaluate dynamic method matcher here: static part will already have
			// been evaluated and found to match.
			InterceptorAndDynamicMethodMatcher dm =
					(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
			if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
				return dm.interceptor.invoke(this);
			}
			else {
				return proceed();
			}
		}
		else {
			// It's an interceptor, so we just invoke it: The pointcut will have
			// been evaluated statically before this object was constructed.
			return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
		}
}
1.3.2、spring如何开启一个事务

下面代码就是我从spring源码调试找到的,spring关闭自己提交的过程代码。

//spring关闭自动提交 DataSourceTransactionManager.java
protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
				Connection newCon = this.dataSource.getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}

			txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
			con = txObject.getConnectionHolder().getConnection();

			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			txObject.setPreviousIsolationLevel(previousIsolationLevel);

			//关闭自动提交改成手动提交,应为jdbc事务默认是开启自动提交的
			if (con.getAutoCommit()) {
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				con.setAutoCommit(false);
			}

			prepareTransactionalConnection(con, definition);
			txObject.getConnectionHolder().setTransactionActive(true);

			int timeout = determineTimeout(definition);
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			// Bind the connection holder to the thread.
			if (txObject.isNewConnectionHolder()) {
				TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
			}
		}

		catch (Throwable ex) {
			if (txObject.isNewConnectionHolder()) {
				DataSourceUtils.releaseConnection(con, this.dataSource);
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}

1.3.2、spring如何加入一个已存在的事务

在一个就是spring传播级别,比如当spring事务传播级别为PROPAGATION_REQUIRED,spring如何加入一个已经存在的事务?

//事务隔离级别检查  AbstractPlatformTransactionManager.java
@Override
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();

		if (definition == null) {
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}
        
        //此处就是事务传播行为的检查点,如果存在事务就不会走下面doBegin
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// 如果不存在事务就抛出异常
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
        //如果事务传播级别是REQUIRED、REQUIRES_NEW、NESTED如果不存在事务,则创建新事务
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException ex) {
				resume(null, suspendedResources);
				throw ex;
			}
			catch (Error err) {
				resume(null, suspendedResources);
				throw err;
			}
		}
		else {
            //事务传播级别不匹配,创建空事务
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + definition);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}
1.3.3、spring如何知道什么时候提交回滚事务?

还有个关注点就是spring何时提交或者回滚。从java aop可以知道,事务是在方法执行结束后执行的,spring方法链相互调用,那么spring如何判断事务应该提交?

1.3.3.1、如何找spring事务回滚入口
看到下面报错信息没有 org.springframework.transaction 打头的几个类就有spring回滚事务的入口。

	at com.yst.tms.order.center.service.impl.DeliveryOrderServiceImpl$$FastClassBySpringCGLIB$$4c20e28c.invoke(<generated>)
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:736)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
	at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:283)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:671)
	at com.yst.tms.order.center.service.impl.DeliveryOrderServiceImpl$$EnhancerBySpringCGLIB$$5a1f699e.saveOrder(<generated>)

1.3.3.2、如何找spring事务回滚入口类
spring回滚入口类 TransactionAspectSupport.invokeWithinTransaction.completeTransactionAfterThrowing这个方法。

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {

		// If the transaction attribute is null, the method is non-transactional.
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(tm, 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) {
				// 当事务方法执行出现异常,spring执行回滚入口
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		else {
			final ThrowableHolder throwableHolder = new ThrowableHolder();

			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
						new TransactionCallback<Object>() {
							@Override
							public Object doInTransaction(TransactionStatus status) {
								TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
								try {
									return invocation.proceedWithInvocation();
								}
								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);
								}
							}
						});

				// Check result state: It might indicate a Throwable to rethrow.
				if (throwableHolder.throwable != null) {
					throw throwableHolder.throwable;
				}
				return result;
			}
			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;
			}
		}
	}

1.3.3.3、spring事务回滚实现方法
在上面我们就分析spring没有事务功能,其利用mysql的事务功能,这个部分是spring事务回滚的最底层。其使用的是Connection.rollback。

//DataSourceTransactionManager.doRollback spring回滚实现类	
@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 {
			con.rollback();
		}
		catch (SQLException ex) {
			throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
		}
}

1.3.3.4、方法嵌套调用spring事务回滚几次?
关于spring回滚几次分两种情况,子事务是否加入父事务、子事务是否独立事务。
**子事务加入父事务:**1次父事务
**子事务未加入父事务:**回滚次数子事务数+1次父事务

//如何证明 上面方法嵌套调用spring事务回滚几次? TransactionAspectSupport.invokeWithinTransaction
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
			throws Throwable {

		// If the transaction attribute is null, the method is non-transactional.
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(tm, 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) {
				// 此处打断点 关注joinpointIdentification变量类型的次数
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

1.3.4、spring事务挂起实现

下面找到spring事务挂起的入口点及实现,spring事务挂起靠的就是重置Connection对象为空实现的**。**

//事务挂起入口分析 AbstractPlatformTransactionManager.java
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);
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}

		//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 {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
			catch (Error beginErr) {
				resumeAfterBeginException(transaction, suspendedResources, beginErr);
				throw beginErr;
			}
		}

		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);
				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.
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, null);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
		}

		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}
//事务挂起实现-将Connect连接置空 DataSourceTransactionManager.java
@Override
protected Object doSuspend(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		txObject.setConnectionHolder(null);
		return TransactionSynchronizationManager.unbindResource(this.dataSource);
}

1.3.2、spring 同类方法之间调用事务为啥不生效?

1.3.2.1、演示spring同类方法调用不生效与生效代码写法

这点很多同学都不清楚吧,我们用事务的时候,时时刻要想到aop。1:写法走的是方法this之间的调用,没有用到动态代理。 2:写法走的是动态代理自然事务传播生效。但是,此时不生效不代表事务失败,this场景一样在事务里面。

public class StationServiceImpl extends BaseService implements StationService {
    
    @Autowired
    private StationService stationService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeStationById(Long stationId, String operateBy) {
        Station station = stationMapper.selectById(stationId);
        
        //1、这一样写事务传播不生效
        getStations();
        
        //2、这样写事务传播生效
        stationService.getStationById();
        
        //3、这样写事务传播生效  spring boot需要开启 @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true),否则会报错:Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available
        ((StationService)AopContext.currentProxy()).getStationById(stationId);
    }
    
    @Override
	@Transactional(rollbackFor = Exception.class)
	public PagingResult<StationVO> getStations() {
        userBindStationMapper.delete(new QueryWrapper<UserBindStation>().eq("station_id", 1L));
		return null;
	}

	@Transactional(rollbackFor = Exception.class)
	public StationDetailVO getStationById() {
        userBindStationMapper.delete(new QueryWrapper<UserBindStation>().eq("station_id", 2L));
		return null;
	}
}
1.3.2.2、spring同类方法调用事务不生效代表事务无效吗?

上面我们介绍this写法,spring从调试源码的角度上讲事务没有起作用,但是不代表事务失败的。他依然在事务里面。spring事务的本质就是打开自动提交、提交、回滚。在此阶段整个语句依然在事务里面。但是如果入口父方法没有开启事务,this方式调B方法就算开启事务也会无效。

二、spring事务传播级别

2.1、spring事务传播级别列表整理

关于事务很多人都知道,但是spring事务传播级别能说明白的估计不多。啥叫spring事务传播级别?就是spring方法调用同级别方法、父级别方法、子级别方法的事务相互影响传递的过程。 spring事务类型枚举类Propagation.java。看下面事务列表特征,我们不难发现spring事务有共同特点:当父事务不被挂起,子事务的异常外抛都会影响父事务 。 声明:底下的各类测试是选择网络上别人的测试结果,并没有亲自测试。常用事务传播策略 REQUIRED、REQUIRES_NEW

事务传播类型事务传播类型描述特征
REQUIRED如果事务管理器存在事务则加入事务,没有事务者新创建一个事务。spring默认事务传递级别 验证父亲无事务:各子方法事务各自独立且不相互影响
父亲有事务:父、各子方法事务相互影响且异常回滚
SUPPORTS如果事务管理器没有事务,如果当前有事务,使用当前事务否则以非事务执行 验证父亲无事务:各子方法无事务执行且不会滚
父亲有事务:父、各子方法事务相互影响且异常回滚
MANDATORY使用当前事务,如果当前事务管理器没有事务就抛出异常。验证父亲无事务:抛出异常
父亲有事务:加入当前事务执行
REQUIRES_NEW如果当前事务管理器有事务,挂起当前事务,新开建一个事务。 验证父亲无事务:不影响子事务执行
父亲有事务:父事务被挂起,等待子事务执行完毕后执行,且父子事务不相互影响
NOT_SUPPORTED以非事务方式执行,如果当前事务管理器有事务则挂起当前事务。父亲无事务:以非事务方式执行
父亲有事务:父事务被挂起,然后子以非事务方式执行
NEVER以非事务方式执行,如果当前事务管理器有事务则抛出异常。父亲无事务:非事务方式执行
父亲有事务:抛出异常
NESTED如果当前事务管理器有事务则嵌套事务内执行,如果没有事务则按照REQUIRED执行。 验证父亲无事务:子事务独立不相互影响
父亲有事务:父子事务相互影响

2.2、当父事务不被挂起,子事务的异常外抛都会影响父事务原因分析

在整理事务传播级别测试时候发现,只要父事务不被挂起,子事务异常外抛都会影响父事务。原因还是aop切面的问题。在aop理解不管子事务、父事务都是一个独立的方法,区别只是父方法是否开启事务而已。如果父事务不被挂起,其就是受子事务影响的。

三、spring事务总结

spring事务需要了解事务的传播级别、spring事务加入如何实现、spring事务挂起如何实现、spring事务回滚提交如何实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值