1
snappyone 2019-06-05 13:26:47 +08:00
你的目的是一个用户不能抢同一个红包多次吗?你的 isMember 检查是放在什么位置的呢
|
2
eefnrowe OP @snappyone 当然是放在 doUnpack 方法里靠前的
String userIdsKey = RedisKeys.buildRedPacketUserIdsKey(redPacketId); if(redisTemplate.hasKey(userIdsKey)){ Boolean member = redisTemplate.opsForSet().isMember(userIdsKey, userId); if(member){ throw new CommonException(ResponseCode.ERROR, "不可重复领取此红包"); } redisTemplate.opsForSet().add(userIdsKey, userId); }else{ redisTemplate.opsForSet().add(userIdsKey, userId); redisTemplate.expire(userIdsKey, 1, TimeUnit.HOURS); } |
3
snappyone 2019-06-05 14:27:55 +08:00
@eefnrowe
我感觉是你释放锁的问题,如果一个线程堵塞没拿到锁,在 finally 里面也把这个锁释放了,但是此时拥有锁的并不是他自己。试试 tryLock, 如果加锁失败则不要去释放锁 |
5
eefnrowe OP @snappyone
//红包锁 redis_lock:redpacket:${redPacketId} String lockName = RedisKeys.buildDistributedLockKey("redpacket", redPacketId); RLock rLock = redissonClient.getLock(lockName); try { boolean b = rLock.tryLock(3, 10, TimeUnit.SECONDS); if(b){ return doUnpack(redPacketId); } } catch (InterruptedException e) { e.printStackTrace(); } finally { rLock.unlock(); } |
7
snappyone 2019-06-05 15:34:34 +08:00
@eefnrowe 我貌似看错了,把 lock 后面的时间看做 waittime 了,不过你可以试下 trylock, 就设置个 5s 就行
|
9
ysweics 2019-06-05 15:44:38 +08:00
把红包和用户的两个 key 组装成一个 key,然后只锁一个 key=redpacketid:userid
|
11
734695609 2019-09-12 16:13:58 +08:00
@eefnrowe
你的问题:如果没有加 lockUser 锁的情况下 doUnpack 逻辑有问题。 你只把红包锁住,一个用户的 2 次并发访问,在你的逻辑中,可能都运行到 if(redisTemplate.hasKey(userIdsKey)) 都没有 userIdsKey,所以加了两条, 当你在 redisson 中加上用户锁时,一个用户的两次并发请求就不会运行到下面的代码了 我反而有一个问题,在 redisson 的官方文档中 https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8 你在 lock 时 // 加锁以后 10 秒钟自动解锁 官方解释 // 无需调用 unlock 方法手动解锁 官方解释 rLock.lock(10, TimeUnit.SECONDS); 这句代码官方解释是 10 秒后自动解锁,这样的话如果你的业务代码大于 10 秒或者因为某些原因等待超过 10 秒,会不会导致锁被释放掉,锁失效。 所以我感觉不加时间才是对的,除非你业务需要 |