美文网首页
幂等性实现方案

幂等性实现方案

作者: 守住阳光 | 来源:发表于2018-11-28 19:50 被阅读0次

    一、什么是幂等性

            所谓幂等性,简单地说,就是对接口的多次调用所产生的结果和调用一次是一致的。扩展一下,这里的接口,可以理解为对外发布的HTTP接口或者Thrift接口,也可以是接收消息的内部接口,甚至是一个内部方法或操作。

    二、应用场景

    支付业务

            如上图所示用户下单后点击支付按钮进行支付。支付系统根据单号创建支付记录,然后调用银行接口,当一行扣款成功后,支付表修改支付状态为已支付。

            但是,存在这样的情况,用户点击按钮无效,连续点击多次,是否会出现同一个订单支付多次?如何避免?这就是今天要讲的的幂等性。

            作为对比,先看没有实现幂等性,也就是用户连续点击按钮,多次调用银行接口的情况。代码如下:

    public void  payForOrder(String orderId){

            Order order = orderDao.findById(orderId);

            Payment payment = paymentDao.findPaymentByOrderId(orderId);

            payment.setOrderId(orderId);

            payment.setMoney(order.getMoney());

            payment.setPayStatus("0");//正在处理中

            paymentDao.update(payment);

            String flag = tranService.invoke(url,paymentId); //调用银行接口

            payment.setPayStatus(flag);

            paymentDao.update(payment);

    }

            有上面代码可知,当用户对一个单多次点击支付时,上面的代码一定会出现多次调用银行接口的情况。那么问题来了,如何保证幂等性?

    介绍一个使用乐观锁实现幂等性的方案。通过新增版本号字段来实现。先看代码:

    public payForOrder(String orderId){

            Order order = orderDao.findById(orderId);

            Payment payment = paymentDao.findPaymentByOrderId(orderId);

            boolean invokeInterface = false ;

            payment.setOrderId(orderId);

            payment.setMoney(order.getMoney());

            payment.setPayStatus("0");//正在处理中

            payment.setVersion(0);

            int records = paymentDao.updateByVersion(payment);

            if(records ){

                    String flag = tranService.invoke(url,payment.getId()); //调用银行接口

                    payment.setPayStatus(flag);   

                    paymentDao.update(payment);

            }else{

                    logger.error("重复调用............+orderId="+orderId);

            }

    }

    updateByVersion的模拟代码为:

    update  t_payment  set  orderId = #{orderId} , money=#{money},  payStatus=#{payStatus}  version=#{ version } +1 

    where id=#{id} and version=#{version}

            用户第一次点击时  paymentDao.updateByVersion(payment) 的返回值为1 ,此时可以调用银行接口;当第二次点击时updateByVersion的返回值为 0 ,不会调用银行接口,实现了幂等性。

    相关文章

      网友评论

          本文标题:幂等性实现方案

          本文链接:https://www.haomeiwen.com/subject/hxyzqqtx.html