• 用redis的订阅发布解决了扫码支付实时响应的问题


    一、场景描述:

           PC收银台的浏览器展示了收款二维码,用户扫了支付二维码,支付完成后,浏览器需要实时响应支付结果。

    二、问题描述:

          扫码支付的支付结果一般通过服务端回调和主动查询来获取,显示二维码之后,不断的去轮询的话,增加了服务器的压力。如果服务端回调支付结果,能立马把支付结果响应给收银台的浏览器,问题就解决了。前端调用一次查询,如果状态还是处理中,就阻塞在那里,直到有支付结果再响应浏览器,想要阻塞,最开始想到用Java的队列,单机没问题,但是生产上的回调服务器和交易服务器不是同一台,所以无效。

    三、实现逻辑:

           交易服务器获取收款二维码,在前端显示,在等待用户支付的同时,调用一次查询,在后台的查询方法中,如果支付完成,立马响应支付结果,如果没有支付完成,就利用redis订阅支付结果,用户扫码支付完成之后,微信、支付宝或银联会异步回调通知我们的回调服务器,我们回调服务器再调用redis的发布,把支付结果发布出去,这个时候交易服务器就订阅到支付结果了,就可以向浏览器作响应了。

    四、实现代码:

        1、redis工具类

    public class RedisFactory {

    private static final Log logger = LogFactory.getLog(RedisFactory.class);
      private static Jedis jedis;
    //此处省略jedis初始化的代码
      public static  String subscribeMessage(String channel){
    try{
    final String[] objs=new String[1];
    //首先初始化一个消息监听器对象,用匿名内部类
    JedisPubSub listener = new JedisPubSub(){
    @Override
    public void onMessage(String channel, String message) {//重写监听新消息的方法,redis在这个频道发布消息之后,这里才能在这个频道读取消息
    objs[0]= message;
    this.unsubscribe();//读取读取到消息之后,就取消订阅这个频道
    }
    };
    subscribe(listener,channel);//利用上面初始化好的监听器和指定频道,开始订阅消息,阻塞在这里,直到监听器的onMessage方法被执行之后,才结束
    return objs[0];//返回订阅获取到的消息
    } catch (Throwable e) {
    logger.error("subscribe channels["+channel+"] ", e);
    }
    return null;
    }
    //订阅消息
    public static void subscribe(JedisPubSub listener,final String channel){
    try {
       jedis.subscribe(listener, channel);
    } catch (Throwable e) {
    logger.error("subscribe channels["+channel+"] ", e);
    }
    }
    //发布消息
    public static boolean publish(final String channel,String msg){
    try {
       Long num=jedis.publish(channel, msg);
      return true;
    } catch (Throwable e) {
    logger.error("subscribe channel["+channel+"] msg["+msg+"] "+e.getMessage(), e);
    }
    return false;
    }
    }

    2、订阅支付状态的部分代码:
     status =RedisFactory.subscribeMessage(channel);

    3、发布支付状态的代码:
    RedisFactory.publish(channel,msg);
     

    五、遇到的问题:

      今天测试了一下,支付完成了,在更新支付结果的方法里发布了支付结果,就订阅了,结果订阅的不是最新的状态。后来断点分析了代码,执行完了更新和发布方法,订阅的地方立马就订阅了,但是查数据库,发现数据还没更新,因为更新和发布这些方法在一个事务里面,事务中后续方法还没执行完成,事务还没结束,所以虽然发布了,事务还没结束,数据更新还没提交就开始查询,查到的数据不是最新的,这说明了发布订阅响应速度太快了。

    六、解决办法:

      1、在更新的事务结束之后再发布支付状态。(带有事务的更新方法在很多地方被调用,在外层加方法改动太多,不现实)     

      2、在订阅的地方,订阅到消息,不会立马去数据库查询,每间隔等待一会儿再查,直到查到最终结果为止。

  • 相关阅读:
    ASP.Net如何用Cookies保存对象
    MS SQL语句优化
    服务消费者
    [模板]线性筛素数(欧拉筛法)
    luogu4159 迷路 (矩阵加速)
    poj1845 sumdiv (因数的和)
    luogu3674 小清新人渣的本愿 (bitset+莫队)
    luogu3621 城池攻占 (倍增)
    luogu3233 世界树 (虚树)
    bzoj4540 序列 (单调栈+莫队+rmq)
  • 原文地址:https://www.cnblogs.com/XiaoyangBoke/p/8691424.html
Copyright © 2020-2023  润新知