摘要
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
类是事务的上下文,后面的 commit
与 rollback
都依赖于它,TransactionDefinition
是事务定义,包含了事务的传播方式、隔离方式和超时属性。
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);
}
我们来分析一下这个方法
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
现场(在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 代理实现的事务拦截器,是声明式事务的雏形,有兴趣的可以看一下