Spring事务管理的另一种方式--TransactionTemplate编程式事务管理简单入门

1, 一直以来, 在用Spring进行事物管理时, 只知道用声明式的策略, 即根据不同的数据源, 配置一个事物管理器(TransactionManager), 通过配置切面(PointCut)应用到相应的业务方法上或者直接在方法上加@Ttransactional注解.

  这种事务管理使用起来比较简单,但个人感觉灵活性欠缺了点.

 

2, 最近看公司项目代码, 发现有位同事在他的模块了用了另外一种事务管理方式, 查了一下,TransactionTemplate是编程式事务管理.需要自己手动在每个业务方法中实现事务.

 

3, TransactionTemplate使用(不一定全面):

  A, 在DAO层的配置文件中, 配置TransactionTemplate, 需要注入TransactionManager

  

    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="transactionTemplate"
          class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
    </bean>

B, 将TransactionTemplate注入到业务层方法中, 并使用:

  首先分析一下TransactionTemplate的核心原理:

  TransactionTemplate核心方法:

 1 public class TransactionTemplate extends DefaultTransactionDefinition
 2         implements TransactionOperations, InitializingBean {
 3 
 4 
 5     public <T> T execute(TransactionCallback<T> action) throws TransactionException {
 6         if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
 7             return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
 8         }
 9         else {
10             TransactionStatus status = this.transactionManager.getTransaction(this);
11             T result;
12             try {
13                 result = action.doInTransaction(status);
14             }
15             catch (RuntimeException ex) {
16                 // Transactional code threw application exception -> rollback
17                 rollbackOnException(status, ex);
18                 throw ex;
19             }
20             catch (Error err) {
21                 // Transactional code threw error -> rollback
22                 rollbackOnException(status, err);
23                 throw err;
24             }
25             catch (Exception ex) {
26                 // Transactional code threw unexpected exception -> rollback
27                 rollbackOnException(status, ex);
28                 throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
29             }
30             this.transactionManager.commit(status);
31             return result;
32         }
33     }

由上面的代码可以推测到, 真正执行业务方法的关键代码是: action.doInTransaction(status);

正好, 有个入参TransactionCallback<T>, 翻看该接口的源码:

1 public interface TransactionCallback<T> {
2 
5     T doInTransaction(TransactionStatus status);
6 
7 }

该接口只有一个doInTransaction方法, 那么很简单, 我们可以通过匿名内部类的方式将业务代码放在doInTransaction中:

举例如下:

 1 private PayOrderDAO payOrderDAO;  
 2   
 3 protected TransactionTemplate transactionTemplate;  
 4   
 5 /** 
 6  * 保存支付订单 
 7  */  
 8 protected PayOrder savePayReq(final PayOrder payOrder) {  
 9     
10     @Autowired
11     private TransactionTemplate transactionTemplate;
12   
13      @Autowired
14     private PayOrderDAO payOrderDAO;
15   
16     PayOrder order = (PayOrder) this.transactionTemplate  
17             .execute(new TransactionCallback() {  
18                 @Override  
19                 public Object doInTransaction(TransactionStatus status) {  
20                     // 查看是否已经存在支付订单,如果已经存在则返回订单主键  
21                     PayOrder payOrderTemp = payOrderDAO.findOrder(String  
22                             .valueOf(payOrder.getPayOrderId()));  
23   
24                     // 由支付渠道类型(PayChannelType)转换得到交易类型(PayType)  
25                     if (payOrder.getPayChannelId().equalsIgnoreCase(PAY_CHNL_ACT_BAL)) {// 账户余额支付  
26                         payOrder.setPayType("3");  
27                     } else if (payOrder.getPayChannelId().equalsIgnoreCase(PAY_CHNL_FAST_PAY)) {// 联通快捷支付  
28                         payOrder.setPayType("4");  
29                     } else {// 网银网关支付  
30                         payOrder.setPayType("2");  
31                     }  
32   
33                     // 比对新的支付金额与原订单金额是否一致,如不一致则提示错误  
34                     if (payOrderTemp == null) {  
35                         String orderId = payOrderDAO.save(payOrder);  
36                         payOrder.setPayOrderId(orderId);  
37                         return payOrder;  
38                     } else {  
39                         return payOrderTemp;  
40                     }  
41                 }  
42             });  
43     if ("2".equals(order.getOrderState())) {// 2:表示支付成功  
44         throw new EpaymentBizException(StatusCode.DQSystem.PAY_FAIL,  
45                 "同一订单不能重复支付");  
46     } else if (payOrder.getPayAmt().longValue() != order.getPayAmt()  
47             .longValue()) {  
48         throw new EpaymentBizException(StatusCode.DQSystem.PAY_FAIL,  
49                 "交易金额与原订单不一致");  
50     } else {  
51         return payOrder;  
52     }  
53   
54 }  

 

posted @ 2017-06-05 14:44  Eric.java  阅读(23190)  评论(2编辑  收藏  举报