SELECT 语句会加锁吗?

MySQL 中 SELECT 语句是否加锁?详细解析


一、通常的 SELECT 是不是加锁?

默认情况下(普通 SELECT 查询):

  • InnoDB 引擎下,普通的 SELECT 查询不会加行锁或者表锁

  • 只会用到 一致性读(Consistent Read),通过 MVCC(多版本并发控制) 实现,无需加锁即可读取当前事务可见的数据快照

普通 SELECT 是非阻塞的,且不会加锁。


二、哪些 SELECT 语句确实会加锁

并不是所有 SELECT 都不加锁,以下几种情况SELECT 会显式加锁:


1. SELECT ... LOCK IN SHARE MODE

  • 加共享锁(S锁),锁定选中的行,防止其他事务对这些行进行修改或删除。

  • 其他事务可以继续读,但不能改。

示例

SELECT * FROM user WHERE id = 10 LOCK IN SHARE MODE;

特点

  • 当前事务可以继续读这行;

  • 其他事务可以读;

  • 但其他事务不能更新或删除这些行,否则阻塞。

常用于:需要读取数据且后续基于这些数据进行一些决策,确保读到的数据在后续处理前不会被别人修改。


2. SELECT ... FOR UPDATE

  • 加排他锁(X锁),锁定选中的行。

  • 当前事务可以读,也可以改;

  • 其他事务不能读(如果是RC隔离级别还能读但不能改),也不能改、不能删。

示例

SELECT * FROM user WHERE id = 10 FOR UPDATE;

特点

  • 只有当前事务能读写这些行;

  • 其他事务读(隔离级别有关)或者写都会阻塞。

常用于

  • 乐观锁/悲观锁场景。

  • 实现扣库存、扣余额等强一致性更新操作


3. 可重复读隔离级别下,防止幻读(隐式加锁)

REPEATABLE READ 隔离级别下,即使普通 SELECT,为了防止幻读,也可能触发内部加锁机制(特别是间隙锁、临键锁)。

比如在某些情况下,针对索引范围的扫描,会加上间隙锁,防止其他事务插入新记录,造成幻读。


三、锁类型汇总(带示意)

查询方式是否加锁加锁类型
普通 SELECT(无加锁语法)只使用MVCC,生成一致性快照
SELECT ... LOCK IN SHARE MODE共享锁(S锁)
SELECT ... FOR UPDATE排他锁(X锁)
隔离级别为 REPEATABLE READ 时的范围查询可能隐式 Next-Key Lock(行锁+间隙锁)

四、示例总结

1. 普通查询(不加锁)

SELECT * FROM orders WHERE id = 123;
  • 不加锁;

  • 快照读,读取事务启动时可见的数据版本。


2. 加共享锁

SELECT * FROM orders WHERE id = 123 LOCK IN SHARE MODE;
  • S锁,防止被别人修改;

  • 适合读后校验,但不修改的场景。


3. 加排他锁

SELECT * FROM orders WHERE id = 123 FOR UPDATE;
  • X锁,其他事务不能改也不能删;

  • 适合读后即将修改的场景,比如扣减库存。


五、注意事项

  • FOR UPDATELOCK IN SHARE MODE 必须在事务中使用START TRANSACTION),否则加锁就没有意义,MySQL自动提交后锁立即释放。

  • 如果没有显式加锁,普通 SELECT 默认采用非锁定一致性读,走 MVCC 快照机制,不阻塞,不加锁,性能最好。

  • 加锁的 SELECT 查询,涉及的行需要有索引,否则可能导致范围过大,性能变差甚至锁表。


最终一句话总结

普通 SELECT 不加锁,靠 MVCC;加了 LOCK IN SHARE MODEFOR UPDATE 的 SELECT,才加共享锁或排他锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值