使用Redis存储,数据库及时更新,MQ消峰请求,延迟请求时间,前端做拼图,限流,限表单重复提交,利用原子性,悲观锁,事务,保持商品一致性,不超卖!
代码还在研发中…等有空就发布出来,实现起来不难,还有性能方面,可以从数据库方面着手,数据库利用好了,性能可以提高几倍!好了,暂时聊到这里,我要去学习liunx去了。
中午没有午休,写了一个简单的例子,这个例子如果要用到正式环境,可能需要做一些改动,我会在代码上面进行备注。
数据库图: 20个商品。
Redis图: 20个商品。
Redis图: 100个用户请求,现在是0,只能进来100个请求。
JMeter测试图: 10万个请求,5秒跑完。
代码: 代码我只突出impl层。
/**
* Redis存储,数据库更新,用MQ更新数据库
* @param param
*/
@Override
public void orderAdd3(OrderParam param) {
try {
//10万个用户请求
long count = RedisUtil.incr( "quantity");
System.out.println("进来的请求是:" + count);
//只要100个用户,其他的用户全部是返回抢购完成
if(100 <= count){
System.out.println("已经抢购完成");
return; //自定义返回异常
}else {
Integer i = Integer.valueOf(RedisUtil.get("commdity"));
System.out.println("剩下商品数量是: " + i);
if(i <=0) {
System.out.println("库存不足,停止售卖");
return; //自定义返回异常
}
//使用decrBy原子性,保证商品不被超卖,需要考虑,如果用户买了10个商品,但是商品库存没有10个,那么需要把扣的商品进行补回去!
RedisUtil.decrBy("commdity", param.getQuantity());
//放入MQ中,异步减库存
SendCaptcha sendCaptcha = new SendCaptcha();
BeanUtils.copyProperties(param,sendCaptcha);
sendCaptcha.setCount((int) count);
String jsonString = JSONObject.toJSONString(sendCaptcha);
rabbitTemplate.convertAndSend(TZGMQConfig.TZG_QUEUE_INFORM,jsonString);
}
}catch (Exception e){
System.out.println("出现异常");
}
}
MQ消费者进行消峰:
//监听sms队列
@RabbitListener(queues = {TZGMQConfig.TZG_QUEUE_INFORM})
public void receive_sms(String msg, String source){
try {
SendCaptcha sendCaptcha = JSONObject.parseObject(source, SendCaptcha.class);
System.out.println("获取到的sms消息==" + sendCaptcha);
commodityMapper.updateOrder(sendCaptcha.getCommodityId(),sendCaptcha.getQuantity());
System.out.println("更新数据库");
}catch (Exception e){
log.error("RabbitMQ consumer throws Exception test");
e.printStackTrace();
}
}
SQL:
update tar_commodity set quantity = (quantity - #{quantity}) where id = #{commodityId} and (quantity - #{quantity}) >= 0
IDEA控制台打印效果图:
数据库效果图:
Redis效果图:商品
Redis效果图:请求
下篇会写多线程,在服务器加悲观锁,与原子性控制,择其善者而从之,其不善者而改之。