我有两次会议。
Session 1>start transaction;
Session 1>select * from account for update;
Session 2>start transaction;
Session 2>select * from account for update; //waiting.
由于IX锁与IX锁兼容,因此第二个会话不应在没有等待的情况下也获得IX锁。
即使下面的状态集都不起作用。
Session 1>start transaction;
Session 1>select * from account where i = 1 for update;
Session 2>start transaction;
Session 2>select * from account where i = 2 for update; //waiting.
隔离级别为Repeatable Read
。在此隔离级别上是否有所不同?
兼容性来源this
答案 0 :(得分:1)
您显示的两个查询获取表的IX锁,它们彼此兼容。
但是SELECT...FOR UPDATE
也会继续在它检查的行上获取X锁。这些是冲突,这就是第二个SELECT...FOR UPDATE
等待的原因。
在您的示例中,一个查询针对行WHERE i = 1
,而另一查询针对行WHERE i = 2
,则它们将不会返回相同的行,但是会检查一个重叠的行行集,如果i
没有索引。检查行意味着InnoDB获取行,然后针对WHERE子句中的条件对其进行测试。根据条件,它可能会跳过它检查的某些行,并且仅在检查的行为true时才返回检查的行。
如果您在i
上有索引,则InnoDB可以排除不匹配的行,而无需检查行。在这种情况下,您的示例将不会显示冲突。
Session 1>ALTER TABLE account ADD INDEX (i);
Session 1>start transaction;
Session 1>select * from account where i = 1 for update;
Session 2>start transaction;
Session 2>select * from account where i = 2 for update; // does NOT wait
答案 1 :(得分:0)
使用SELECT ... FOR UPDATE
时,MySQL将尝试在查询将返回的所有行和关联的索引条目上获得IX(意向排他锁)锁。来自documentation:
对于索引记录,记录搜索遇到的内容,锁定行和任何关联的索引条目,就像为这些行发出UPDATE语句一样。
您的两个事务之一将首先执行FOR UPDATE
,然后无论哪个成功,都将锁定整个表,因为选择是SELECT *
而没有任何{ {1}}子句。
更现实的现实情况是,一个事务锁定了一些记录以进行更新,而另一个事务同时锁定了一些其他行。在这种情况下,两个事务都可能能够同时进行。这是两个选择更新的示例,这些选择不会锁定相同的记录(假设两个结果集都不为空)
WHERE
如果上面仍然看到第二个稍后的事务阻塞,那可能是因为MySQL有时还可以在实际目标记录之后锁定间隙。