JAVA全系列 教程
3762个小节阅读:7088.2k
目录
C语言快速入门
JAVA全系列 教程
面向对象的程序设计语言
Python全系列 教程
Python3.x版本,未来主流的版本
人工智能 教程
顺势而为,AI创新未来
大厂算法 教程
算法,程序员自我提升必经之路
C++ 教程
一门通用计算机编程语言
微服务 教程
目前业界流行的框架组合
web前端全系列 教程
通向WEB技术世界的钥匙
大数据全系列 教程
站在云端操控万千数据
AIGC全能工具班
A A
White Night
Redisson是一个高级的分布式协调Redis客户端,能帮助用户在分布式环境中轻松操作Redis服务,Jedis更侧重对Redis的增删改查,而Redisson侧重于分布式开发。
在秒杀服务模块引入Redisson依赖
xxxxxxxxxx
<!-- Redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.27.1</version>
</dependency>
秒杀服务模块已经配置了redis连接,所以不需要再配置了。
编写Redisson工具类
xxxxxxxxxx
@Component
public class RedissonLock {
@Autowired
private RedissonClient redissonClient;
// 加锁
public boolean lock(String key, long expireTime) {
// 拿到锁的名字。redis的key,即锁的名为秒杀商品id
RLock lock = redissonClient.getLock("lock:"+key);
try {
/**
* 尝试获取锁,如果没有别人占用这把锁,则拿到锁
*
* 参数代表redis过期时间,即如果没有主动释放锁,到期会自动释放,防止服务器出现问题后引发死锁
*/
return lock.tryLock(expireTime, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
/**
* 没有拿到锁证明别人占用,中断当前线程
*/
Thread.currentThread().interrupt();
return false;
}
}
// 释放锁
public void unlock(String key) {
// 拿到锁的名字
RLock lock = redissonClient.getLock("lock:"+key);
// 如果锁被占用,释放锁
if (lock.isLocked()) {
lock.unlock();
}
}
}
修改秒杀下单方法
xxxxxxxxxx
@Override
public Orders createOrder(Orders orders) {
String lockKey = orders.getCartGoods().get(0).getGoodId().toString();
if (redissonLock.lock(lockKey,10000)){
try{
// 1.生成订单对象
orders.setId(IdWorker.getIdStr()); // 手动使用雪花算法生成订单id
orders.setStatus(1); // 订单状态未付款
orders.setCreateTime(new Date()); // 订单创建时间
orders.setExpire(new Date(new Date().getTime() + 1000 * 60 * 5)); // 订单过期时间
// 计算商品价格
CartGoods cartGoods = orders.getCartGoods().get(0);
Integer num = cartGoods.getNum();
BigDecimal price = cartGoods.getPrice();
BigDecimal sum = price.multiply(BigDecimal.valueOf(num));
orders.setPayment(sum);
// 2.减少秒杀商品库存
// 查询秒杀商品
SeckillGoods seckillGoods = findSeckillGoodsByRedis(cartGoods.getGoodId());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 查询库存,库存不足抛出异常
if (seckillGoods == null || seckillGoods.getStockCount() <= 0) {
throw new BusException(CodeEnum.NO_STOCK_ERROR);
}
// 减少库存
seckillGoods.setStockCount(seckillGoods.getStockCount() - cartGoods.getNum());
redisTemplate.boundHashOps("seckillGoods").put(seckillGoods.getGoodsId(), seckillGoods);
// 3.将订单数据保存到Redis中
redisTemplate.setKeySerializer(new StringRedisSerializer());
// 设置订单1分钟过期
redisTemplate.opsForValue().set(orders.getId(), orders, 100, TimeUnit.MINUTES);
/**
* 给订单创建副本,副本的过期时间长于原订单
* redis过期后触发过期事件时,redis的数据已经过期,此时只能拿到key,拿不到value
* 而过期事件需要回退商品库存,必须拿到value即订单详情,才能拿到商品数据,进行回退操作
* 我们保存一个订单副本,过期时间长于原订单,我们就可以通过副本拿到订单数据
*/
redisTemplate.opsForValue().set(orders.getId() + "_copy", orders, 102, TimeUnit.MINUTES);
System.out.println("下单成功,订单号:"+orders.getId());
System.out.println("库存还有:"+seckillGoods.getStockCount());
return orders;
}finally {
redissonLock.unlock(lockKey);
}
}else {
return null;
}
}
新增秒杀商品
重启两个服务,测试秒杀下单功能。