Spring 事务控制

spring事务控制

简介

事务是恢复和并发控制的基本单位。
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID特性。
原子性(atomicity)。一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。
一致性(consistency)。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。
隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

常规项目使用事务

常规项目都是自己手动控制事务的开关,连接的开关,导致很多时候事务和连接的开关出现问题,导致各种各样的报错,这样的报错通常不好发现,排查困难。

Connection,Session,Transaction的关系

Connection是一个物理连接,一个物理连接可以有多次session。一次session里面可以有多次transaction

Spring使用事务

spring的事务依靠thread保存,和线程绑定,自动开启和释放,只需要我们使用特定的注解即可。

Spring 事务几个关键的接口

PlatformTransactionManager,TransactionStatus,TransactionDefinition。这三个接口都在spring-tx-x.x.x.RELEASE.jar下面的org.springframework.trasaction包下面。

  • PlatformTransactionManager : 事务管理器
  • TransactionDefinition : 事务的一些基础信息,如超时时间、隔离级别、传播属性等
  • TransactionStatus : 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚

PlatformTransactionManager

看一下PlatformTransactionManager 有哪些方法
PlatformTransactionManager
在上面我们看到,PlatformTransactionManager 定义了事务的获取,提交和回滚。获取出来的,就是TransactionStatus。看下PlatformTransactionManager的实现类。
PlatformTransactionManager的实现类
比较常见的实现类有DataSourceTransactionManager,HibernateTransactionManager。如果我们用的mybatis操作mysql数据库,就用的DataSourceTransactionManager。如果用的hibernate,就是HibernateTransactionManager。还有jpa等其他的。

TransactionDefinition

TransactionDefinition
从上面,我们可以看到有一些静态常量,这是都是spring的事务传播类型。下面,是一些方法,比如获取当前事务的传播类型,获取事务隔离级别,获取超时时间,是否只读,获取事务的名字,获取默认的TransactionDefinition。

TransactionStatus

TransationStatus继承了其他接口,所以我们看到他的实现类AbstractTransactionStatus。
AbstractTransactionStatus

该类的属性主要标记了当前transaction和他的状态。该类的方法包含了对上面状态的获取和维护,SavepointManager接口的一些方法的实现。SavepointManager定义了spring事务的保存点(SavePoint)的操作方法。SavePoint主要为了事务嵌套使用的,SavePoint详细解释

上面三个怎么搭配的

从TransactionInterceptor这个类的invoke方法进入到TransactionAspectSupport.invokeWithinTransaction方法。进入到该方法后,看到一个比较重要的TransactionAttribute txAttr,TransactionAttribute是TransactionDefinination的子接口。txAttr保存了事务的传播属性,事务的隔离级别,事务的是否只读等信息。看到我们利用txAttr获取到的是PlatformTransactionManager(tm对象),继续往下面走到createTransactionIfNecessary方法。在该方法下面会利用tm.getTransaction(txAttr)构建一个TransactionStatus对象。
所以从上面来看,TransationDefinition先决定了PlatformTransactionManager,然后通过PlatformTransactionManager和TransationDefinition获取TransactionStatus。然后把PlatformTransactionManager,TransationDefinition,TransactionStatus保存到TransactionInfo对象中。

进入到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可能为空或不为空,但是tm很多情况下也不是CallbackPreferringPlatformTransactionManager,所以会走if下面的逻辑。
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			//在这个方法里面会判断是否创建事务,会走到下面的PlatformTransactionManager.getTransaction。注意在走到PlatformTransactionManager.getTransaction前时会判断txAttr是否为null,为null时不会走到getTransaction方法。
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			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);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		//编程式事务,自己决定是提交还是回滚
		else {
			// 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.
										return new ThrowableHolder(ex);
									}
								}
								finally {
									cleanupTransactionInfo(txInfo);
								}
							}
						});

				// Check result: It might indicate a Throwable to rethrow.
				if (result instanceof ThrowableHolder) {
					throw ((ThrowableHolder) result).getThrowable();
				}
				else {
					return result;
				}
			}
			catch (ThrowableHolderException ex) {
				throw ex.getCause();
			}
		}
	}
