Spring框架 编程式事务

Spring事务

Spring的事务有编程式事务和声明式事务两种。Spring的事务实现都在spring-tx包。

编程式事务

先附上代码再分析。


@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    private DruidDataSource dataSource;//数据源
    @Autowired
    private AccountDao accountDao;//持久层
    @Override
    public void update(String OutName, String InName, double money) {
  		PlatformTransactionManager pm =null;
        TransactionStatus ts =null;
        try {
            pm = new DataSourceTransactionManager(dataSource);
            TransactionDefinition td = new DefaultTransactionDefinition();
            ts = pm.getTransaction(td);
            accountDao.inMoney("张三",100.0);//张三加100块钱
            //  int i=1/0;
            accountDao.outMoney("李四", 100.0);//李四减去100块钱
            pm.commit(ts);

        } catch (TransactionException e) {
            if (pm!=null){
                pm.rollback(ts);
            }
        }
    }
}

以上代码模拟转账操作。我们通过上述代码来进行分析。

源码分析

1.初始化PlatformTransactionManager
PlatformTransactionManager pm =new DataSourceTransactionManager(dataSource);

此处创建了一个DataSourceTransactionManager对象,dataSource是数据源,点进去看源码。

	public DataSourceTransactionManager() {
	  //调用了父类的setNestedTransactionAllowed方法
		setNestedTransactionAllowed(true);
	}
	public DataSourceTransactionManager(DataSource dataSource) {
		//此处调用了上面的构造方法  
		this();
		setDataSource(dataSource);
		//判断dataSource是否为null
		afterPropertiesSet();
	}

这是父类的setNestedTransactionAllowed方法 对nestedTransactionAllowed 属性进行了赋值

public final void setNestedTransactionAllowed(boolean nestedTransactionAllowed) {
		//设置为可嵌套事务
		this.nestedTransactionAllowed = nestedTransactionAllowed;
	}

到了此处PlatformTransactionManager初始化完成。

2.初始化TransactionDefinition
TransactionDefinition td = new DefaultTransactionDefinition();

DefaultTransactionDefinition有两个构造方法我们此处用的第一个,第二个构造方法可以看出是将别的TransactionDefinition的实现属性进行赋值。DefaultTransactionDefinition里的属性对事务进行了描述,例如事务的隔离级别,传播途径,超时时间等等。

	public DefaultTransactionDefinition() {
	}
	public DefaultTransactionDefinition(TransactionDefinition other) {
		this.propagationBehavior = other.getPropagationBehavior();
		this.isolationLevel = other.getIsolationLevel();
		this.timeout = other.getTimeout();
		this.readOnly = other.isReadOnly();
		this.name = other.getName();
	}

TransactionDefinition初始化完成。
接下来获取事务当前状态

