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

redis和数据库实现分布式锁

目录

  • 一、为什么需要分布式锁
    • 1. 什么是锁
    • 2. 单机锁为什么失效
  • 二、分布式锁是什么
  • 三、分布式锁需要满足什么条件
    • 1. 互斥性
    • 2. 可重入
    • 3. 防死锁
    • 4. 高可用
  • 四、Redis实现分布式锁
    • 1. 原理
    • 2. Spring Boot实现
      • 加锁
      • 释放锁
    • 3. Redisson实现
  • 五、数据库唯一索引实现分布式锁
    • 1. 建表
    • 2. 获取锁
    • 3. 原理
    • 4. 缺点
  • 六、数据库乐观锁(版本号)
    • 1. 表结构
    • 2. 查询
    • 3. 更新
    • 4. 原理
    • 5. MyBatis Plus实现
  • 七、数据库悲观锁
    • 1. 获取锁
    • 2. 原理
    • 3. 缺点
  • 八、ZooKeeper实现分布式锁
  • 九、各种方案对比
  • 十、单机环境如何实现锁
    • 1. synchronized
    • 2. ReentrantLock
    • 3. ReadWriteLock
  • 总结

一、为什么需要分布式锁

1. 什么是锁

锁(Lock)的本质是:

保证同一时刻只有一个线程(或一个进程)能够执行某段代码。

例如:

publicvoiddeductStock(){stock--;}

假设库存为 1:

  • 用户A购买
  • 用户B购买

两个线程同时执行:

stock--;

结果可能变成:

库存:-1

这就是典型的并发问题。

因此需要锁来保证:

synchronized(lock){stock--;}

同一时刻只能有一个线程进入。


2. 单机锁为什么失效

在单体应用中:

JVM ┌─────────────────┐ │ Thread-1 │ │ Thread-2 │ │ synchronized │ └─────────────────┘

synchronizedReentrantLock都能正常工作。

但是微服务部署后:

Nginx / \ Service-A Service-B JVM1 JVM2

用户请求可能进入:

请求1 -> JVM1 请求2 -> JVM2

此时:

synchronized(lock)

只锁住当前 JVM。

因为:

JVM1 不知道 JVM2 的锁状态 JVM2 不知道 JVM1 的锁状态

于是两个服务同时执行。

这就是:

本地锁失效问题

因此需要:

所有节点共享同一把锁

这就是分布式锁。


二、分布式锁是什么

定义:

分布式系统中多个节点共同竞争同一个共享资源时,用来保证同一时刻只有一个节点执行操作的机制。

例如:

秒杀活动 定时任务 订单创建 库存扣减 退款操作

都可能需要分布式锁。


三、分布式锁需要满足什么条件

一个合格的分布式锁通常需要满足:

1. 互斥性

同一时间只能一个客户端获得锁

2. 可重入

例如:

methodA()->methodB()

methodA已经获得锁。

methodB再次加锁:

lock.lock();

不能死锁。


3. 防死锁

持有锁的服务挂掉:

JVM Crash

锁必须自动释放。

通常依赖:

TTL过期时间

4. 高可用

Redis挂了:

锁全部失效

需要主从、哨兵或集群保障。


四、Redis实现分布式锁

这是目前最常见的方案。


1. 原理

Redis提供:

SET key value NX EX 30

含义:

NX:不存在才创建 EX:30秒过期

执行成功:

OK

说明获得锁。

执行失败:

null

说明锁已被占用。


2. Spring Boot实现

加锁

@AutowiredprivateStringRedisTemplateredisTemplate;publicbooleantryLock(Stringkey){returnBoolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key,UUID.randomUUID().toString(),30,TimeUnit.SECONDS));}

底层执行:

SET lock:order uuid NX EX 30

释放锁

错误写法:

redisTemplate.delete(key);

问题:

线程A锁超时 线程B获得锁 线程A执行delete 把线程B的锁删了

正确做法:

