欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring事务:编程式事务管理

程序员文章站 2022-07-13 12:20:44
...

一、背景

       在上一篇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事务中的声明式事务管理,有兴趣的小伙伴可以继续阅读。