尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

悲观锁,乐观锁和redis分布式锁

悲观锁,乐观锁和redis分布式锁
📅 发布时间:2026/6/20 9:04:29

​​悲观锁(Pessimistic Lock)​​

​​为什么叫 "悲观"?​​

因为它 ​​"悲观" 地认为并发操作一定会发生冲突​​,所以在操作数据之前,​​先加锁​​,确保其他事务无法修改这条数据,直到当前事务完成。

​​实现方式​​(数据库层面):

  • SELECT ... FOR UPDATE(MySQL)

  • SELECT ... WITH (UPDLOCK)(SQL Server)

  • 其他数据库的排他锁机制

​​特点​​:

  • ​​先锁再操作​​,防止并发修改

  • ​​适用于高并发写操作​​(如抢购、库存扣减)

  • ​​可能降低并发性能​​(锁会阻塞其他事务)

​​示例​​(ThinkPHP):

 
Db::startTrans(); // 开启事务 $info = $this->where(['id' => $id])->lock(true)->find(); // 加悲观锁 // ... 处理数据 ... Db::commit(); // 提交事务(释放锁)
 
 

​​乐观锁(Optimistic Lock)​​

​​为什么叫 "乐观"?​​

因为它 ​​"乐观" 地认为并发操作不会冲突​​,所以 ​​不加锁​​,而是在更新时检查数据是否被修改过(通常用版本号或时间戳)。

​​实现方式​​:

  • ​​版本号机制​​(version字段)

  • ​​时间戳机制​​(update_time字段)

  • ​​CAS(Compare-And-Swap)​​(如 Redis)

​​特点​​:

  • ​​不加锁,先操作再检查冲突​​

  • ​​适用于读多写少的场景​​

  • ​​冲突时需要重试或回滚​​

​​示例​​(ThinkPHP):

 
// 假设数据表有 `version` 字段 $data = $this->where(['id' => $id])->find(); $newData = ['name' => 'new_name', 'version' => $data['version'] + 1]; $result = $this->where(['id' => $id, 'version' => $data['version']])->save($newData); if (!$result) { // 更新失败,说明数据被其他人修改过,可以重试或报错 }
 
 

​​对比总结​​

特性

悲观锁(Pessimistic Lock)

乐观锁(Optimistic Lock)

​​加锁方式​​

先加锁再操作(FOR UPDATE)

不加锁,更新时检查冲突

​​适用场景​​

高并发写操作(如抢购)

读多写少(如文章编辑)

​​性能影响​​

可能降低并发性能(锁阻塞)

无锁,冲突时才处理

​​实现方式​​

数据库锁机制

版本号、时间戳、CAS

​​冲突处理​​

其他事务会被阻塞

需要重试或回滚

​​如何选择?​​

  • ​​悲观锁​​:数据竞争激烈,必须保证数据一致性(如支付、库存扣减)。

  • ​​乐观锁​​:冲突概率低,希望提高并发性能(如文章编辑、评论更新)。

 

redis分布式锁:

这段代码的作用是 ​​使用 Redis 的 SETNX(SET if Not eXists)实现分布式锁​​,防止并发重复提交(如重复提现)。具体解析如下:


​​代码解析​​

 
if (!setLockNx($withdrawLockKey, 30)) { //提现锁,处理完手动解锁 json_exit_Base64(401, lang("处理中,请勿重复点击")); }
 
 
  1. ​​setLockNx($withdrawLockKey, 30)​​

    • 调用一个自定义函数(可能是封装了 Redis 的 SETNX命令)。

    • ​​$withdrawLockKey​​:锁的唯一标识(如用户ID + 业务类型,例如 withdraw:user123)。

    • ​​30​​:锁的自动过期时间(单位:秒),防止锁未释放导致死锁。

  2. ​​!setLockNx(...)​​

    • 如果获取锁失败(返回 false),说明锁已存在(即当前有其他请求正在处理相同业务)。

    • 直接返回错误提示,阻止重复操作。

  3. ​​json_exit_Base64(401, ...)​​

    • 返回 HTTP 401 状态码和 Base64 编码的 JSON 错误消息(可能是项目约定的通信格式)。

    • 提示用户:"处理中,请勿重复点击"。

  4. ​​注释说明​​

    • //提现锁,处理完手动解锁:提示开发者需要在业务逻辑完成后 ​​手动释放锁​​(如调用 delLock($withdrawLockKey)),否则锁会在 30 秒后自动过期。


​​实现原理(Redis 分布式锁)​​

  1. ​​加锁​​

    通过 Redis 的 SETNX命令实现原子性锁:

     
    SETNX $withdrawLockKey 1 # 如果 key 不存在则设置成功(返回1),否则失败(返回0) EXPIRE $withdrawLockKey 30 # 设置过期时间,避免程序崩溃导致死锁
     
     

    (注:高版本 Redis 支持 SET $withdrawLockKey 1 NX EX 30一步完成)

  2. ​​解锁​​

    业务处理完成后需手动删除 key:

     
    DEL $withdrawLockKey
     
     

​​适用场景​​

  • ​​提现/支付防重​​:防止用户多次点击导致重复扣款。

  • ​​秒杀/库存扣减​​:避免超卖问题。

  • ​​任何需要分布式环境下的互斥操作​​(如定时任务防并发执行)。


​​注意事项​​

  1. ​​锁的粒度​​

    • 锁的 key 需要足够具体(例如包含用户ID),避免不同用户互相阻塞。

  2. ​​锁的过期时间​​

    • 过期时间(如30秒)需大于业务处理时间,但不宜过长(否则阻塞其他请求)。

  3. ​​原子性问题​​

    • 确保 SETNX + EXPIRE是原子操作(如用 Redis 2.6.12+ 的 SET命令带 NX和 EX参数)。

  4. ​​手动解锁​​

    • 如果业务逻辑异常退出,需在 finally块中释放锁,或依赖自动过期。

每天进步一点点

相关新闻

  • US$33.25 YANHUA ACDP N20/N13 Integrated Interface Board
  • 苍穹外卖-day06(HttpClient) - a
  • 元人文AI的领域化部署:从哲学构想到实践应用的完整路径

最新新闻

  • 2026南昌漏水检测维修本地口碑防水商家榜单:厨卫/阳台/屋面/地下室渗漏水维修,持证施工+明码实价,防水补漏公司TOP5推荐 - 即刻修防水
  • 2026年市面上质量好的电缆防火涂料源头厂家怎么选 - 品牌排行榜
  • 从java走向java ee 从Java到Java EE?JVM不死,只是老当益壮
  • PLM破解研发数据孤岛:跨部门流程协同与研发效率提升实战指南
  • ChatGPT帮我写SECS/GEM通信代码:一个MES工程师的AI提效实战
  • 怎样高效获取音乐歌词:3大实用技巧与专业工具实战指南

日新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号