Redis乐观锁解决超卖问题
情景假设:现在华为最新手机在做活动,双十二 00:00 准时前十名抢购的用户可以1元秒杀。而数据库对这个秒杀的动作呢,需要作出两个动作:
1、库存减1
2、记录秒杀成功的用户id
话不多说,我们直接用代码来演示:
这里直接给出控制器方法。
@PostMapping("/secKill")
public void TestSecKill(){
/**
* 实际开发,我们需要获取用户的id和商品的id
* 这里作为学习使用,我们先写死
*/
//用户id,我们使用随机数来表示每次访问的不同用户
String userid = new Random().nextInt(50000) + "";
//商品id,我们先写死
String prodid = "1001";
//1、连接redis(如果有设置requirepass的话,记得添加jedis.auth("你的密码");
Jedis jedis = new Jedis("119.91.153.74", 6379);
//2、拼接key
String kcKey = "sk:"+prodid+":qt"; //库存key
String userKey = "sk:"+userid+":user"; //秒杀成功用户key
//使用乐观锁,监视库存
jedis.watch(kcKey);
//3、获取库存,为null表示活动未开始
String kc = jedis.get(kcKey);
if(kc == null){
System.out.println("秒杀还未开始");
jedis.close();
return;
}
//4、判断用户是否重复秒杀
if(jedis.sismember(userKey, userid)){
System.out.println("您已成功秒杀,不可重复秒杀");
jedis.close();
return;
}
//5、库存小于等于0,秒杀结束
if (Integer.parseInt(kc) <= 0){
System.out.println("秒杀活动已结束,感谢您的参与");
jedis.close();
return;
}
//6、秒杀过程
//开启事务
Transaction transaction = jedis.multi();
//组队
//6.1 库存减1
transaction.decr(kcKey);
//6.2 添加秒杀成功用户
transaction.sadd(userKey, userid);
//执行
List<Object> results = transaction.exec();
//执行失败
if (results == null || results.size() == 0){
System.out.println("秒杀失败.....");
jedis.close();
return;
}
//执行成功
System.out.println("恭喜您秒杀成功.......");
jedis.close();
}
然后我们来测试一下:
首先,先给redis添加库存:
set sk:1001:qt 10
然后我们使用ab工具模拟并发:
这里顺便介绍几个命令:
命令 | 描述 |
---|---|
-n | requests:请求次数 |
-c | concurrency:并发数 |
-T | content-type:用于POST和PUT请求,其值固定为’application/x-www-form-urlencoded’ |
-p | postfile:如果post请求有参数,要放到该文件中 |
-u | putfile:如果put请求有参数,要放到该文件中 |
基本介绍就这么多,接下来我们直接用,使用命令:
注意:即使post请求没有参数,也要使用-p标签,否则好像会默认使用get请求,192.168.148.148是Tomcat服务器的ip地址(这里我的是我的windows的ip地址)。
ab -n 1000 -c 100 -p postfile -T ‘application/x-www-form-urlencoded’ http://192.168.148.148:8080/secKill
如果要查询自己本机的ip地址的话,在cmd下输入 ipconfig即可。它里面有一个Ipv4地址就是你的ip地址啦。
如果Linux服务器访问不了你的windows,那么我们也可以在windows上下载ab工具,并使用python来模拟我们的并发测试。
import os
#D:\Download\httpd-2.4.51-o111l-x64-vc15\Apache24\bin\ab是我们的ab工具路径
ab=os.popen(r'D:\Download\httpd-2.4.51-o111l-x64-vc15\Apache24\bin\ab -n 1000 -c 100 -p ./postfile -T application/x-www-form-urlencoded http://192.168.148.148:8080/secKill')
print(ab.read())
运行结果:(可以看到秒杀成功的次数是10次,成功解决了我们的超卖问题)
我们再去Redis下查看:
CentOS7下载ab工具
安装命令:
yum install httpd-tools
Windows下载ab工具
ab工具官网下载地址:https://www.apachehaus.com/cgi-bin/download.plx
进入后往下拉:
下载完成后直接解压即可。