Stringlua="if redis.call('get',KEYS[1])==ARGV[1] then "+" return redis.call('del',KEYS[1]) "+"else return 0 end";redisTemplate.execute(newDefaultRedisScript<>(lua,Long.class),Collections.singletonList(key),uuid);

保证:

谁加锁 谁解锁

3. Redisson实现

实际项目更推荐。

引入:

<dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId></dependency>

获取锁:

RLocklock=redissonClient.getLock("orderLock");try{lock.lock();createOrder();}finally{lock.unlock();}

优点:

自动续期 可重入 看门狗机制 高可靠

面试中一般回答:

生产环境推荐 Redisson。


五、数据库唯一索引实现分布式锁

这是最简单的方案之一。


1. 建表

CREATETABLEdistributed_lock(lock_nameVARCHAR(100)PRIMARYKEY,create_timeDATETIME);

2. 获取锁

try{lockMapper.insert(lockName);returntrue;}catch(DuplicateKeyExceptione){returnfalse;}

对应SQL:

INSERTINTOdistributed_lockVALUES('ORDER_LOCK',NOW());

3. 原理

假设:

JVM1 插入成功 JVM2 插入同样主键

数据库保证:

主键唯一

第二次插入失败。

因此:

只有一个服务获得锁

4. 缺点

数据库压力大:

频繁insert 频繁delete

性能远低于Redis。


六、数据库乐观锁(版本号)

严格来说:

它不是传统意义上的分布式锁

但经常用于解决并发问题。


1. 表结构

CREATETABLEstock(idBIGINT,stockINT,versionINT);

数据:

stock = 100 version = 1

2. 查询

SELECTstock,versionFROMstockWHEREid=1;

得到:

stock=100 version=1

3. 更新

UPDATEstockSETstock=stock-1,version=version+1WHEREid=1ANDversion=1;

4. 原理

线程A:

version=1

线程B:

version=1

线程A先更新:

version=2

线程B再更新:

WHEREversion=1

匹配不到。

更新失败:

update count = 0

然后重试。


5. MyBatis Plus实现

实体:

@VersionprivateIntegerversion;

配置:

@BeanpublicMybatisPlusInterceptorinterceptor(){MybatisPlusInterceptorinterceptor=newMybatisPlusInterceptor();interceptor.addInnerInterceptor(newOptimisticLockerInnerInterceptor());returninterceptor;}

更新时自动带:

version=oldVersion

条件。


七、数据库悲观锁

利用数据库行锁。


1. 获取锁

SELECT*FROMstockWHEREid=1FORUPDATE;

2. 原理

事务提交前:

其他事务无法修改这条记录

例如:

@TransactionalpublicvoiddeductStock(){Stockstock=stockMapper.selectForUpdate(1L);stock.setCount(stock.getCount()-1);stockMapper.update(stock);}

3. 缺点

性能较差:

锁粒度大 阻塞严重 数据库压力高

八、ZooKeeper实现分布式锁

原理:

临时顺序节点

例如:

/lock/order0001 /lock/order0002 /lock/order0003

最小节点获得锁:

order0001

删除后:

order0002

获得锁。

常见框架:

Apache Curator

优点:

一致性强 可靠

缺点:

实现复杂 性能低于Redis

九、各种方案对比

方案性能实现难度推荐程度
synchronized★★★★★简单单机
ReentrantLock★★★★★简单单机
数据库唯一索引★★简单小项目
数据库悲观锁★★简单一般
数据库乐观锁★★★★简单库存扣减
ZooKeeper★★★复杂大型系统
Redis+Lua★★★★★中等推荐
Redisson★★★★★简单生产推荐

十、单机环境如何实现锁

如果系统没有部署多个实例:

只有一个JVM

那么根本不需要分布式锁。


1. synchronized

publicsynchronizedvoidcreateOrder(){}

或者:

privatefinalObjectlock=newObject();synchronized(lock){}

