用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、在订阅的地方,订阅到消息,不会立马去数据库查询,每间隔等待一会儿再查,直到查到最终结果为止。
用redis的订阅发布解决了扫码支付实时响应的问题的更多相关文章
- Redis之Redis消息订阅发布简介
概念: Redis消息订阅发布是进程间的一种消息通信模式,发送者pub发送消息,订阅者sub接收消息. 使用须知: 需要先订阅后发布,才能接收到消息.在订阅时,相当于创建了可供发布的频道. 案例: ( ...
- 微信支付之扫码支付开发:我遇到的坑及解决办法(附:Ecshop 微信支付插件)
前段时间帮一个朋友的基于ecshop开发的商城加入微信扫描支付功能,本以为是很简单的事儿——下载官方sdk或开发帮助文档,按着里面的做就ok了,谁知折腾了两三天的时间才算搞定,中间也带着疑问在网上找了 ...
- 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付
微信支付教程系列之扫码支付 今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...
- 微信支付Native扫码支付模式二之CodeIgniter集成篇
CI:3.0.5 微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/ ...
- (实用篇)微信支付扫码支付php版
本文实例为大家分享了php微信扫码支付源码,供大家参考,具体内容如下 代码中包含四个文件createUrl.php.ArrayToXML.php.returnGoodsUrl.php.notifyUr ...
- c#版在pc端发起微信扫码支付
等了好久,微信官方终于发布了.net的demo. 主要代码: /** * 生成直接支付url,支付url有效期为2小时,模式二 * @param productId 商品ID * @return 模式 ...
- C# 微信支付教程系列之扫码支付
微信支付教程系列之扫码支付 今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添加好友的时候 ...
- 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结
最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...
- 微信小程序使用场景延伸:扫码登录、扫码支付
微信小程序使用场景延伸:扫码登录.扫码支付 小程序最适合的使用场景有哪些?相比大家能列举出来很多,但这个场景,大家可能多数没想到_^ 笔者团队近期接到了一个PC项目:转转游戏租号PC官网,该项目要求在 ...
随机推荐
- JAVA-基础语法篇
JAVA-基础语法篇 一. 基础语法: 对大小写敏感 类名的首字母大写 方法名首字母小写,后面用驼峰发命名 源文件名和类名要相同 主方法入口: public static void main( ...
- linux下各种解压方法
linux下各种格式的压缩包的压缩.解压方法.但是部分方法我没有用到,也就不全,希望大家帮我补充,我将随时修改完善,谢谢! .tar 解包:tar xvf FileName.tar 打包:t ...
- Hibernate学习(4)- Hibernate对象的生命周期
1.Hibernate对象的生命周期(瞬时状态.持久化状态.游离状态) 1.瞬时状态(Transient): 使用new操作符初始化的对象就是瞬时状态,没有跟任何数据库数据相关联:2.持久化状态(Pa ...
- 项目Beta冲刺预热
Beta准备 1. 讨论组长是否重选的议题和结论. 经过讨论,我们认为,经过一段时间的磨合,现任组长是不需要更换的. 2. 下一阶段需要改进完善的功能. 增加关于征信的功能,贴近选题主题 美化界面,尽 ...
- Mysql 相关操作
1.用户管理 创建用户 create user '用户名'@'IP地址' identified by '密码'; 删除用户 drop user '用户名'@'IP地址'; 修改用户 rename us ...
- JAVA_SE基础——6.标识符&关键字
学会写helloworld之后, 我们就开始来认识标识符&关键字 一.标识符 标识符是指可被用来为类.变量或方法等命名的字符序列,换言之,标识符就是用户自定义的名称来标识类.变量或方法等.更 ...
- PC或者手机弹出窗效果
http://layer.layui.com/ 这个网站提供弹窗,是在jq封装的,弹窗之后,背景页面还可以滑动. 这个里面的js可能也会包含css,这个css不能移动位置,否则会报错,还有谷歌浏览器在 ...
- C++ 实现一个信号量
C++ 实现一个信号量 信号量有很多应用场景,事实上只要是生产者-消费者模型,一般都需要一个信号量来控制. POSIX接口是有PV信号量API的.但C++标准没有.下面是一个PV信号量的简单实现.有些 ...
- AngularJS1.X学习笔记8-自定义指令(上)
AngulaJS的指令是一种非常强大的特性,一个ng-repeat就能让我们非常方便的展示一个数据列表,指令相当于是一个组件,为我们将一些东西封装起来了,提供了复用的可能性.个人认为自定义指令还是比较 ...
- ELK学习总结(3-2)elk的过滤查询
和一般查询比较,filter查询:能够缓存数据在内存中,应该尽可能使用 建立测试数据 查看测试数据 1.filtered查询 GET /store/products/_search { "q ...