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