3.getTransaction方法
TransactionStatus ts = pm.getTransaction(td);
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
		//创建了DataSourceTransactionObject对象
		Object transaction = doGetTransaction();
		
		boolean debugEnabled = logger.isDebugEnabled();
		//如果definition为空此处会创建一个新的
		if (definition == null) {
			definition = new DefaultTransactionDefinition();
		}
		//判断是否有现有的事务,内部也是通过ConnectionHolder判断
		if (isExistingTransaction(transaction)) {
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

		// 检查事务的超时时间
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}

		// 此处获取当前事务的传播行为,走到这里意味着当前线程没有事务所以抛异常
		//PROPAGATION_MANDATORY当前存在事务则加入不存在则抛异常
		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) {
			//挂起事务的方法,此处参数为null就不进行挂起操作,对于有些传播途径会需要挂起操作,实际上的挂起操作就是将他从ThreadLocal中取出来然后放到一个SuspendedResourcesHolder对象中
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			try {
			//此处与事务同步有关,根据newSynchronization属性来判断是否需要事务同步
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				//创建了DefaultTransactionStatus对象
				DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				//开启事务,并设置事务的一些属性只读  超时时间  隔离级别等
				doBegin(transaction, definition);
				//将status  和  definition中的属性赋值给TransactionSynchronizationManager(为了保证线程安全用的ThreadLocal维护connection)
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
			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方法创建了DataSourceTransactionObject对象

protected Object doGetTransaction() {
		//创建了DataSourceTransactionObject对象
		DataSourceTransactionObject txObject = new DataSourceTransactionObject();
		//此处与嵌套事务有关,默认初始化Manager的时候已经赋值为true 所以此处也为true 嵌套事务的实现也需要靠SavePoint
		txObject.setSavepointAllowed(isNestedTransactionAllowed());
		//判断当前线程有没有连接
		ConnectionHolder conHolder =
				(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
		//有的话可以进行复用
		txObject.setConnectionHolder(conHolder, false);
		return txObject;
	}

doBegin方法开启了事务

@Override
	protected void doBegin(Object transaction, TransactionDefinition definition) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		Connection con = null;

		try {
		//此处还是判断如果当前线程没有连接则新获取一个
			if (!txObject.hasConnectionHolder() ||
					txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
					//获取连接
				Connection newCon = obtainDataSource().getConnection();
				if (logger.isDebugEnabled()) {
					logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
				}
				//将获取到的设置到ConnectionHolder属性
				txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
			}
		//设置连接的SynchronizedWithTransaction事务同步属性为true
		txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
		//获取连接
			con = txObject.getConnectionHolder().getConnection();
			//prepareConnectionForTransaction方法根据definition中对事务的描述,对connection的只读属性和事务的隔离级别进行了赋值,返回来的是事务的隔离级别。此处源码可以自己看一下。如果definition没有对属性进行赋值,则返回的是null,connection的隔离级别默认为REPEATABLE_READ
			Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
			//设置事务的隔离级别
			txObject.setPreviousIsolationLevel(previousIsolationLevel);
			//设置只读属性
			txObject.setReadOnly(definition.isReadOnly());

			//此处是开启事务,JDBC开启事务就是要设置AutoCommit为false
			if (con.getAutoCommit()) {
			//这个属性为了恢复autoCommit属性后面会用到  用来判断是否设置AutoCommit为true
				txObject.setMustRestoreAutoCommit(true);
				if (logger.isDebugEnabled()) {
					logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
				}
				//开启事务
				con.setAutoCommit(false);
			}
			//这个方法主要执行了一句SQL  SET TRANSACTION READ ONLY  如果definition中为只读那么就执行SQL 设置事务为只读
			prepareTransactionalConnection(con, definition);
			txObject.getConnectionHolder().setTransactionActive(true);
			//这个方法返回了definition中的超时时间
			int timeout = determineTimeout(definition);
			//如果与默认的不同,则设置给connect
			if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
				txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
			}

			//先进行判断是新创建的连接就绑定 
			if (txObject.isNewConnectionHolder()) {
				//该方法内部有ThreadLoacl把连接放到ThreadLoacl中与当前线程绑定
				TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
			}
		}

		catch (Throwable ex) {
		//如果出异常则释放资源,并且设置ConnectionHolder为null
			if (txObject.isNewConnectionHolder()) {
				DataSourceUtils.releaseConnection(con, obtainDataSource());
				txObject.setConnectionHolder(null, false);
			}
			throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
		}
	}
4.commit

中间执行完逻辑执行commit方法,我们来看看commit方法的实现

@Override
	public final void commit(TransactionStatus status) throws TransactionException {
		//判断事务是否已经提交,防止重复提交
		if (status.isCompleted()) {
			throw new IllegalTransactionStateException(
					"Transaction is already completed - do not call commit or rollback more than once per transaction");
		}

		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		//判断事务是否设置为回滚状态
		if (defStatus.isLocalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Transactional code has requested rollback");
			}
			processRollback(defStatus, false);
			return;
		}
//shouldCommitOnGlobalRollbackOnly默认返回false  isGlobalRollbackOnly与嵌套事务有关,此处先不讨论
		if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
			if (defStatus.isDebug()) {
				logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
			}
			processRollback(defStatus, true);
			return;
		}
		//提交事务的逻辑
		processCommit(defStatus);
	}

processCommit方法

private void processCommit(DefaultTransactionStatus status) throws TransactionException {
		try {
			boolean beforeCompletionInvoked = false;

			try {
				boolean unexpectedRollback = false;
				//提交事务前的处理,这个事务没有子类实现,父类也是空,暂时没啥用
				prepareForCommit(status);
				//事务提交前的处理
				triggerBeforeCommit(status);
				triggerBeforeCompletion(status);
				beforeCompletionInvoked = true;
				//判断是否有回滚点,此处先不讨论
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Releasing transaction savepoint");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					status.releaseHeldSavepoint();
				}
				//除非是新事务才会提交
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction commit");
					}
					unexpectedRollback = status.isGlobalRollbackOnly();
					//具体的提交事务,数据库层面
					doCommit(status);
				}
				else if (isFailEarlyOnGlobalRollbackOnly()) {
					unexpectedRollback = status.isGlobalRollbackOnly();
				}
				if (unexpectedRollback) {
					throw new UnexpectedRollbackException(
							"Transaction silently rolled back because it has been marked as rollback-only");
				}
			}
			catch (UnexpectedRollbackException ex) {
				
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
				throw ex;
			}
			catch (TransactionException ex) {
				
				if (isRollbackOnCommitFailure()) {
					doRollbackOnCommitException(status, ex);
				}
				else {
					triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				}
				throw ex;
			}
			catch (RuntimeException | Error ex) {
				if (!beforeCompletionInvoked) {
					triggerBeforeCompletion(status);
				}
				doRollbackOnCommitException(status, ex);
				throw ex;
			}
			try {
			//提交事务后的钩子方法
				triggerAfterCommit(status);
			}
			finally {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
			}

		}
		finally {
			cleanupAfterCompletion(status);
		}
	}

