秒杀案例设计
存入redis中的设计
商品库存
key: sk:prodid:qt
string: 剩余个数
秒杀成功者清单
key: sk:prodid:user
set: 成功者的user_id 成功者的user_id 成功者的user_id
代码实现
public static boolean doSecKill(String uid,String prodid) throws IOException{
//拼接向redis中保存库存和秒杀成功人员名单的key
String kcKey = "sk:" + prodid + ":qt";
String userKey = "sk:" + prodid + ":user";
//创建Jredis连接池对象
JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
Jedis jedis = jedisPoolInstance.getResource();
//添加乐观锁
jedis.watch(kcKey);
//获取库存
String count = jedis.get(kcKey);
//判断库存的数量
if("0".equals(count)){
//证明已经秒完
System.err.println("已经秒完");
JedisPoolUtil.release(jedisPoolInstance.jedis);
return false;
}
//添加事务
Transaction multi = jedis.multi();
//有库存的情况下需要进行以下操作
//将库存减1
multi.decr(kcKey);
//保存秒杀成功者的名单
multi.sadd(userKey, uid);
//执行
List<Object> exec = multi.exec();
if(exec == null || exec.size() == 0){
System.err.println("秒杀失败");
JedisPoolUtil.release(jedisPoolInstance.jedis);
return false;
}
System.out.println("秒杀成功!!");
return true;
}
利用lua脚本解决超卖和库存遗留问题
local userid=KEYS[1];
local userid=KEYS[2];
local qtkey="sk:"..prodid..":qt";
local usersKey="sk:"..prodid..":user";
local userExists=redis.call("sismember",usersKey,userid);
if tonumber(userExists)==1 then
return 2;
end
local num=redis.call("get", qtkey);
if tonumber(num) <=0 then
return 0;
else
redis.call("decr", qtkey);
redis.call("sadd",usersKey,userid);
end
return 1;
代码实现
public static boolean doSecKill(String uid,String prodid) throws IOException{
JedisPool jedispool = JedisPoolUtil.getJedisPoolInstance();
Jedis jedis = jedispool.getResource();
String sha1 = jedis.scriptLoad(secKillScript);
Object result = jedis.evalsha(sha1, 2, uid, prodid);
String reString =String.valueOf(result);
if ("0".equals(reString)){
System.err.println("已抢空");
} else if("1".equals(reString)){
System.out.println("抢购成功");
}else if("2".equals(reString)){
System.err.println("该用户已抢过");
}else{
System.err.println("抢购异常");
}
jedis.close();
return true;
}
# secKillScript
staic String secKillScript = "local userid=KEYS[1];\r\n" +
"local userid=KEYS[2];\r\n" +
"local qtkey='sk:'..prodid..\":qt\";\r\n" +
"local usersKey='sk:'..prodid..\":user\";\r\n" +
"local userExists=redis.call(\"sismember\",usersKey,userid);\r\n" +
"if tonumber(userExists)==1 then\r\n" +
"return 2;\r\n" +
"end\r\n" +
"local num=redis.call(\"get\", qtkey);\r\n" +
"if tonumber(num) <=0 then\r\n" +
" return 0;\r\n" +
"else\r\n" +
"redis.call(\"decr\", qtkey);\r\n" +
"redis.call(\"sadd\",usersKey,userid);\r\n" +
"end\r\n" +
"return 1;"
-------------------------------------------
个性签名:代码过万,键盘敲烂!!!
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!