InnoDB SELECT … FOR UPDATE 语句锁定表中的所有行
技术问答
216 人阅读
|
0 人回复
|
2023-09-12
|
MySQL 服务器版 5.1.41,启用了 InnoDB 插件。我有以下三个发票表:invoices、invoice_components 和 invoice_expenses。表发票有 invoice_id 主键。invoice_components 和 invoice_expenses 都链接到表发票,包括 invoice_id 作为一个非唯一的外键(每张发票可以有多个组件和多个成本)。两个表都有这个外键 BTREE 索引。
- N& z" f u6 |* g我有以下交易:1 G6 _, Y( w. `$ x
交易 1
4 z; I. T# O, p. ]* v; }. ^START TRANSACTION;
% U7 d* B6 s9 O" g+ I+ q. K* XSELECT * FROM invoices WHERE invoice_id = 18 FOR UPDATE;
: r$ p3 | i- }SELECT * FROM invoice_components WHERE invoice = 18 FOR UPDATE;
- r* B9 U, E5 rSELECT * FROM invoice_expenses WHERE invoice = 18 FOR UPDATE;
6 T2 k$ C- h" t" d. x4 g7 F第一件事一切正常,选择并锁定。
3 ^" @$ s" y! b7 F; N6 [交易2
' G; }/ f- b2 v( H! A4 N# s8 ISTART TRANSACTION; SELECT * FROM invoices WHERE invoice_id = 19 FOR UPDATE; SELECT * FROM invoice_components WHERE invoice = 19 FOR UPDATE; SELECT * FROM invoice_expenses WHERE invoice = 19 FOR UPDATE; 第二个事务ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction返回第三个查询。
+ M. a7 {9 o$ k2 } v当我尝试选择时… FOR UPDATE同样的情况也会发生在其他发票及其组成和费用上。似乎第一笔交易已经锁定 invoice_expenses 表中的一切。为什么会出现任何想法?( y9 `4 F, V* I. ~
附加信息% F( s" b* u2 K, i
事务 2 在事务 1 第三次查询后开始。服务器上没有其他用户、连接或事务。5 a6 E6 t" \: u1 m
这个问题发生在默认 REPEATABLE READ 事务隔离级别。它被改为 READ COMMITTED 级别修复。这是一个解决方案,但它仍然没有解释为什么问题发生在 invoice_expenses 而不是 invoice_components 上。7 r8 A# `& Q4 m
c. @' C d6 A6 f% d0 B
解决方案:
& A6 x y N* |4 I% O! U' Z. W 我怀疑这与间隙锁和谐next-key 锁以及REPEATABLE READ行为差异:
7 }- Q& D- q* L# D摘录来自 MySQL 文档:SET TRANSACTION 语法
! Q C* B9 P; q6 @6 j锁定读取(SELECT with FOR UPDATE 或 LOCK IN SHARE MODE)、UPDATE 和 DELETE 语句的锁定取决于语句是使用具有唯一搜索条件的唯一索引还是范围类型的搜索条件。唯一具有唯一搜索条件的索引,InnoDB 只锁定找到的索引记录,而不锁定它之前的间隙。对于其他搜索条件,InnoDB 锁定扫描的索引范围,使用间隙锁或 next-key(间隙加索引记录)锁,防止其他会话插入范围覆盖的间隙。, j" l* C! j4 M# k4 {
和读提交:1 k) q; j; h: i4 k; H
注意:在 MySQL 5.如果在1 中使用 READ COMMITTED 隔离级别或启用 innodb_locks_unsafe_for_binlog 系统变量,则除了外键约束检查和重复键检查之外,没有 InnoDB 间隙锁定。另外, MySQL 评估 WHERE 条件发生后,将释放不匹配的记录锁。
% ]3 {2 N7 n; t# r也许 OP 可以告诉我们innodb_locks_unsafe_for_binlog system变量的状态,以及在改变变变量设置时是否发生相同的锁定。
5 ~0 r2 J% a8 X. O% x `另外,如果同一锁发生在非顺序 id ,如18and 20,或18and99 |
|
|
|
|
|