Spring Transaction 管理原理

原创
2019/02/21 10:53
阅读数 250

摘要

Spring 使用的都是声明式事务,不过在最开始时 Spring 支持的是编程式事务。本篇讲的是 Spring 最初版本 interface21(以下使用它指代spring的最初版本代码) 实现的事务即编程式事务。因为声明式事务只是提升了易用性,两者的内核是一致的。

环境与说明

jdk: 1.7
github: https://github.com/SixPenny/spring-framework-0.9.git
IDE: idea

在根目下的 docs 目录中有一个 tutorial.pdf 文件,描述了 Spring 该如何使用,是阅读代码的好帮手。

源码解析

核心类

interface21 使用的是编程式事务模型,使用上不如声明式事务模型方便,不过却有利于我们看清 Spring 是如何实现事务的。

Spring 事务的核心类是PlatformTransactionManager, 里面定义了事务相关的三个方法 获取事务对象getTransaction,提交事务 commit 和 回滚事务 rollback

TransactionStatus getTransaction(TransactionDefinition definition)
	    throws TransactionException;

void commit(TransactionStatus status) throws TransactionException;

void rollback(TransactionStatus status) throws TransactionException;

TransactionStatus 类是事务的上下文,后面的 commitrollback 都依赖于它,TransactionDefinition 是事务定义,包含了事务的传播方式、隔离方式和超时属性。

getTransaction 方法

接口的方法很少,事务开始、事务同步等都是怎么实现的呢? getTransaction 这个方法的语义包含了这些,可以在AbstractPlatformTransactionManagergetTransaction模板中找到具体的流程定义。

/**
 * This implementation of getTransaction handles propagation behavior and
 * checks non-transactional execution (on CannotCreateTransactionException).
 * Delegates to doGetTransaction, isExistingTransaction, doBegin.
 */
public final TransactionStatus getTransaction(TransactionDefinition definition)
    throws TransactionException {
	try {
		Object transaction = doGetTransaction();
		logger.debug("Using transaction object [" + transaction + "]");
		if (isExistingTransaction(transaction)) {
			logger.debug("Participating in existing transaction");
			return new TransactionStatus(transaction, false);
		}
		if (definition == null) {
			// use defaults
			definition = new DefaultTransactionDefinition();
		}
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new NoTransactionException("Transaction propagation mandatory but no existing transaction context");
		}
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED) {
			// create new transaction
			doBegin(transaction, definition.getIsolationLevel(), definition.getTimeout());
			if (this.transactionSynchronization) {
				TransactionSynchronizationManager.init();
			}
			return new TransactionStatus(transaction, true);
		}
	}
	catch (CannotCreateTransactionException ex) {
		// throw exception if transactional execution required
		if (!this.allowNonTransactionalExecution) {
			logger.error(ex.getMessage());
			throw ex;
		}
		// else non-transactional execution
		logger.warn("Transaction support is not available: falling back to non-transactional execution", ex);
	}
	catch (TransactionException ex) {
		logger.error(ex.getMessage());
		throw ex;
	}
	// empty (-> "no") transaction
	return new TransactionStatus(null, false);
}

我们来分析一下这个方法

  1. Object transaction = doGetTransaction(); 由子类实现的,返回一个事务对象,需要保证同一个事务返回的事务对象是同一个,事务对象中封装了连接、会话等信息,视具体实现而定。DataSourceTransactionManager 返回了一个封装了Connection的对象,HibernateTransactionManager 返回了一个封装了Session 的对象。
if (isExistingTransaction(transaction)) {
	logger.debug("Participating in existing transaction");
	return new TransactionStatus(transaction, false);
}

如果已经存在一个事务,则直接返回(此时还未加入PROPAGATION_REQUIRES_NEW 等属性,加入之后这个返回变成了handleExistingTransaction方法) 3.

if (definition == null) {
	// use defaults
	definition = new DefaultTransactionDefinition();
}

如果没有事务定义,就使用默认的事务定义 PROPAGATION_REQUIRED 与 ISOLATION_DEFAULT 4.

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
	throw new NoTransactionException("Transaction propagation mandatory but no existing transaction context");
}

如何事务定义指定使用 PROPAGATION_MANDATORY 方式,则抛出异常(到这是没有事务的路径,前面存在事务直接返回了) 5.

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED) {
	// create new transaction
	doBegin(transaction, definition.getIsolationLevel(), definition.getTimeout());
	if (this.transactionSynchronization) {
		TransactionSynchronizationManager.init();
	}
	return new TransactionStatus(transaction, true);
}

如果事务定义为PROPAGATION_REQUIRED, 则开启一个新事务, 模板方法doBegin由子类决定如何开启一个新事务。
DataSourceTransactionManager 中的事务开启定义如下

