目标:
巧用锁 解决订单超卖场景
步骤:
1、启动Redis环境2、 搭建一个demo(单机版),消费同一个redis的key
3、加锁!
4、使用Apifox并发消费,看结果
Tips:其余步骤可看上篇博客
二:搭建一个demo(单机版),消费同一个redis的key
三:加锁!
加上单机版的锁:ReentraLock
@RestController
public class GoodsController {
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Value("${server.port}")
private String serverPort;
private final ReentrantLock COMMON_LOCK = new ReentrantLock();
@GetMapping("/bug_1")
public String bugGoods_1(){
COMMON_LOCK.lock(); // 执行业务代码前加锁
try{
// 查看redis中库存数量
String res = stringRedisTemplate.opsForValue().get("goods:001");
int goodsNum = res == null ? 0 : Integer.parseInt(res);
if(goodsNum > 0 ){
int realNum = goodsNum - 1;
stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNum));
System.out.println("bugGoods_1:成功购买商品,库存仅剩:"+realNum);
return "bugGoods_1:成功购买商品,库存仅剩:"+realNum;
}else{
System.out.println("bugGoods_1:商品售罄");
}
}catch (Exception e){
e.printStackTrace();
}finally{
COMMON_LOCK.unlock(); // finally 最终释放锁
}
return "bugGoods_1:商品售罄";
}
@GetMapping("/bug_2")
public String bugGoods_2(){
COMMON_LOCK.lock();
try {
// 查看redis中库存数量
String res = stringRedisTemplate.opsForValue().get("goods:001");
int goodsNum = res == null ? 0 : Integer.parseInt(res);
if(goodsNum > 0 ){
int realNum = goodsNum - 1;
stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNum));
System.out.println("bugGoods_2:成功购买商品,库存仅剩:"+realNum);
return "bugGoods_2:成功购买商品,库存仅剩:"+realNum;
}else{
System.out.println("bugGoods_2:商品售罄");
}
}catch (Exception e){
e.printStackTrace();
}finally{
COMMON_LOCK.unlock();
}
return "bugGoods_2:商品售罄";
}
}
或者单机版的锁:synchronized
@GetMapping("/buy01")
public String buy_01(){
synchronized (this){
try {
// 查看redis中库存数量
String res = stringRedisTemplate.opsForValue().get("goods:001");
int goodsNum = res == null ? 0 : Integer.parseInt(res);
if(goodsNum > 0 ){
int realNum = goodsNum - 1;
stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNum));
System.out.println("buy01:成功购买商品,库存仅剩:"+realNum);
return "buy01:成功购买商品,库存仅剩:"+realNum;
}else{
System.out.println("buy01:商品售罄");
}
}catch (Exception e){
e.printStackTrace();
}
return "buy01:商品售罄";
}
}
@GetMapping("/buy02")
public String buy_02(){
synchronized (this){
try {
// 查看redis中库存数量
String res = stringRedisTemplate.opsForValue().get("goods:001");
int goodsNum = res == null ? 0 : Integer.parseInt(res);
if(goodsNum > 0 ){
int realNum = goodsNum - 1;
stringRedisTemplate.opsForValue().set("goods:001",String.valueOf(realNum));
System.out.println("buy02:成功购买商品,库存仅剩:"+realNum);
return "buy02:成功购买商品,库存仅剩:"+realNum;
}else{
System.out.println("buy02:商品售罄");
}
}catch (Exception e){
e.printStackTrace();
}
return "buy02:商品售罄";
}
}
四:使用Apifox并发消费,看结果
Reentralock实现结果:
synchronized实现结果: