新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于redis实现分布式锁

发布时间:2026/10/1 21:56:33来源:尧图网络
基于redis实现分布式锁
初步实现主要业务流程:在Utils创建ILock接口:package com.hmdp.utils; public interface ILock { /** * 尝试获取锁 * param timeoutSec 锁持有的超时时间过期后自动释放 * return true代表获取锁成功false代表获取锁失败 */ boolean tryLock(long timeoutSec); /** * 释放锁 */ void unlock(); }创建实现类SimpleRedisLock并实现ILock接口:package com.hmdp.service.impl; import com.hmdp.utils.ILock; import org.springframework.data.redis.core.StringRedisTemplate; import java.util.concurrent.TimeUnit; public class SimpleRedisLock implements ILock{ private String name; private StringRedisTemplate stringRedisTemplate; public SimpleRedisLock(String name, StringRedisTemplate stringRedisTemplate) { this.name name; this.stringRedisTemplate stringRedisTemplate; } private static final String KEY_PROFIX lock:; /** * 尝试获取锁 * param timeoutSec 锁持有的超时时间过期后自动释放 * return true代表获取锁成功false代表获取锁失败 */ Override public boolean tryLock(long timeoutSec) { //获取线程标示 long threadId Thread.currentThread().getId(); //获取锁 Boolean success stringRedisTemplate.opsForValue() .setIfAbsent(KEY_PROFIX name, threadId , timeoutSec, TimeUnit.SECONDS); return Boolean.TRUE.equals(success); } /** * 释放锁 */ Override public void unlock() { stringRedisTemplate.delete(KEY_PROFIX name); } }将VoucherOrderServiceImpl修改为如下代码import com.hmdp.utils.UserHolder; import org.springframework.aop.framework.AopContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; public class VoucherOrderServiceImpl extends ServiceImplVoucherOrderMapper, Vou private ISeckillVoucherService seckillVoucherService; Autowired private RedisIdWorker redisIdWorker; Autowired private StringRedisTemplate stringRedisTemplate; Override public Result secVoucherKill(Long voucherId) { public Result secVoucherKill(Long voucherId) { //8.返回订单id Long userId UserHolder.getUser().getId(); synchronized (userId.toString().intern()) { //创建锁对象 SimpleRedisLock lock new SimpleRedisLock(order: userId, stringRedisTemplate); //获取锁 boolean isLock lock.tryLock(1200); //判断是否获取成功 if (!isLock){ return Result.fail(不允许重复下单); } try { //获取代理对象(事务) IVoucherOrderService proxy (IVoucherOrderService) AopContext.currentProxy(); return proxy.createVoucherOrder(voucherId); }finally{ //释放锁 lock.unlock(); } } Transactional public Result createVoucherOrder(Long voucherId) { //5.一人一单 Long userId UserHolder.getUser().getId(); //查询订单 int count query().eq(user_id, userId).eq(voucher_id, voucherId).count(); if (count 0){ return Result.fail(该优惠券每人仅限一单!); } //6.扣减库存 boolean success seckillVoucherService.update() .setSql(stock stock - 1) .eq(voucher_id, voucherId).gt(stock,0) .update(); if (!success){ //扣减失败 return Result.fail(库存不足); } //7.创建订单 VoucherOrder voucherOrder new VoucherOrder(); //7.1订单id long orderID redisIdWorker.nextId(order); voucherOrder.setId(orderID); //7.2用户id voucherOrder.setUserId(userId); //7.3优惠券id voucherOrder.setVoucherId(voucherId); //7.4创建订单 save(voucherOrder); return Result.ok(orderID); } }解决redis分布式锁的误删问题:误删问题出现的原因:线程A获取锁成功后,处理自己的业务逻辑时由于种种原因可能会出现处理缓慢或程序休眠等情况,而redis锁在获取时设置的过期时间已经过期,线程B现在可以进行获取锁和处理自身业务的操作,此时线程A的业务执行完成开始进行释放锁,而现在redis中的锁属于线程B,此时就会出现误删问题解决方案:在获取锁时添加线程标示(UUID线程id),在释放锁时进行标示判断,一致则可以释放;不一致则说明当前线程的标示早已过期,不需要再进行手动删除代码逻辑改动如下:/** * 尝试获取锁 * param timeoutSec 锁持有的超时时间过期后自动释放 * return true代表获取锁成功false代表获取锁失败 */ Override public boolean tryLock(long timeoutSec) { //获取线程标示 String threadId ID_profix Thread.currentThread().getId(); //获取锁 Boolean success stringRedisTemplate.opsForValue() .setIfAbsent(KEY_PROFIX name, threadId , timeoutSec, TimeUnit.SECONDS); return Boolean.TRUE.equals(success); }/** * 释放锁 */ Override public void unlock() { //获取线程标示 String threadId ID_profix Thread.currentThread().getId(); //获取锁中的标示 String id stringRedisTemplate.opsForValue().get(KEY_PROFIX name); //判断标示是否一致 if (threadId.equals(id)){ //释放锁 stringRedisTemplate.delete(KEY_PROFIX name); } }基于Lua脚本确保释放锁操作的原子性在线程A释放锁操作时,判断线程表示与锁标示一致后,进行释放操作可能会出现业务阻塞,锁到期自动释放;此时线程B可以获取锁操作成功,如果线程A业务恢复就可能删掉其他线程的锁实现方案:编写Lua脚本--- 比较线程标示与锁中的标示是否一致 if (redis.call(get, KEYS[1]) ARGV[1] ) then ---释放锁 redis.call(del,KEYS[1]) end return 0修改释放锁逻辑/** * 释放锁 */ public void unlock(){ //调用lua脚本 stringRedisTemplate.execute( UNLOCK_SCRIPT, Collections.singletonList(KEY_PROFIX name), ID_profix Thread.currentThread().getId()); }
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

商用制冰机内部结构拆解:看懂制冷与供水系统,少花冤枉钱 2026/10/1 22:56:06

商用制冰机内部结构拆解:看懂制冷与供水系统,少花冤枉钱

一台商用制冰机,很多人开店之前觉得它就是个"会出冰的冰箱",等到夏天高峰期不够用、或者机器三天两头闹脾气的时候,才后悔当初没弄明白它内部到底是什么结构。我见过太多餐饮店主,机器一报错就喊维修工,结果…

阅读更多 →
uniapp接入阿里云点播:播放凭证与跨端播放器集成实战 2026/10/1 22:56:05

uniapp接入阿里云点播:播放凭证与跨端播放器集成实战

这两周我一直在折腾一个uniapp项目接入阿里云点播的事,项目本身是一个视频课程App,要求一套代码同时跑Android、iOS、微信小程序和H5四个端。视频这块最早是用nginx静态目录直接放MP4的,开发阶段倒是爽,上线后问题全来了&#xff…

阅读更多 →
华为53页PPT拆解:制造数字化转型的工业互联网落地路径 2026/10/1 22:56:05

华为53页PPT拆解:制造数字化转型的工业互联网落地路径

简介:华为制造行业数字化转型工业互联网智能制造解决方案PPT共53页,面向制造企业信息化负责人、工业互联网方案架构师及智能制造研究人员,系统梳理从产业趋势洞察到落地案例的完整路径。压缩包内为单个.pptx演示文稿,约4.65MB&…

阅读更多 →
从零构建私有AI操作系统:本地部署、知识库与智能体的完整实践指南 2026/10/1 22:55:52

从零构建私有AI操作系统:本地部署、知识库与智能体的完整实践指南

上个月的一个晚上,我在整理自己十年来散落在硬盘各处的项目笔记、日记和工作文档,忽然意识到一个很讽刺的事实:我每天都在用各种 AI 工具提升效率,但这些工具里没有一个是"我"的。在线 AI 确实强,可是把财务…

阅读更多 →
DeepSeek Harness 实战:从聊天框到AI驾驶舱的工程化工具 2026/10/1 22:55:52

DeepSeek Harness 实战:从聊天框到AI驾驶舱的工程化工具

拿到标题那天我正好在整理旧设备,三年前装的 ChatGPT 桌面客户端还躺在应用列表里。于是我把 DeepSeek Harness 桌面版下载下来,解压、装依赖、跑起来,前后大概花了五分钟。然后我盯着屏幕上那个黑底绿字的终端窗口愣了三秒——这东西&#x…

阅读更多 →
智能化软件开发:从AI写代码到人机协同范式迁移 2026/10/1 22:55:52

智能化软件开发:从AI写代码到人机协同范式迁移

1. 这不是“AI写代码”,而是软件开发范式的迁移起点“智能化软件开发”这六个字,最近半年在技术会议、招聘JD、内部立项文档里出现的频率,已经超过了“云原生”和“微服务”当年爆发期的峰值。但绝大多数人——包括不少一线工程师——把它理解…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