【黑马点评-3秒杀优惠券】六、开源工具Redisson 解决一人一单
1 之前的分布式锁toy存在以下问题
1.1 分布式锁不可重入:
不可重入是指同一线程不能重复获取同一把锁。
比如,方法A中调用方法B,方法A需要获取分布式锁,方法B同样需要获取分布式锁,
线程1进入方法A获取了一次锁,进入方法B又获取一次锁,由于锁不可重入,所以就会导致死锁
1.2 分布式锁不可重试:
获取锁只尝试一次就返回false,没有重试机制,这会导致数据丢失,
比如线程1获取锁,然后要将数据写入数据库,但是当前的锁被线程2占用了,线程1直接就结束了而不去重试,这就导致数据发生了丢失
1.3 分布式锁超时释放:
超市释放机机制虽然一定程度避免了死锁发生的概率,
但是如果业务执行耗时过长,期间锁就释放了,这样存在安全隐患。
锁的有效期过短,容易出现业务没执行完就被释放,锁的有效期过长,容易出现死锁,所以这是一个大难题!
我们可以设置一个较短的有效期,但是加上一个 心跳机制 和 自动续期:在锁被获取后,可以使用心跳机制并自动续期锁的持有时间。通过定期发送心跳请求,显示地告知其他线程或系统锁还在使用中,同时更新锁的过期时间。如果某个线程持有锁的时间超过了预设的有效时间,其他线程可以尝试重新获取锁。
1.4 主从一致性问题:
如果Redis提供了主从集群,主从同步存在延迟, 当主宕机时。
2 实现
2.1 引入maven坐标
2.2 RedissonConfig
config配置
2.3 仅需修改获取锁逻辑在VoucherServiceImpl.java中
Long userId = UserHolder.getUser().getId();
RLock lock = redissonClient.getLock("order:" + userId);
boolean isLock = lock.tryLock();
// 获取锁失败
if (!isLock) {
return Result.fail("一人一单");
}
try {
// 获取锁成功,创建代理对象,使用代理对象调用第三方事务方法
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
return proxy.createVoucherOrder(userId, voucherId);
} finally {
lock.unlock();
}

浙公网安备 33010602011771号