spring-boot-redisson-lock
环境
- JDK 1.8
- Spring boot 2.1.0.RELEASE
- redisson-spring-boot-starter 3.9.1
- spring-data-redis 2.1.2.RELEASE
说明
我们在做业务的时候进程会碰到并发的问题,比如秒杀,下面我们通过Redis解决这类问题
1 2 3 4
| 初始化接口:http://192.168.1.145:8080/kill/initBaiKe 用户秒杀抢到的商品数量接口:http://192.168.1.145:8080/kill/successNum Redisson锁秒杀接口:http://192.168.1.145:8080/kill/redis 事务秒杀接口:http://192.168.1.145:8080/kill/affair
|
初始化数据
通过锁方式秒杀
我们知道在Redis中官方提供了一个名为Redisson的工具,它的功能非常强大在她的文档中有充分的介绍:官方文档
我们使用它的lock功能,好吧废话不多说上代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
@RequestMapping(value = "/redis", method = RequestMethod.POST) public MessageResult secKillRedis() { MessageResult result = MessageResult.ok(); RLock rLock = redissonClient.getLock("baike_lock");
try { rLock.lock(); String baikeJson = redisTemplate.opsForValue().get("baike"); Baike baike = JSONUtil.toBean(baikeJson, Baike.class); Integer amount = baike.getAmount(); amount = amount - 1; if (amount < 0) { result.setMsg("库存不足");
return result; }
baike.setAmount(amount); redisTemplate.opsForValue().set("baike", JSONUtil.toJsonStr(baike));
String msg = "减少库存成功,共减少" + successNum.incrementAndGet(); result.setMsg(msg); log.info(msg);
return result; } finally { rLock.unlock(); } }
|
我使用jmeter进行测试
从结果可以看出,商品并没有出现超卖的问题
我们来看看卖出的接口统计的数据,从数据看一切正常,解决超卖问题
Redis事务方式秒杀
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| /** * 通过事务解决秒杀 * @return */ @RequestMapping(value = "/affair", method = RequestMethod.POST) public MessageResult affair() { MessageResult result = MessageResult.ok(); redisTemplate.setEnableTransactionSupport(true);
// 通过事务解决超卖问题 List results = redisTemplate.execute(new SessionCallback<List>() { @Override public List execute(RedisOperations operations) throws DataAccessException { operations.watch("baike"); String baikeJson = redisTemplate.opsForValue().get("baike"); Baike baike = JSONUtil.toBean(baikeJson, Baike.class); operations.multi(); //一定要有空查询 operations.opsForValue().get("baike"); Integer amount = baike.getAmount(); amount = amount - 1; if (amount < 0) { return null; }
baike.setAmount(amount); redisTemplate.opsForValue().set("baike", JSONUtil.toJsonStr(baike));
return operations.exec(); } });
if (results != null && !results.isEmpty()) { // 用户抢到商品累计 String msg = "减少库存成功,共减少" + successNum.incrementAndGet(); result.setMsg(msg); log.info(msg);
return result; }
result.setMsg("库存不足"); return result; }
|
通过事务的方式比较复杂,但效果和锁的方式是一样的,图我就不贴了,有兴趣的可以去看看代码:代码
总结
我们推荐用锁的方式进行操作,比较比较简单,不过初期的配置也挺麻烦,
我们可以查看官方的文档进行配置:配置文档
他可以配置的模式如下:
- 集群模式
- 云托管模式
- 单Redis节点模式
- 哨兵模式
- 主从模式
问题建议