doCommit方法

protected void doCommit(DefaultTransactionStatus status) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
		Connection con = txObject.getConnectionHolder().getConnection();
		if (status.isDebug()) {
			logger.debug("Committing JDBC transaction on Connection [" + con + "]");
		}
		try {
			con.commit();
		}
		catch (SQLException ex) {
			throw new TransactionSystemException("Could not commit JDBC transaction", ex);
		}
	}
5.rollback
public final void rollback(TransactionStatus status) throws TransactionException {
		if (status.isCompleted()) {
			throw new IllegalTransactionStateException(
					"Transaction is already completed - do not call commit or rollback more than once per transaction");
		}

		DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
		processRollback(defStatus, false);
	}

processRollback方法

private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
		try {
			boolean unexpectedRollback = unexpected;

			try {
				triggerBeforeCompletion(status);
				//判断是否有回滚点  与嵌套事务有关 此处先不讨论
				if (status.hasSavepoint()) {
					if (status.isDebug()) {
						logger.debug("Rolling back transaction to savepoint");
					}
					status.rollbackToHeldSavepoint();
				}
				//如果是新事务
				else if (status.isNewTransaction()) {
					if (status.isDebug()) {
						logger.debug("Initiating transaction rollback");
					}
					//事务回滚
					doRollback(status);
				}
				else {
					
					if (status.hasTransaction()) {
						if (status.isLocalRollbackOnly() || isGlobalRollbackOnParticipationFailure()) {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - marking existing transaction as rollback-only");
							}
							doSetRollbackOnly(status);
						}
						else {
							if (status.isDebug()) {
								logger.debug("Participating transaction failed - letting transaction originator decide on rollback");
							}
						}
					}
					else {
						logger.debug("Should roll back transaction but cannot - no transaction available");
					}
					
					if (!isFailEarlyOnGlobalRollbackOnly()) {
						unexpectedRollback = false;
					}
				}
			}
			catch (RuntimeException | Error ex) {
				triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
				throw ex;
			}

			triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
			if (unexpectedRollback) {
				throw new UnexpectedRollbackException(
						"Transaction rolled back because it has been marked as rollback-only");
			}
		}
		finally {
			//释放资源  此处就会用到之前的一个属性  用来恢复autoCommit的状态
			cleanupAfterCompletion(status);
		}
	}

doRollback方法

@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 translateException("JDBC rollback", ex);
		}
	}

整体流程大致就是这样,暂时还没有看具体的嵌套事务的流程等等。仅仅是常规的一个流程,后面再慢慢挖掘

总结

Spring的编程式事务通过PlatformTransactionManager接口来管理

public interface PlatformTransactionManager extends TransactionManager {
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException;
	void commit(TransactionStatus status) throws TransactionException;
	void rollback(TransactionStatus status) throws TransactionException;

}

我们可以看到PlatformTransactionManager接口里面定义了三个方法,获取事务状态,提交事务,回滚事务三个方法。
通过TransactionStatus来描述事务的状态

public interface TransactionStatus extends TransactionExecution, SavepointManager, Flushable {
	boolean hasSavepoint();//判断是否有回滚点
	@Override
	void flush();//暂时不知道这个刷新是刷新什么

}

接下来是TransactionDefinition,这个接口主要是对事务的定义。例如传播行为,隔离级别等等。

public interface TransactionDefinition {
	int PROPAGATION_REQUIRED = 0;
	int PROPAGATION_SUPPORTS = 1;
	int PROPAGATION_MANDATORY = 2;
	int PROPAGATION_REQUIRES_NEW = 3;
	int PROPAGATION_NOT_SUPPORTED = 4;
	int PROPAGATION_NEVER = 5;
	int PROPAGATION_NESTED = 6;
	int ISOLATION_DEFAULT = -1;
	int ISOLATION_READ_UNCOMMITTED = 1;  
	int ISOLATION_READ_COMMITTED = 2;  
	int ISOLATION_REPEATABLE_READ = 4;  
	int ISOLATION_SERIALIZABLE = 8; 
	int TIMEOUT_DEFAULT = -1;
	default int getPropagationBehavior() {
		return PROPAGATION_REQUIRED;
	}
	default int getIsolationLevel() {
		return ISOLATION_DEFAULT;
	}
	default int getTimeout() {
		return TIMEOUT_DEFAULT;
	}
	default boolean isReadOnly() {
		return false;
	}
	@Nullable
	default String getName() {
		return null;
	}
	static TransactionDefinition withDefaults() {
		return StaticTransactionDefinition.INSTANCE;
	}

}

不同的框架通过这三个接口来实现他们各自的事务
在这里插入图片描述

以上均为个人理解,如果有错误,请大佬指出。谢谢。

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值