Spring事务:编程式事务管理

一、背景

       在上一篇Spring事务:事务属性和API简介中,初步地介绍了关于Spring事务的一些属性和主要的API,这一篇主要论述的是Spring事务中的编程史事务管理。

 

二、编程式事务管理

1、Spring的编程式事务管理概述

       在Spring出现以前,编程式事务管理对基于POJO的应用来说是唯一选择。之前学习过Hibernate,这里面的事务管理是需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,这就是编程式事务管理。通过Spring提供的事务管理API,我们可以在代码中灵活控制事务的执行。在底层,Spring仍然将事务操作委托给底层的持久化框架来执行。

2、基于底层API的编程式事务管理

       根据PlatformTransactionManager、TransactionDefinition和TransactionStatus三个核心接口,我们完全可以通过编程的方式来进行事务管理。示例代码如下所示:

public class BankServiceImpl implements BankService {
    private BankDao bankDao;
    private TransactionDefinition txDefinition;
    private PlatformTransactionManager txManager;
    ......
    public boolean transfer(Long fromId, Long toId, double amount) {
        TransactionStatus txStatus = txManager.getTransaction(txDefinition);
        boolean result = false;
        try {
             result = bankDao.transfer(fromId, toId, amount);
             txManager.commit(txStatus);
        } catch (Exception e) {
             result = false;
             txManager.rollback(txStatus);
             System.out.println("Transfer Error!");
        }
        return result;
    }
}
相应的配置文件如下所示:
<bean id="bankService" class="footmark.spring.core.tx.programmatic.origin.BankServiceImpl">
   <property name="bankDao" ref="bankDao"/>
   <property name="txManager" ref="transactionManager"/>
   <property name="txDefinition">
      <bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
         <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
      </bean>
   </property>
</bean>
       如上所示,我们在类中增加了两个属性:一个是TransactionDefinition类型的属性,它用于定义一个事务;另一个是PlatformTransactionManager类型的属性,用于执行事务管理操作。如果方法需要实施事务管理,我们首先需要在方法开始执行前启动一个事务,调用PlatformTransactionManager.getTransaction(...) 方法便可启动一个事务。创建并启动了事务之后,便可以开始编写业务逻辑代码,然后在适当的地方执行事务的提交或者回滚。

3、基于TransactionTemplate的编程式事务管理

       通过前面的示例可以发现,这种事务管理方式很容易理解,但令人头疼的是,事务管理的代码散落在业务逻辑代码中,破坏了原有代码的条理性,并且每一个业务方法都包含了类似的启动事务、提交/回滚事务的样板代码。Spring在数据访问层非常常见的模板回调模式,如下所示:

public class BankServiceImpl implements BankService {
    private BankDao bankDao;
    private TransactionTemplate transactionTemplate;
    ......
    public boolean transfer(final Long fromId, final Long toId, final double amount) {
        return (Boolean) transactionTemplate.execute(new TransactionCallback(){
            public Object doInTransaction(TransactionStatus status) {
                Object result;
			try {
			     result = bankDao.transfer(fromId, toId, amount);
			} catch (Exception e) {
			     status.setRollbackOnly();
			     result = false;
			     System.out.println("Transfer Error!");
			}
                return result;
            }
        });
    }
}

相应的配置文件如下:

<bean id="bankService" class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">
   <property name="bankDao" ref="bankDao"/>
   <property name="transactionTemplate" ref="transactionTemplate"/>
</bean>

       

       TransactionTemplate的execute()方法有一个TransactionCallback类型的参数,该接口中定义了一个doInTransaction()方法,通常我们以匿名内部类的方式实现TransactionCallback接口,并在其doInTransaction()方法中书写业务逻辑代码。这里可以使用默认的事务提交和回滚规则,这样在业务代码中就不需要显式调用任何事务管理的API。doInTransaction()方法有一个TransactionStatus类型的参数,我们可以在方法的任何位置调用该参数的setRollbackOnly()方法将事务标识为回滚的,以执行事务回滚。

根据默认规则,如果在执行回调方法的过程中抛出了未检查异常,或者显式调用了TransacationStatus.setRollbackOnly()方法,则回滚事务;如果事务执行完成或者抛出了checked类型的异常,则提交事务。

        TransactionCallback接口有一个子接口TransactionCallbackWithoutResult,该接口中定义了一个doInTransactionWithoutResult()方法,TransactionCallbackWithoutResult接口主要用于事务过程中不需要返回值的情况。当然,对于不需要返回值的情况,我们仍然可以使用TransactionCallback接口,并在方法中返回任意值即可。

三、总结

       这篇主要介绍了Spring中的编程式的事务管理,下一篇主要介绍下Spring事务中的声明式事务管理,有兴趣的小伙伴可以继续阅读。

猜你喜欢

转载自zh-workhard-java.iteye.com/blog/2348159