前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Transaction 管理原理

Spring Transaction 管理原理

作者头像
Dylan Liu
发布2019-07-01 13:19:55
6200
发布2019-07-01 13:19:55
举报
文章被收录于专栏:dylanliudylanliu

摘要

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

代码语言:javascript
复制
TransactionStatus getTransaction(TransactionDefinition definition)
	    throws TransactionException;

void commit(TransactionStatus status) throws TransactionException;

void rollback(TransactionStatus status) throws TransactionException;

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

getTransaction 方法

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

代码语言:javascript
复制
/**
 * 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 的对象。
代码语言:javascript
复制
if (isExistingTransaction(transaction)) {
	logger.debug("Participating in existing transaction");
	return new TransactionStatus(transaction, false);
}

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

代码语言:javascript
复制
if (definition == null) {
	// use defaults
	definition = new DefaultTransactionDefinition();
}

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

代码语言:javascript
复制
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
	throw new NoTransactionException("Transaction propagation mandatory but no existing transaction context");
}

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

代码语言:javascript
复制
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 中的事务开启定义如下

代码语言:javascript
复制
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 方法提供了编程式回滚的功能,对嵌套事务提供支持,还提供了回调功能。

代码语言:javascript
复制
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 中的例子,很简单,就不多说了。

代码语言:javascript
复制
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, 实际上是一个回调模式的应用。

代码语言:javascript
复制
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-
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 环境与说明
  • 源码解析
    • 核心类
      • getTransaction 方法
      • commit 与 rollback 方法
      • 使用方式
    • 周边类
      • TransactionTemplate
      • TransactionSynchronization
      • TransactionInterceptor
  • 参考网址
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档