【黑马点评-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();
}
posted @ 2025-04-23 18:44  kuki'  阅读(138)  评论(0)    收藏  举报