Spring声明式事务管理踩过

当前系统使用Spring声明式事务来做事务管理,出现了一个非常诡异的bug,且看代码辅助细说。

 

Spring声明式事务配置:

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

        <tx:attributes>

            <tx:method name="handle*"  propagation="REQUIRED"  rollback-for="Exception"/>

            <tx:method name="inner*"  propagation="REQUIRES_NEW"  rollback-for="Exception"/>

            <tx:method name="*"   propagation="SUPPORTS"    read-only="true" />

        </tx:attributes>

    </tx:advice>

 

    <aop:config>

        <aop:pointcut id="interceptorPointCuts" expression="execution(* service..*.*(..))" />        <!-- 扫描路径service包下 -->

        <aop:advisor advice-ref="txAdvice" pointcut-ref="interceptorPointCuts"/>

    </aop:config>

 

 

Service包下的接口:

public interfaceISPOrderService {

   public enum DealStatusEnum {

        RISK_FAIL_BEYOND_AMT("0", "风控审核失败,超出借款限额!"), RISK_FAIL_REJECT("1", "风控审核驳回!"), RISK_FAIL_EXCEPTION("2", "风控审核异常!"),

        LACK_OF_CFG("3", "缺少配置信息!");

       

        private final String code;

        private final String name;

        private DealStatusEnum(String code, String name) {

            this.code = code;

            this.name = name;

        }

        public String getCode() {

            return code;

        }

        public String getName() {

            return name;

        }

   }

   

   /**

     * 处理订单

     * @return

     */

   public DealStatusEnum handleYlOrderReq(Stringreq_sn,String trans_date,String terminal_id,String merchant_id,String submit_time, String order_sn,String trans_amt, String acct_id);

   /**

     * 保存订单信息

     * @return

     */

   public boolean innerSaveOrder(Orderorder);

}

 

 //实现类

@Service

public classSPOrderServiceImpl implements ISPOrderService {

   privateLogger logger= LoggerFactory.getLogger(SPOrderServiceImpl.class);

   @Autowired

   privateOrderDao orderDao;

   @Autowired

   privateISPInnerOrderService innerOrderService;

   @Autowired

   privateRiskAuthService riskAuthService;

   @Autowired

   privateUserCardMapDao cardMapDao;

   @Autowired

   privateLoanTempCfgDao loanTempCfgDao;

   @Autowired

   privateLoanInfoDao loanInfoDao;

 

   @Override

   publicDealStatusEnum handleYlOrderReq(String req_sn, String trans_date, String terminal_id, String merchant_id,

            String submit_time, String order_sn, String trans_amt, String acct_id) {

        try {

            BigDecimal transAmount = new BigDecimal("trans_amt");

            Date currentTime = new Date();

            Order order = new Order();

            order.setCardNo(acct_id);

            order.setCreateTime(new Date());

            order.setLiquidationTime(DateUtil.getFormattedDate(DateUtil.DATE_FORMAT_YYYYMMDD,trans_date));

            order.setMerchantNo(merchant_id);

            order.setOrderNo(order_sn);

            order.setOrderStatus(DictConstant.orderStatus.WATI_PAY.getCode());

            order.setReturnAmount(BigDecimal.ZERO);

            order.setSubmitTime(DateUtil.getFormattedDate(DateUtil.DATE_FORMAT_YYYYMMDDHHMMSS, submit_time));

            order.setTransAmount(transAmount);

            order.setTransTime(DateUtil.getFormattedDate(DateUtil.DATE_FORMAT_YYYYMMDDHHMMSS, submit_time));

            innerSaveOrder(order);//新开事务,插入订单信息,风控审核系统要基于订单信息做风控审核

            //风控审核

            Map<String,Object> cardMapParam = newHashMap<String,Object>();

            cardMapParam.put("cardNo", acct_id);

            UserCardMapVO cardMapVo = cardMapDao.selectByParams(cardMapParam);

            //调用风控系统,审核是否允许下单(另一个系统,post请求)

            RiskResult authResult = riskAuthService.auditLoanClaim(String.valueOf(cardMapVo.getCustId()), order_sn);

            if(! authResult.isSuccess()){

                return DealStatusEnum.RISK_FAIL_EXCEPTION;

            }

            Order updateOrder = new Order();

            updateOrder.setOrderNo(order_sn);

            updateOrder.setOrderStatus(DictConstant.orderStatus.PAIED.getCode());

            orderDao.updateByPrimaryKeySelective(updateOrder);

           

            //TODO   后续逻辑,此处省略

                        

        } catch (Exception e) {

            logger.error("handleYlOrderReq exception 4 param,req_sn:"+req_sn+" trans_date:"+trans_date+" merchant_id:"+merchant_id

                    +"  submit_time:"+submit_time+" order_sn:"+order_sn+" trans_amt:"+trans_amt+" acct_id:"+acct_id,e);

        }

        return null;

}

 

   @Override

   public boolean innerSaveOrder(Orderorder){

        orderDao.insert(order);

        return true;

    }

}


在以上处理订单的逻辑中,我在方法handleYlOrderReq中调用了同一个service中的方法innerSaveOrder,在事务配置中,我给inner配置的是ropagation="REQUIRES_NEW" ,也就是新开事务处理,因此我期望的效果是在执行到innerSaveOrder(order);这行代码,新开事务,将订单信息保存到数据库,后续调用风控系统,风控系统根据保存的订单信息来做风控审核。但事与愿违,执行到innerSaveOrder(order);并没有提交事务,而是要等到方法handleYlOrderReq执行结束才会提交事务插入订单信息,因此执行到以下代码

RiskResult authResult = riskAuthService.auditLoanClaim(String.valueOf(cardMapVo.getCustId()), order_sn);

请求风控系统的时候,其实库里还没有当前这笔订单,一次风控审核始终失败。

经过查证,发现导致该问题的原因。方法handleYlOrderReq与方法innerSaveOrder都是在同一个service中的,Spring对事物管理的原则是,同一个Service中的方法嵌套调用,事务类型以入口方法(此处为handleYlOrderReq)为准,被调用的方法继承调用它的事务类型,也就是配置的<tx:method name="handle*"  propagation="REQUIRED"  rollback-for="Exception"/>,因此两个方法是同一个事务,在方法handleYlOrderReq执行结束之前,方法innerSaveOrder的插入语句不会作为一个新开事务提交。


综上,如果希望新开事务,那么一定要在另外一个service中去实现这个方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值