前言
前面介绍了基于Redis实现分布式锁来解决优惠券秒杀系统中的高并发问题。通过SET key value NX PX命令实现互斥锁,结合Spring的setIfAbsent方法封装锁获取逻辑。实现中需要注意锁的过期时间设置以避免死锁,以及事务处理保证数据一致性。该方案有效解决了JVM单机锁在分布式环境下的局限性。
经过上面的优化,我们实现的分布式锁已经达到生产可用级别了,但是还不够完善,比如:

来看看怎么解决吧
像上面一步优化分布式锁,太麻烦了,可以直接使用已经实现好的Redission'。
来看看什么是Redission吧
Redisson 是一个基于 Java 的 Redis 客户端 ,它不仅提供了对 Redis 原生命令的封装,更重要的是在 Redis 的基础上实现了一系列分布式对象、服务和工具,使得开发者可以像使用本地 Java 对象一样操作分布式环境中的共享资源。Redisson 的设计目标是简化分布式系统开发,提供线程安全、高性能、高可用的分布式解决方案。

Redisson实现分布式锁
1)引入Redisson依赖
xml
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.6</version>
</dependency>
2)配置Redisson客户端
java
package com.hmdp.config;
import ...
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient() {
// 创建配置
Config config = new Config();
config.useSingleServer().setAddress("redis://localhost:6379");//我的Redis是本地的,要改成自己的如果有密码记得配置
// 创建RedissonClient对象
return Redisson.create(config);
}
}
4)Redission的使用:其实就是换一个锁把我们自己写的RedisIdWorker锁换成刚刚配置的redisson锁
java
package com.hmdp.service.impl;
import ...
/**
* <p>
* 服务实现类
* </p>
*
* @author 虎哥
* @since 2021-12-22
*/
@Slf4j
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
@Resource
private ISeckillVoucherService seckillVoucherService;
@Resource
private RedisIdWorker redisIdWorker;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private RedissonClient redissonClient;
/*
查询领取秒杀券
*/
@Override
public Result seckillVoucher(Long voucherId) {
//1.查询优惠券
SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
//2.判断秒杀是否开始
if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
return Result.fail("秒杀尚未开始");
}
//3.判断秒杀是否结束
if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
return Result.fail("秒杀已结束");
}
//4.判断库存是否充足
if (voucher.getStock() < 1) {
return Result.fail("库存不足");
}
// 3、创建订单(使用分布式锁)
Long userId = ThreadLocalUtls.getUser().getId();
RLock lock = redissonClient.getLock(RedisConstants.LOCK_ORDER_KEY + userId);
boolean isLock = lock.tryLock();
if (!isLock) {
// 索取锁失败,重试或者直接抛异常(这个业务是一人一单,所以直接返回失败信息)
return Result.fail("一人只能下一单");
}
try {
// 索取锁成功,创建代理对象,使用代理对象调用第三方事务方法, 防止事务失效
IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
return proxy.createVoucherOrder(userId, voucherId);
} finally {
lock.unLock();
}
}
/*
// 创建订单
// */
@Transactional //添加事务保证数据库操作和缓存操作的原子性
public void createVoucherOrder(VoucherOrder voucherOrder) {
//5.一人一单
//5.1 查询订单
Long userId = voucherOrder.getUserId();
//5.1 获取锁成功
int count = query().eq("user_id", userId).eq("voucher_id", voucherOrder).count();
//5.2.判断是否存在
if (count > 0) {
//用户购买过
log.error("用户已经买过了");
return ;
}
//6.扣减库存
boolean success = seckillVoucherService.update()
.setSql("stock = stock - 1")
.eq("voucher_id", voucherOrder)
.gt("stock", 0)//where id = ? and stock > 0
.update();
if (!success) {
//扣减库存失败
log.error("库存不足");
return ;
}
//写入数据库
save(voucherOrder);
}
}
所以其实最好的分布式锁,就是用别人写好包装好的🤪,一场酣畅淋漓的白雪。。。
本文是学习黑马程序员---黑马点评项目的课程笔记,小白啊!!!写的不好轻喷啊🤯如果觉得写的不好,点个赞吧🤪(批评是我写作的动力)
...。。。。。。。。。。。...

...。。。。。。。。。。。...