mysql中读写锁的使用与性能调优

发布时间 - 2026-01-09 00:00:00    点击率:
SELECT ... FOR UPDATE 用于先查后改场景(如扣库存),加排他锁;SELECT ... LOCK IN SHARE MODE 用于协同只读场景(如报表),加共享锁;二者均需事务、索引支持,否则退化为表锁或间隙锁。

MySQL 中 SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE 的适用场景

这两个语句是 InnoDB 实现行级读写锁的核心手段,但它们不是“加锁就能用”,而是必须在事务中生效,且只对索引列有效。如果 WHERE 条件未命中索引,InnoDB 会退化为表锁(或间隙锁组合),导致并发骤降。

  • SELECT ... FOR UPDATE:适用于需要“先查后改”的典型场景,比如扣减库存、转账前校验余额——它会加排他锁(X 锁),阻塞其他事务的读写
  • SELECT ... LOCK IN SHARE MODE:适合多事务需协同读取同一数据但不修改的场景,比如生成报表时防止基础数据被删——它加共享锁(S 锁),允许其他事务加 S 锁,但阻塞 X 锁
  • 两者都要求事务隔离级别为 READ COMMITTEDREPEATABLE READ;在 READ UNCOMMITTED 下会被忽略

为什么 FOR UPDATE 有时锁住整张表而不是某几行

根本原因在于锁的粒度由执行计划决定,而非 SQL 表面写法。即使写了 WHERE id = 123,若 id 列没有索引,优化器无法定位具体行,只能走全表扫描,进而对所有聚簇索引记录加 X 锁——表现就是“锁表”。

  • EXPLAIN 检查执行计划:type 字段必须是 constrefrange,不能是 ALLindex
  • 注意隐式类型转换:比如 WHERE user_id = '123'(字段是 INT),会导致索引失效,锁范围扩大
  • 唯一索引和普通索引行为不同:非唯一索引可能触发间隙锁(Gap Lock),锁住不存在的值区间,造成意外阻塞

高并发下锁等待超时与死锁的实际应对

Lock wait timeout exceededDeadlock found when trying to get lock 是线上最常遇到的两类锁问题,但它们成因和处理方式完全不同。

  • 锁等待超时(Lock wait timeout exceeded):通常是事务持有锁时间过长(比如事务里混入 HTTP 调用、日志写入或 sleep),应缩短事务生命周期,把非数据库操作移出事务块
  • 死锁(Deadlock found when trying to get lock):本质是循环等待,MySQL 会自动回滚代价小的事务。关键不是避免死锁(不可能完全避免),而是让应用能捕获 errno 1213 并重试——尤其对幂等性操作(如更新状态)必须支持重试逻辑
  • 通过 SHOW ENGINE INNODB STATUS\G 查看最近死锁详情,重点关注 TRANSACTION 块中的 lock_mode X locks rec but not gap 等描述,定位哪几行/哪个索引被争抢

替代方案:用 INSERT ... ON DUPLICATE KEY UPDATEREPLACE INTO 规避显式锁

当业务逻辑本质是“存在则更新,不存在则插入”,硬上 SELECT ... FOR UPDATE + INSERT/UPDATE 不仅代码冗长,还放大锁竞争。这类场景优先考虑原子性更强的替代语法。

  • INSERT ... ON DUPLICATE KEY UPDATE:依赖唯一索引(主键或 UNIQUE 约束),整个操作由 InnoDB 内部加锁完成,无需手动控制事务顺序,性能更稳
  • REPLACE INTO:底层是 DELETE + INSERT,会触发两次索引查找和锁操作,且可能引发自增 ID 跳变,在高并发下不如前者可控
  • 注意:这两者仍会加锁,但锁的持有时间极短(仅在索引查找和行修改瞬间),且无事务上下文依赖,天然规避了长事务锁表风险
INSERT INTO order_lock (order_id, status, updated_at) 
VALUES (1001, 'processing', NOW()) 
ON DUPLICATE KEY UPDATE status = 'processing', updated_at = NOW();
锁的复杂性不在语法本身,而在于它和索引、事务、隔离级别、执行路径深度耦合。一个没走索引的 FOR UPDATE,比十个没加锁的 UPDATE 更容易拖垮系统。


# mysql  # ai  # 隐式类型转换  # 为什么  # 有锁  # sql  # for  # select  # const  # errno  # int  # 循环  # delete  # 类型转换  # 并发  # 数据库  # http  # 死锁  # 加锁  # 不存在  # 锁住  # 重试  # 几行  # 不可能  # 两次  # 适用于  # 这两个 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: php增删改查怎么学_零基础入门php数据库操作必知基础【教程】  电视网站制作tvbox接口,云海电视怎样自定义添加电视源?  如何用手机制作网站和网页,手机移动端的网站能制作成中英双语的吗?  在线制作视频的网站有哪些,电脑如何制作视频短片?  Laravel如何实现本地化和多语言支持_Laravel多语言配置与翻译文件管理  Laravel如何实现文件上传和存储?(本地与S3配置)  微信小程序 input输入框控件详解及实例(多种示例)  Linux虚拟化技术教程_KVMQEMU虚拟机安装与调优  Internet Explorer官网直接进入 IE浏览器在线体验版网址  Claude怎样写约束型提示词_Claude约束提示词写法【教程】  北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?  如何在沈阳梯子盘古建站优化SEO排名与功能模块?  网站设计制作书签怎么做,怎样将网页添加到书签/主页书签/桌面?  php读取心率传感器数据怎么弄_php获取max30100的心率值【指南】  如何用5美元大硬盘VPS安全高效搭建个人网站?  jimdo怎样用html5做选项卡_jimdo选项卡html5实现与切换效果【指南】  Laravel怎么发送邮件_Laravel Mail类SMTP配置教程  如何基于云服务器快速搭建网站及云盘系统?  手机软键盘弹出时影响布局的解决方法  网页制作模板网站推荐,网页设计海报之类的素材哪里好?  ,网页ppt怎么弄成自己的ppt?  企业网站制作这些问题要关注  开心动漫网站制作软件下载,十分开心动画为何停播?  Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置  微信公众帐号开发教程之图文消息全攻略  黑客入侵网站服务器的常见手法有哪些?  Laravel定时任务怎么设置_Laravel Crontab调度器配置  谷歌浏览器下载文件时中断怎么办 Google Chrome下载管理修复  php 三元运算符实例详细介绍  html5如何实现懒加载图片_ intersectionobserver api用法【教程】  Android仿QQ列表左滑删除操作  如何在阿里云部署织梦网站?  Laravel模型关联查询教程_Laravel Eloquent一对多关联写法  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  JS中页面与页面之间超链接跳转中文乱码问题的解决办法  bootstrap日历插件datetimepicker使用方法  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  教你用AI润色文章,让你的文字表达更专业  javascript事件捕获机制【深入分析IE和DOM中的事件模型】  Laravel中间件如何使用_Laravel自定义中间件实现权限控制  Laravel如何使用Eloquent进行子查询  Laravel如何使用.env文件管理环境变量?(最佳实践)  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  如何在局域网内绑定自建网站域名?  活动邀请函制作网站有哪些,活动邀请函文案?  如何用AWS免费套餐快速搭建高效网站?  深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?  谷歌浏览器如何更改浏览器主题 Google Chrome主题设置教程  Laravel如何生成PDF或Excel文件_Laravel文档导出工具与使用教程  Laravel storage目录权限问题_Laravel文件写入权限设置