面试官问:select......for update 会锁表还是锁行?

面试官问:select......for update 会锁表还是锁行?
最新回答
绝尘映雪

2021-12-10 13:28:33

select...for update是悲观锁的一种实现,其加锁行为取决于查询条件是否使用索引/主键:

  • 使用索引/主键:锁定符合条件的(行锁)。
  • 未使用索引/主键:锁定整个(表锁)。
验证过程1. 建表语句CREATE TABLE `user` ( `id` INT(11) NOT NULL AUTO_INCREMENT, `name` VARCHAR(255) DEFAULT NULL, `age` INT(11) DEFAULT NULL, `code` VARCHAR(255) DEFAULT NULL, PRIMARY KEY (`id`), KEY `idx_age` (`age`) USING BTREE) ENGINE=INNODB AUTO_INCREMENT=1570068 DEFAULT CHARSET=utf8;2. 实例验证实例1:使用主键(行锁)
  • 事务1:通过主键id=1查询并加锁。
  • 事务2:尝试更新id=2的数据,成功(未被阻塞)。
  • 结论:仅锁定id=1的行,其他行可正常更新。
实例2:使用索引字段(行锁)
  • 事务1:通过索引字段age=18查询并加锁。
  • 事务2:尝试更新age=20的数据,成功(未被阻塞)。
  • 结论:仅锁定age=18的行,其他索引值可更新。
实例3:未使用索引(表锁)
  • 事务1:通过非索引字段code='test'查询并加锁。
  • 事务2:尝试更新任意行的数据,全部阻塞
  • 结论:未使用索引导致全表锁定。
关键点总结
  1. 索引的重要性

    使用索引/主键时,锁的粒度为行级,避免阻塞其他无关行的操作。

    未使用索引时,锁升级为表级,严重影响并发性能。

  2. 悲观锁特性

    for update会阻塞其他事务对锁定行的修改,直到当前事务提交或回滚。

  3. 验证方法

    通过手动提交模式(set autocommit=0)模拟事务,观察其他事务的阻塞情况。

实际应用建议
  • 优先使用索引字段:确保查询条件命中索引,减少锁冲突。
  • 避免全表扫描:非索引字段的for update会导致性能问题。
  • 短事务设计:尽快提交或回滚事务,减少锁持有时间。

通过以上验证和总结,可以清晰回答面试官的问题,并展示对数据库锁机制的深入理解。