0

我知道这与其他问题(例如, this one )非常相似,但我觉得我还没有找到一个答案,其中包括查询的 SELECT 部分如何影响锁的具体问题。

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

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

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

文档说(强调我的):

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

但我可以用多种方式来解释。“有资格”包含在结果集中是什么意思?我没有在我的SELECT不合格”中包含任何列的事实吗?还是“限定”仅指JOIN...ON, WHERE, 和HAVING子句?

谢谢!

4

1 回答 1

0

锁会影响检查的行,无论其列是否是结果的一部分。

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

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

假设有一个索引 onA单独,而没有索引 on B。条件 onA匹配 100 行,但筛选出也匹配条件 on 的子集,B最终结果只有 3 行。但是所有匹配条件的 100 行都A被锁定。这些是检查的行。尽管其中 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

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

于 2021-09-30T15:33:39.783 回答