protected void doBegin(Object transaction, int isolationLevel, int timeout) {
	if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
		throw new InvalidTimeoutException("DataSourceTransactionManager does not support timeouts");
	}
	DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
	Connection con = txObject.getConnectionHolder().getConnection();
	logger.debug("Switching JDBC connection [" + con + "] to manual commit");
	try {
		if (isolationLevel != TransactionDefinition.ISOLATION_DEFAULT) {
			logger.debug("Changing isolation level to " + isolationLevel);
			txObject.setPreviousIsolationLevel(new Integer(con.getTransactionIsolation()));
			con.setTransactionIsolation(isolationLevel);
		}
		con.setAutoCommit(false);
	}
	catch (SQLException ex) {
		throw new CannotCreateTransactionException("Cannot configure connection", ex);
	}
	DataSourceUtils.getThreadObjectManager().bindThreadObject(this.dataSource, txObject.getConnectionHolder());
}

可以看到这里事务的开启就是保存当前jdbc connection 的autoCommit现场(在commitrollback中恢复),并将 autoCommit 设为 false

上面的5步就是事务的开始过程,相比现在功能不全,但是流程更加清晰,理解更加方便。

commitrollback 方法

commit 方法与rollback 方法提供了编程式回滚的功能,对嵌套事务提供支持,还提供了回调功能。

public final void commit(TransactionStatus status) throws TransactionException {
	if (status.isRollbackOnly()) {
		logger.debug("Transactional code has requested rollback");
		rollback(status);
	}
	else if (status.isNewTransaction()) {
		try {
			doCommit(status);
			triggerAfterCompletion(TransactionSynchronization.STATUS_COMMITTED);
		}
		catch (UnexpectedRollbackException ex) {
			triggerAfterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
			logger.error(ex.getMessage());
			throw ex;

		}
		catch (TransactionException ex) {
			triggerAfterCompletion(TransactionSynchronization.STATUS_UNKNOWN);
			logger.error(ex.getMessage());
			throw ex;
		}
		finally {
			TransactionSynchronizationManager.clear();
		}
	}
}
public final void rollback(TransactionStatus status) throws TransactionException {
	if (status.isNewTransaction()) {
		try {
			doRollback(status);
			triggerAfterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK);
		}
		catch (TransactionException ex) {
			triggerAfterCompletion(TransactionSynchronization.STATUS_UNKNOWN);
			logger.error(ex.getMessage());
			throw ex;
		}
		finally {
			TransactionSynchronizationManager.clear();
		}
	}
	else if (status.getTransaction() != null) {
		try {
			doSetRollbackOnly(status);
		}
		catch (TransactionException ex) {
			logger.error(ex.getMessage());
			throw ex;
		}
	}
	else {
		// no transaction support available
		logger.info("Should roll back transaction but cannot - no transaction support available");
	}
}

前面说的恢复 autoCommit 属性是在子类中实现的(现场保存也是在子类中),大家可以去看DataSourceTransactionManager 类的closeConnection方法。

使用方式

使用方式非常简单,下面是一个参考资料1 中的例子,很简单,就不多说了。

public void persistOrderItems() {
      TransactionStatus ts =
              transactionManager.getTransaction(new DefaultTransactionDefinition());
      try {
          long id = dao.save(new OrderItem("BWell Ethernet Cable", 5));
          id = dao.save(new OrderItem("EDrive SSD", 2000));
          transactionManager.commit(ts);
      } catch (Exception e) {
              transactionManager.rollback(ts);
      }
  }

也可以使用周边类中的TransactionTemplate,里面定义了主流程,我们只需要定义自己的执行方法就可以了。

周边类

TransactionTemplate

Spring 封装了一个简单类供我们使用 TransactionTemplate, 它的核心方法是 execute,虽然叫 Template, 实际上是一个回调模式的应用。

public Object execute(TransactionCallback action) throws TransactionException, RuntimeException {
	TransactionStatus status = this.transactionManager.getTransaction(this);
	try {
		Object result = action.doInTransaction(status);
		this.transactionManager.commit(status);
		return result;
	}
	catch (TransactionException tse) {
		throw tse;
	}
	catch (RuntimeException ex) {
		// transactional code threw exception
		this.transactionManager.rollback(status);
		throw ex;
	}
}

TransactionCallback 是我们定义的需要执行的方法回调,TransactionTemplate 帮我们处理了提交与回滚操作。(TransactionCallback 在interface21 中只有一个默认实现,还没有返回结果,不过我们注重的是这个结构)

TransactionSynchronization

TransactionSynchronization 提供了事务同步相关的方法,interface21 中只包含了 void afterCompletion(int status); 方法,现在的Spring 包含了更多的方法,用户可以使用这个注册事务提交,完成之后的回调任务。

TransactionInterceptor

这是一个cglib 代理实现的事务拦截器,是声明式事务的雏形,有兴趣的可以看一下

参考网址

  1. Spring - Programmatic Transaction
  2. Spring MVC type conversion : PropertyEditor or Converter?
  3. Spring Property Editor – CustomEditorConfigurer Example
  4. Spring Framework’s WebDataBinder
  5. <Spring>属性编辑器, PropertyEditor, JavaBean-
展开阅读全文
打赏
0
3 收藏
分享
加载中
更多评论
打赏
0 评论
3 收藏
0
分享
返回顶部
顶部