特点:

JDK内置 自动释放 简单

2. ReentrantLock

privatefinalReentrantLocklock=newReentrantLock();publicvoidcreateOrder(){lock.lock();try{//业务逻辑}finally{lock.unlock();}}

优点:

可重入 可中断 支持公平锁 支持超时

3. ReadWriteLock

读多写少场景:

privateReadWriteLocklock=newReentrantReadWriteLock();

读锁:

lock.readLock().lock();

写锁:

lock.writeLock().lock();

特点:

多个读线程同时执行 写线程独占

总结

分布式锁的核心目标只有一句话:

在多个 JVM、多个服务实例同时访问同一资源时,保证同一时刻只有一个节点执行关键业务逻辑。

实际生产中:

  • 单机应用:synchronizedReentrantLock
  • 库存扣减:乐观锁(Version)
  • 中小项目:Redis + Lua
  • 企业级项目:Redisson
  • 强一致性场景:ZooKeeper

学习路径,掌握:

synchronized → ReentrantLock → Redis SET NX EX → Lua释放锁 → Redisson看门狗 → 乐观锁Version → ZooKeeper临时顺序节点

http://www.cnnetsun.cn/news/2881732.html

相关文章:

  • 大华 海康 宇视 摄像头 onvif协议 时间同步 实战踩坑与兼容性解析
  • Google 推出 Gemini 3.5 Live Translate:打破「对讲机」式翻译,让对话无缝衔接
  • OpenLayers 6 动态流动线效果实战:从静态GeoJSON到‘活’地图的保姆级教程
  • 别再问怎么连PLC了!手把手教你用Python+SMLP协议读写三菱FX5U数据
  • 2026视频转文字工具怎么选?免费方案+详细教程一看就会
  • AI动态简报之技术前沿篇(2026.06.11)
  • 融合七普数据与WorldPop:ArcGIS实战人口栅格精细化修正指南
  • JSC低功耗SDRAM存储芯片DDR架构
  • MPC7455处理器热管理实战:从热阻计算到散热选型与验证
  • TrollInstallerX:iOS 14.0-16.6.1 系统上的高级越狱安装解决方案
  • 深入解析MSC8156六核DSP架构:从核心设计到硬件实战避坑指南
  • ThinkPad开机卡顿?BIOS中Secure Boot与UEFI/Legacy设置实战解析
  • Claude 5 震撼发布并限时免费开放!实测最强 Mythos/Fable “神话级”模型,到底有多牛?
  • AI Agent在内容营销全链路的应用:从选题、创作到分发的自动化
  • AI 辅助的 API 接口 Mock 数据生成:前端独立开发的数据引擎
  • 关于C语言的介绍
  • 5分钟搞定黑苹果配置:OpCore-Simplify的智能革命
  • 模拟CMOS 进阶解析——短沟道效应与FinFET工艺的博弈
  • 从Kaggle经典赛题到实战:Rossmann销售额预测的数据探索与特征工程全解析
  • 告别手动建模!用Gmsh Python API快速生成复杂三维网格(附完整代码)
  • 从工艺文件到精准模型:EMX PROC编写与电感仿真实践
  • GitHub 7 月更改默认设置堵攻击途径,虽姗姗来迟但意义重大!
  • 厂区内人员跌倒操作间工作间人员摔倒检测数据集VOC+YOLO格式2898张4类别
  • MySQL 存储引擎
  • AI 电动家用电器智能功率 MOSFET 完整选型方案
  • MRIcroGL:医学影像三维可视化的免费开源终极指南
  • 3篇2章1节:医学综述的撰写临床综述的主要类型和分享 AI 辅助技巧
  • 【网安利器实战】——Sqlmap进阶:从自动化注入到权限提升
  • DDrawCompat架构深度解析:DirectDraw兼容性革命与性能突破
  • 从四色定理到算法实战:手把手教你用C++实现地图填色回溯法(附完整代码)