1、场景
2、复现超卖场景
2.1 初始化库存接口
@RestController @RequestMapping("/redis") @Slf4j public class RedisController { @Resource private RedisTemplate redisTemplate; //记录实际卖出的商品数量 private AtomicInteger successNum = new AtomicInteger(0); @GetMapping(value = "/init") public String init() { // 初始化库存数量,模拟库存只要5个商品,写入到redis中 redisTemplate.opsForValue().set("stock", 5); successNum.set(0); log.info("===>>>库存初始化成功,库存数为" + 5); return "初始化库存成功"; } }
2.2 库存扣减接口
@RestController @RequestMapping("/redis") @Slf4j public class RedisController { @Resource private RedisTemplate redisTemplate; //记录实际卖出的商品数量 private AtomicInteger successNum = new AtomicInteger(0); @GetMapping(value = "/reduce") public String reduce() { int stock = (Integer) redisTemplate.opsForValue().get("stock"); log.info("===>>>当前数量" + stock); // 模拟只减少一个库存 stock = stock - 1; if (stock < 0) { log.info("===>>>库存不足"); return "库存不足"; } // 将剩余数量回写到redis redisTemplate.opsForValue().set("stock", stock); // 记录实际卖出的商品数量(线程安全每个请求都会记录) log.info("===>>>减少库存成功,共出售" + successNum.incrementAndGet()); return "减少库存成功"; } }
2.3 测试
使用工具JMeter模拟并发请求,此处模拟每秒200次;JMeter工具使用参考博客:https://blog.csdn.net/tianqingmuyu/article/details/108401543
注意:测试前先执行初始化库存接口,保证库存写入到Redis中
使用JMeter请求接口,结果如下图:
3、解决超卖实现
3.1 初始化库存接口
@RestController @RequestMapping("/redis") @Slf4j public class RedisController { @Resource private RedisTemplate redisTemplate; //记录实际卖出的商品数量 private AtomicInteger successNum = new AtomicInteger(0); @GetMapping(value = "/init") public String init() { // 初始化库存数量,模拟库存只要5个商品,写入到redis中 redisTemplate.opsForValue().set("stock", 5); successNum.set(0); log.info("===>>>库存初始化成功,库存数为" + 5); return "初始化库存成功"; } }
3.2 库存扣减接口
@RestController @RequestMapping("/redis") @Slf4j public class RedisController { @Resource private RedisTemplate redisTemplate; //记录实际卖出的商品数量 private AtomicInteger successNum = new AtomicInteger(0); @GetMapping(value = "/reduce") public String reduce() { // 开启事务 redisTemplate.setEnableTransactionSupport(true); List<Object> results = (List<Object>) redisTemplate.execute(new SessionCallback<List<Object>>() { @Override public List<Object> execute(RedisOperations operations) throws DataAccessException { // 监视key operations.watch("stock"); Integer stock = (Integer) operations.opsForValue().get("stock"); operations.multi(); stock = stock - 1; if (stock < 0) { log.info("===>>>库存不足"); return null; } operations.opsForValue().set("stock", stock); return operations.exec(); } }); if (results != null && results.size() > 0) { log.info("===>>>减少库存成功,共出售" + successNum.incrementAndGet()); return "减少库存成功"; } return "库存不足"; } }
3.3 测试
使用工具JMeter模拟并发请求,此处模拟每秒200次;JMeter工具使用参考博客:https://blog.csdn.net/tianqingmuyu/article/details/108401543
注意:测试前先执行初始化库存接口,保证库存写入到Redis中
使用JMeter请求接口,结果如下图,没有出现超卖情况:
结论
通过Redis事务机制,能够有效的解决秒杀系统的超卖问题;
其他实现方式:Redis实现分布式锁机制
发表评论 取消回复