说明:因为本公司是服务公司,不是电商公司,所以不涉及减库存等事务操作
技术选型:redis的list数据类型的"栈"特点进行,因为redis采用多路io复用,且基于内存的单线程数据库,所以程序快,且没有多线程并发引起的超卖问题,也不会有采用单纯的乐观锁实现秒杀而形成用户大量的失败问题
这里利用吃饭时间写了点简单代码代码实现,有不对的地方 可以指出
准备工作:在秒杀开始前,提前利用程序把需要秒杀的商品(服务),写进redis的list.注:一中商品(服务)一个key,如果此商品要秒杀50个,就往list中存入50个唯一标识(令牌).
1.获取令牌
public boolean miaoshaTokenFromRedis(Integer goodsId, String user) {
String token = (String)redisTemplate.boundListOps("token_goods_"+goodsId).rightPop();
if(token == null || token.equals("")){
return false;
}else{
//记录当前用户已经抢购到令牌,证明当前这个用户可以取支付
String yes = (String)redisTemplate.boundValueOps(token).get();
if(yes != null && yes.equals("yes")) {
System.out.println("当前token已经被支付,不能再抢购");
redisTemplate.boundListOps("token_goods_"+goodsId).remove(1,token);
return false;
}
//value 存的对象(token,当前时间)---当前时间是跑定时任务的
redisTemplate.boundHashOps("user_token").put(user,{token,new Date()});
return true;
}
}
2.退还令牌(定时任务每5s执行一次)
public boolean returnToken(String user) {
//获得当前用户的令牌
String token = (String) redisTemplate.boundHashOps("user_token").get(user);
if(token == null || token.equals("")){
return false;
}else {
//得到商品id并从新存入list中 其他人可以抢购
String goodsId = token.split("_")[1];
redisTemplate.boundListOps("token_goods_"+goodsId).leftPush(token);
return true;
}
}
3.成功支付
public boolean payTokenToOrder(String user) {
//获得当前用户的令牌
String token = (String) redisTemplate.boundHashOps("user_token").get(user);
if(token == null || token.equals("")){
return false;
}else {
//如果在当前token已经被购买过,那么别人就不能抢当前的token或者不能再对该token进行支付
//采用redis记录当前token已经被支付
//redisTemplate.boundValueOps("key").setIfAbsent("value")
//如果当前这个key有值,该方法就会返回false,如果没有值,就会s设置为对应value,同时返回true
boolean flag = redisTemplate.boundValueOps(token).setIfAbsent("yes");
//当前token第一次被支付 flag=true
if(flag) {
//得到商品(f服务)id
String goodsId = token.split("_")[1];
Order order = new Order();
order.setUser(user);
order.setGoodId(Integer.parseInt(goodsId));
orderMapper.insert(order);
//用户刚好在支付时,定时任务执行,保证用户支付成功,所以删除一次
redisTemplate.boundHashOps("user_token").delete(user);//有可能已经归还token
redisTemplate.boundListOps("token_goods_" + goodsId).remove(1, token);//移除token, 有可能被别人抢到
}
return true;
}
}