zoukankan      html  css  js  c++  java
  • 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 }  
  • 相关阅读:
    数据库表结构变动发邮件脚本
    .net程序打包部署
    无法登陆GitHub解决方法
    netbeans 打包生成 jar
    第一次值班
    RHEL6 纯命令行文本界面下安装桌面
    C语言中格式化输出,四舍五入类型问题
    I'm up to my ears
    How to boot ubuntu in text mode instead of graphical(X) mode
    the IP routing table under linux@school
  • 原文地址:https://www.cnblogs.com/wyisprogramming/p/6944878.html
Copyright © 2011-2022 走看看