SSM秒杀系统(十一)消息队列RabbitMQ实现异步订单
RabbitMQ 是实现 AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。
为什么要使用消息队列?
再秒杀系统中,如果商品服务和订单服务是两个不同的微服务,在下单的过程中订单服务需要调用商品服务进行扣库存操作。按照传统的方式,下单过程要等到调用完毕之后才能返回下单成功,如果网络产生波动等原因使得商品服务扣库存延迟或者失败,会带来较差的用户体验,如果在高并发的场景下,这样的处理显然是不合适的,那怎么进行优化呢?这就需要消息队列登场了。
消息队列提供一个异步通信机制,消息的发送者不必一直等待到消息被成功处理才返回,而是立即返回。消息中间件负责处理网络通信,如果网络连接不可用,消息被暂存于队列当中,当网络畅通的时候在将消息转发给相应的应用程序或者服务,当然前提是这些服务订阅了该队列。如果在商品服务和订单服务之间使用消息中间件,既可以提高并发量,又降低服务之间的耦合度。
十五、消息队列RabbitMQ
15.1 rabbitMQ的安装与使用
1.RabbitMQ服务端代码是使用并发式语言Erlang编写的,安装Rabbit MQ的前提是安装Erlang
我下载的是19.3: http://erlang.org/download/otp_win64_19.3.exe
2.安装RabbitMQ
我是用的3.6.10的windows版本:https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.10/rabbitmq-server-3.6.10.exe
3.使用RabbitMQ
rabbitmqctl status //查看启动状态
rabbitmq-service start //开始服务
Rabbitmq-service stop //停止服务
//插件启动和停止
rabbitmq-plugins enable rabbitmq_management //启动
rabbitmq-plugins disable rabbitmq_management //关闭
在浏览器输:http:localhost:15672
进入控制台
默认的账号和密码都是 guest
15.2 消息队列使用
我们所有的订单、提交订单和支付订单都需要使用redis缓存和消息队列来实现
1.订单模块优化–redis缓存
将订单提交后的订单信息(新增订单),订单支付(订单状态更新),订单查询全部交由redis来处理,先保存在redis缓存中。
(1) OrderRedisService.java 订单缓存
public class OrderRedisServiceImpl implements OrderRedisService{
@Autowired
private RedisUtil redisUtil;
/**
* 将秒杀商品放到redis缓存
*/
public Map<String,Object> seckill(int userid, int productid,ConstomOrder msorder) {
Map<String,Object> resultmap = new HashMap<String,Object>();
int stockcount = msorder.getStockcount();//库存总数
if(redisUtil.getkeylistsize(productid+"")> stockcount){
System.out.println("秒杀失败");
resultmap.put("success", false);
}
//将每个商品秒杀情况加入到redis的list中
redisUtil.pushlist(productid+"", userid+"");
System.out.println("秒杀成功");
//将订单信息存放到redis
String key = "userid:"+userid+"==productid:"+productid;
String value = "";
//日期转换成字符串
String createtimestring = DateUtils.transferdate(new Date(), "yyyy-MM-dd HH:mm:ss");
String merchantid = msorder.getMerchantid()+"";
String payamount = msorder.getPayamount()+"";
String receivingadress = msorder.getReceivingadress();
String receivingname = msorder.getReceivingname();
String receivingphone = msorder.getReceivingphone();
String stockcountnum = msorder.getStockcount()+"";
String tradeserialnumber = createtimestring+UUID.randomUUID();
String paystatus = "1";
value += paystatus+"=="+tradeserialnumber+"=="+createtimestring+"=="+merchantid+"=="+payamount+"=="+receivingadress+"=="+receivingname+"=="+receivingphone+"=="+stockcountnum;
redisUtil.set(key, value);
//返回订单信息,供action调用
Map<String,String> datamap = new HashMap<String,String>();
datamap.put("createtime", createtimestring);
datamap.put("merchantid", merchantid);
datamap.put("payamount", payamount);
datamap.put("receivingadress", receivingadress);
datamap.put("receivingname", receivingname);
datamap.put("receivingphone", receivingphone);
datamap.put("stockcountnum", stockcountnum);
datamap.put("tradeserialnumber", tradeserialnumber);
datamap.put("paystatus", paystatus);
datamap.put("productid", productid+"");
datamap.put("userid", userid+"");
resultmap.put("success", true);
resultmap.put("datamap", datamap);
return resultmap;
}
/**
* 更新redis缓存的订单(在redis中修改订单状态)
*/
public boolean payorder(int paytype,int userid,int productid,int merchantid,String tradeserialnumber, int payamount){
String key = "userid:"+userid+"==productid:"+productid;
String value = (String) redisUtil.get(key);
String[] splitvalues = value.split("==");
splitvalues[0] = "2";
value = "";
//更新redis缓存里的订单状态
for(String temp:splitvalues){
value += temp+"==";
}
boolean issuccess = redisUtil.set(key, value);
return issuccess;
}
//在redis中查询所有的订单
public List<Msorder> queryorderbyuserid(int userid){
List<Msorder> listmsorder = new ArrayList<Msorder>();
Set<String> keys = redisUtil.getkeys("userid:"+userid);
for(String key :keys){
String[] prusers = key.split("==");
if(prusers.length <= 1){
continue;
}
String productid = prusers[1].split(":")[1];
String useridstring = prusers[0].split(":")[1];
String value = (String) redisUtil.get