具体看下PlatformTransactionManager.getTransaction
/**
	 * This implementation handles propagation behavior. Delegates to
	 * {@code doGetTransaction}, {@code isExistingTransaction}
	 * and {@code doBegin}.
	 * @see #doGetTransaction
	 * @see #isExistingTransaction
	 * @see #doBegin
	 */
	@Override
	public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
		//根据底层实现类决定返回的transaction,该阶段的transaction,对于我们常用的DataSourceTransactionManager来说,里面有ConnectionHolder和SavepointAllowed属性。
		Object transaction = doGetTransaction();

		// Cache debug flag to avoid repeated checks.
		boolean debugEnabled = logger.isDebugEnabled();
		//如果TransactionDefinition为空,即可能在方法上或者该方法的类上没有@Transactional注解,或者也没有在其他地方配置
		if (definition == null) {
			//new一个默认的transactiondefinition
			definition = new DefaultTransactionDefinition();
		}
		//根据底层实现类决,检查当前情况下是否有事务,如果有,那么根据事务传播级别去处理
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// 走到这里就代表当前情况下没有事务,那么下面就会根据事务传播属性等配置信息创建transationStatus和开启事务。
		
		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'");
		}

		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);
				//创建transactionStatus
				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);
		}
	}

上面有两个比较重要的方法,doGetTransaction和isExistingTransaction。这里用DatasourceTransactionManager举例。

protected Object doGetTransaction() {
	//这里新建了一个txObject,在这里会返回出去
    DataSourceTransactionObject txObject = new DataSourceTransactionObject();
    txObject.setSavepointAllowed(isNestedTransactionAllowed()); //是否可以使用savepoint(具体的作用可以看上面)
    //利用datasource从TransactionSynchronizationManager获取对象。
    ConnectionHolder conHolder =
        (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
     //设置connectionHolder,但是conHolder可能为null
    txObject.setConnectionHolder(conHolder, false); 
    return txObject;
}

从上面看到一个TransactionSynchronizationManager,这个类里面有很多ThreadLocal相关的对象,resource就是其中一个。也就是说这些都是和线程绑定的。在DatasourceTransactionManager的doBegin会绑定该资源。
继续看isExistingTransaction。

protected boolean isExistingTransaction(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
        //如果ConnectionHolder为空,txObject.hasConnectionHolder()返回为false。txObject.getConnectionHolder().isTransactionActive()返回事务是否在活动状态
		return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
	}

如果已存在事务,那么回进入到handleExistingTransaction方法,如果不存在,就会走下面的方法。
当我们第一次访问数据库的时候,是没有事务的,所以会走下面的方法。如果事务的传播方式为required,required_new,nested情况的时候,会走到doBegin方法。在dobegin方法中会创建事务并且绑定到TransactionSynchronizationManager的resource中,设置TransactionSynchronizationManager的当前事务。
如果我们第二次进来,那么可能已经存在事务了,那么会走handleExistingTransaction。
在handleExistingTransaction中,会针对不同的事务传播属性进行特殊处理,例如为never的,会抛出异常,not_supported的会将当前transaction保存到新的transactionStatus中。required_new的会将transaction保存到新的transactionStatus中,同时会创建新的事务。这里和第一次进来无事务的时候一样。

回到TransactionInterceptor的invokeWithinTransaction

继续看到下面的catch,finally,和正常执行。在catch的时候,调用了completeTransactionAfterThrowing,这里对事物进行了回滚,如果有被暂停的事务(比如required_new的时候,会把老事务悬停),会把悬停的事务重新激活。在正常的执行情况下,调用了cleanupTransactionInfo,这里完成了事务的提交,和rollback一样,都会处理被悬停的事务。在finally里面,调用了cleanupTransactionInfo(),这里完成了事务的清除。

扩展

1、手动设置回滚

TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动开启事务回滚

编程式事务

@Autowired
private TransactionTemplate transactionTemplate; 
 @Transactional
public UserInfo saveRegistInfoAndBuildUser(RegistInfo resgitInfo) {
	//独立的事务
	resgitInfoService.saveRegistInfo(resgitInfo);
	// 独立的事务
	return transactionTemplate.execute(new TransactionCallback<UserInfo>() {
		@Override
		public UserInfo doInTransaction(TransactionStatus status) {
			try{
				UserInfo userInfo = userInfoService.convertRegistInfoToUserInfo(resgitInfo);
				userInfoService.saveUserInfo(userInfo);
				return userInfo;
			}catch(Exception e){
				 e.printStackTrace();
				TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动开启事务回滚
			}
		}
	});
}

2、当我们没有申明事务参数时,也就是说我们获取到的txAttr为空时,很多的代码都是没有进入的,比如我们上面的getTransaction(),那当前是没有事务的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值