MySQL InnoDB - 在使用连接表进行锁定读取期间,即使没有选择任何列,连接的行也会被锁定吗?

Posted

技术标签:

【中文标题】MySQL InnoDB - 在使用连接表进行锁定读取期间,即使没有选择任何列,连接的行也会被锁定吗?【英文标题】:MySQL InnoDB - During a locking read with joined tables, will the joined rows be locked even if no columns are SELECTed? 【发布时间】:2021-11-22 10:46:55 【问题描述】:

我知道这与其他问题非常相似(例如,this one),但我觉得我还没有找到包含特定问题的答案,即查询会影响锁。

具体来说,我有两个表之间的父子关系,通过引用父主键的子表上的外键强制执行。在我正在开发的一个软件中,我想采用“路径”(父键+子键)并仅在子行是有效的“路径”时才返回子行。因此,查询将类似于:

SELECT Child.*
FROM Child
INNER JOIN Parent ON Parent.id = Child.parent_id
WHERE Parent.id = ? AND Child.id = ?
FOR UPDATE

我从我链接的另一个问题中了解到,如果我执行 SELECT *,父行被锁定。但我不确定当我实际上没有返回任何父行的列时这种情况是否会改变。

documentation 说(强调我的):

对于 SELECT ... FOR UPDATE 或 SELECT ... LOCK IN SHARE MODE,会为扫描的行获取锁,预计会为不符合包含在结果集中的行释放锁 (例如,如果它们不符合 WHERE 子句中给出的条件)。但是,在某些情况下,行可能不会立即解锁,因为结果行与其原始源之间的关系在查询执行期间丢失。

但我可以用多种方式来解释。 “有资格”包含在结果集中是什么意思?我没有在我的SELECT "disqualify" 中包含任何列的事实是否证明了这一点?还是“限定”仅指JOIN...ONWHEREHAVING 子句?

谢谢!

【问题讨论】:

【参考方案1】:

锁影响检查的行,不管它的列是否是结果的一部分。

您可能对没有 JOIN 的查询有同样的疑问:

SELECT ... FROM MyTable WHERE A = 123 AND B = 456;

假设A 上只有一个索引,而B 上没有索引。 A 上的条件匹配 100 行,但是过滤与B 上的条件也匹配的子集,最终结果只有 3 行。但是与A 上的条件匹配的所有 100 行都被锁定。这些是检查的行。尽管其中 97 个不在最终结果中,但它们都被锁定。

同样,查询中的表达式引用Parent 的列,这使得相应的行被检查为行。


演示:

mysql> create table MyTable (id serial primary key, a int, key (a), b int);

mysql> insert into mytable set a = 123, b = 456;

mysql> insert into mytable set a = 124, b = 457;

mysql> start transaction;

mysql> select * from mytable where a = 123 and b = 456 for update;
+----+------+------+
| id | a    | b    |
+----+------+------+
|  1 |  123 |  456 |
+----+------+------+

现在根据您对文档的阅读,a=123, b=457 的行应该被锁定,对吧?

所以在第二个窗口中,我尝试使用锁定读取来读取它:

mysql> select * from mytable where a = 123 and b = 457 lock in share mode;
... waits for 50 seconds ...
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

在第一个窗口中被锁定读取锁定的行包括所有检查的行,即与a 上的索引匹配的所有行,即使其中一些被@987654331 上的非索引条件排除@。

【讨论】:

感谢您的回答。但是,您的示例似乎与文档背道而驰。它特别指出,锁定“预计会为不符合包含在结果集中的行(例如,如果它们不符合 WHERE 子句中给出的条件)释放”。所以,我希望这 97 行在事务期间不会被锁定。 见我上面的演示。你可以自己试试!

以上是关于MySQL InnoDB - 在使用连接表进行锁定读取期间,即使没有选择任何列,连接的行也会被锁定吗?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 事物控制和锁定语句

深入浅出Mysql——事务控制和锁定语句

mysql-innoDB-锁

MySQL行表锁定

MySQL 储存引擎 MyISAM 和 InnoDB 配置

mysql innodb存储引擎和myisam引擎