jseckill icon indicating copy to clipboard operation
jseckill copied to clipboard

如果希望采用多个服务器进行消息的消费,是不是在操作redis减库存的时候加分布式锁呢?

Open myhearis opened this issue 3 years ago • 2 comments

` @Override public void handleInRedis(long seckillId, long userPhone) throws SeckillException { Jedis jedis = jedisPool.getResource(); //获取前缀,+商品的秒杀id=当前秒杀商品的key String inventoryKey = RedisKeyPrefix.SECKILL_INVENTORY + seckillId; //key前缀+商品的秒杀id String boughtKey = RedisKeyPrefix.BOUGHT_USERS + seckillId; //获取商品库存 String inventoryStr = jedis.get(inventoryKey); //转换成int int inventory = Integer.valueOf(inventoryStr); if (inventory <= 0) { logger.info("handleInRedis SECKILLSOLD_OUT. seckillId={},userPhone={}", seckillId, userPhone); throw new SeckillException(SeckillStateEnum.SOLD_OUT); } //这里使用了redis的set集合,使用秒杀商品的id作为key,value是一个set集合, //这里是先判断当前秒杀商品的秒杀集合中是否存在了用户的电话,如果存在,说明该用户已经秒杀过一次了,抛出重复秒杀异常 if (jedis.sismember(boughtKey, String.valueOf(userPhone))) { logger.info("handleInRedis SECKILL_REPEATED. seckillId={},userPhone={}", seckillId, userPhone); throw new SeckillException(SeckillStateEnum.REPEAT_KILL); } //商品redis中库存-1 jedis.decr(inventoryKey); //往商品的set集合中添加手机号,作为成员,代表该手机号用户已经秒杀了该商品 jedis.sadd(boughtKey, String.valueOf(userPhone)); logger.info("handleInRedis_done");

}`

我给您的这个方法添加了一些注释,是不是需要在 jedis.decr(inventoryKey);这里使用分布式锁,防止多余的减库存请求进入redis,或者是在消费者调用这个方法的时候就使用分布式锁,我感觉后面这个比较好一些呢

myhearis avatar Jan 08 '23 10:01 myhearis

decr本来就是原子操作

yuyinhao avatar Feb 17 '23 03:02 yuyinhao

decr本来就是原子操作

如果 在分布式的条件下,多个消费者进行消费,这时候库存是1,两个秒杀请求都同时通过了校验,那么你直接减库存,哪怕是这原子操作,也最终是-1啊,所以我觉得得用分布式锁去防止这种情况。

myhearis avatar Feb 17 '23 08:02 myhearis