Spring 使用的都是声明式事务,不过在最开始时 Spring 支持的是编程式事务。本篇讲的是 Spring 最第一版本 interface21(如下使用它指代spring的最第一版本代码) 实现的事务即编程式事务。由于声明式事务只是提高了易用性,二者的内核是一致的。html
jdk: 1.7
github: https://github.com/SixPenny/spring-framework-0.9.git
IDE: ideajava
在根目下的 docs 目录中有一个 tutorial.pdf 文件,描述了 Spring 该如何使用,是阅读代码的好帮手。git
interface21 使用的是编程式事务模型,使用上不如声明式事务模型方便,不过却有利于咱们看清 Spring 是如何实现事务的。github
Spring 事务的核心类是PlatformTransactionManager
, 里面定义了事务相关的三个方法 获取事务对象getTransaction
,提交事务 commit
和 回滚事务 rollback
web
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException;
TransactionStatus
类是事务的上下文,后面的 commit
与 rollback
都依赖于它,TransactionDefinition
是事务定义,包含了事务的传播方式、隔离方式和超时属性。spring
getTransaction
方法接口的方法不多,事务开始、事务同步等都是怎么实现的呢? getTransaction
这个方法的语义包含了这些,能够在AbstractPlatformTransactionManager
的getTransaction
模板中找到具体的流程定义。编程
/** * 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); }
咱们来分析一下这个方法spring-mvc
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.mvc
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
现场(在commit
或 rollback
中恢复),并将 autoCommit
设为 false
。
上面的5步就是事务的开始过程,相比如今功能不全,可是流程更加清晰,理解更加方便。
commit
与 rollback
方法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 代理实现的事务拦截器,是声明式事务的雏形,有兴趣的能够看一下