0

0

mysql中使用SELECT FOR UPDATE语句进行行级锁定

P粉602998670

P粉602998670

发布时间:2026-01-21 11:22:03

|

148人浏览过

|

来源于php中文网

原创

SELECT FOR UPDATE 未锁住行的根本原因是事务未开启或autocommit=1;它仅在显式事务中生效,且依赖索引与隔离级别——RR下加间隙锁+记录锁,无索引则锁全表。

mysql中使用select for update语句进行行级锁定

SELECT FOR UPDATE 为什么没锁住行

根本原因通常是事务未开启或自动提交未关闭。MySQL 的 SELECT FOR UPDATE 只在显式事务中生效,且必须搭配 START TRANSACTIONBEGIN 使用;如果 autocommit=1(默认),每条语句执行完立即提交,锁会立刻释放。

  • 执行前务必确认:
    SELECT @@autocommit;
    返回 0 才安全;若为 1,需先执行 SET autocommit = 0;
  • 不能在视图、临时表、非事务引擎(如 MyISAM)上使用,否则报错 ERROR 1288: The target table ... of the FOR UPDATE clause cannot be updated
  • 锁定范围取决于 WHERE 条件是否命中索引:全表扫描时可能升级为表锁;无索引字段查询会锁全表,极大降低并发性

SELECT FOR UPDATE 在可重复读(RR)隔离级别下的行为

MySQL 默认隔离级别是 REPEATABLE READ,此时 SELECT FOR UPDATE 使用的是**间隙锁(Gap Lock)+ 记录锁(Record Lock)**,不仅锁住匹配的行,还会锁住索引间隙,防止幻读。

  • 例如表 t(id PK, name),执行 SELECT * FROM t WHERE name = 'Alice' FOR UPDATE,若 name 无索引,则锁全表;若有索引但值不存在,仍会锁住该间隙(比如 'Alice' 应该插入的位置)
  • 间隙锁不可被 SELECT ... LOCK IN SHARE MODE 兼容,但可被其他 SELECT FOR UPDATE 阻塞——这是死锁高发场景
  • 想禁用间隙锁?只能临时切到 READ COMMITTED 级别(SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED),但会失去幻读防护

如何验证某行是否已被 SELECT FOR UPDATE 锁定

最直接的方式是用另一会话尝试相同语句并观察阻塞行为,但生产环境不宜盲试。更稳妥的方法是查 INFORMATION_SCHEMA.INNODB_TRX 和锁信息表:

虎课网
虎课网

虎课网是超过1800万用户信赖的自学平台,拥有海量设计、绘画、摄影、办公软件、职业技能等优质的高清教程视频,用户可以根据行业和兴趣爱好,自主选择学习内容,每天免费学习一个...

下载
  • 查看当前活跃事务:
    SELECT trx_id, trx_state, trx_started, trx_query FROM INFORMATION_SCHEMA.INNODB_TRX;
  • 关联锁信息定位被锁行:
    SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_thread, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS w INNER JOIN INFORMATION_SCHEMA.INNODB_TRX b ON b.trx_id = w.blocking_trx_id INNER JOIN INFORMATION_SCHEMA.INNODB_TRX r ON r.trx_id = w.requesting_trx_id;
  • 注意:这些表只显示 InnoDB 层面的锁,不包含表级锁或元数据锁(MDL)

SELECT FOR UPDATE 和 UPDATE 的锁区别

SELECT FOR UPDATE 是“纯读锁”,不修改数据,但会加写锁(X 锁),阻止其他事务读写该行;而 UPDATE 语句本身隐式执行类似逻辑,但多了数据变更和 undo log 写入开销。

  • 若后续确定要更新,推荐直接用 UPDATE ... WHERE ...,避免多一次锁获取;SELECT FOR UPDATE 更适合“读-判-写”三步逻辑,比如库存扣减前先校验余额是否充足
  • UPDATE 在 RR 下也会加间隙锁,但仅当 WHERE 条件涉及索引且存在匹配行时才触发;而 SELECT FOR UPDATE 即使 WHERE 不匹配(如 WHERE id = 999999 不存在),只要索引可用,仍会锁间隙
  • 两者都受 innodb_lock_wait_timeout 控制,默认 50 秒,超时抛出 ERROR 1205: Deadlock found when trying to get lockERROR 1205: Lock wait timeout exceeded

实际应用中最容易忽略的是索引有效性与隔离级别的耦合影响——同一句 SELECT FOR UPDATE,在有无索引、RR 与 RC 下,锁的粒度和范围可能天差地别。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

664

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

246

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

281

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

515

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

255

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

386

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

530

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

599

2023.08.14

Java编译相关教程合集
Java编译相关教程合集

本专题整合了Java编译相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
MySQL 教程
MySQL 教程

共48课时 | 1.8万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 804人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号