当前位置: 首页 > news >正文

Redis黑马点评 分布式锁

1.不可重复下单。

@Overridepublic 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("库存不足");}Long userId = UserHolder.getUser().getId();//创建锁SimpleRedisLock lock = new SimpleRedisLock("order:"+userId, stringRedisTemplate);//6一人一单boolean isLock = lock.tryLock(1200L);if(!isLock){//失败return Result.fail("请勿重复下单");}try {//获取代理对象(事务)IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();return proxy.creatVoucherOrder(voucherId);} finally {//释放锁lock.unlock();}}@Transactionalpublic Result creatVoucherOrder(Long voucherId) {//6一人一单Long userId = UserHolder.getUser().getId();//6.1查询订单Integer count = query().eq("user_id",userId).eq("voucher_id", voucherId).count();//6.2判断是否存在if(count > 0){return Result.fail("不能重复下单");}//5.扣减库存boolean success = seckillVoucherService.update().setSql("stock = stock -1").eq("voucher_id", voucherId).gt("stock",0).update();if(!success){return Result.fail("库存不足");}//6.创建订单VoucherOrder voucherOrder = new VoucherOrder();//6.1订单id 用户id 代金券idlong orderId = redisIdWorker.nextId("order");voucherOrder.setId(orderId);voucherOrder.setUserId(userId);voucherOrder.setVoucherId(voucherId);save(voucherOrder);//7.返回订单idreturn Result.ok(orderId);}

package com.hmdp.utils;import org.springframework.data.redis.core.StringRedisTemplate;import java.util.concurrent.TimeUnit;public class SimpleRedisLock implements ILock{private StringRedisTemplate stringRedisTemplate;private String name;public SimpleRedisLock( String name,StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;this.name = name;}private static final String KEY_PREFIX = "lock:";@Overridepublic boolean tryLock(long timeoutSec) {//获取线程标示long threadId = Thread.currentThread().getId();//获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name,threadId+"", timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);}@Overridepublic void unlock() {}}

在 Redis 中使用 Lua 脚本的主要原因是 原子性性能优化。Redis 是一个高性能的键值存储系统,通常用于缓存、消息队列等场景。在这些场景中,确保操作的原子性和高效性是非常重要的。Lua 脚本可以帮助你实现这些目标。以下是具体的原因和好处:

1. 原子性

Redis 的 Lua 脚本执行是原子性的,这意味着在脚本执行期间,其他客户端的请求不会中断脚本的执行。这确保了脚本中的操作序列是不可分割的,从而避免了并发问题。

2. 性能优化

使用 Lua 脚本可以减少网络往返次数。如果你需要在 Redis 中执行多个操作,每次操作都需要与 Redis 服务器进行一次网络交互。通过将这些操作封装在 Lua 脚本中,可以一次性发送脚本并执行,从而减少网络延迟。

3. 复杂逻辑

Lua 脚本可以实现复杂的逻辑,而不需要在客户端进行多次交互。这使得你可以将复杂的业务逻辑封装在 Redis 中,减少客户端的负担。

4. 减少锁的使用

在某些情况下,使用 Lua 脚本可以减少锁的使用。通过将多个操作封装在 Lua 脚本中,可以避免在客户端使用锁来确保操作的原子性。

Lua

---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by zhaoming.
--- DateTime: 2025/10/27 10:36
-----比较线程标识与锁中是否一致
if(redis.call('get',KEY[1]) == ARGV[1]) then--释放锁return redis.call('del',KEY[1])
end
return 0

SimpleRedisLock


public class SimpleRedisLock implements ILock{private StringRedisTemplate stringRedisTemplate;private String name;public SimpleRedisLock( String name,StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate = stringRedisTemplate;this.name = name;}private static final String KEY_PREFIX = "lock:";private static final String ID_PREFIX = UUID.randomUUID().toString(true) + "-";private static final DefaultRedisScript<Long> UNLOCK_SCRIPT;static {UNLOCK_SCRIPT = new DefaultRedisScript<>();UNLOCK_SCRIPT.setLocation(new ClassPathResource("unlock.lua"));UNLOCK_SCRIPT.setResultType(Long.class);}@Overridepublic boolean tryLock(long timeoutSec) {//获取线程标示long threadId = Thread.currentThread().getId();//获取锁Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(KEY_PREFIX + name,threadId+"", timeoutSec, TimeUnit.SECONDS);return Boolean.TRUE.equals(success);}@Overridepublic void unlock() {//调用lua脚本stringRedisTemplate.execute(UNLOCK_SCRIPT,Collections.singletonList(KEY_PREFIX + name),ID_PREFIX + Thread.currentThread().getId());}

http://www.dtcms.com/a/535789.html

相关文章:

  • Lua-function的常见表现形式
  • 免费com域名网站提升wordpress性能的插件
  • 面试150——堆
  • shell实战-跳板机和测试主机是否在线
  • 精美课程表软件,课时科目灵活管理
  • MestReNova 16下载安装教程(附安装包)
  • 前端开发中的特殊字符
  • 【超音速专利 CN119515970A】一种适用于电池极片的边缘点距离处理方法、系统及平台
  • CANoe基础讲解04:掌握CANoe Graphics窗口(二)
  • 外国域名注册很多网站制作灯笼的手工做法步骤
  • Spring MVC配置解决跨域请求
  • 从一个nginx镜像启动的容器中分出部分location配置到另外一个nginx容器
  • 探秘仓颉:当函数式编程遇见面向对象王国,当协程风暴席卷并发荒原——从基础语法到实战测试联动的多维编程奇遇记
  • (场景题)怎么实现数据的批量插入?
  • 网站建设与管理案例...建企业网站一般需要多少钱
  • 使用el-table时,某个字段对应多个key值,如何进行展示
  • 空间数据采集与管理(如何使用ArcGIS Pro和Python进行空间数据的管理,确保数据采集和组织的高效性和准确性)
  • WHAT - React Compiler Directives 让手动优化变成过去式
  • API请求关键指标全解:Apipost视角下,从连接到性能的全景分析
  • HTML 的底层原理
  • 布吉做网站的公司关于网站建设的图片
  • 服务器运维(六)网站访问分析统计——东方仙化神期
  • 【Docker】定制化构建一个可以运行GaussDB的kylinv10sp3系统的docker镜像
  • 5分钟搭建云IDE!CodeServer+cpolar打造跨设备开发工作站
  • vmware和kali linux安装和搭建
  • 网络:网络层(IP协议)和数据链路层
  • DDS和SOMEIP区别以及应用场景
  • Lumi 具神智能机器人 SDK说明和ACT算法中的学习与推理
  • Rokid AR眼镜开发入门:构建智能演讲提词器Android应用
  • 量化指标解码03:布林带的开口收口策略与市场波动性分析