例如,我锁定了一些行:
select * from t1 where c2 = 1 for update;c2没有索引。这意味着MySQL必须搜索整个表,如果它读取未提交或读取提交的隔离级别,它会在每个扫描行上设置锁,如果它不满足WHERE条件,则立即释放锁。
如果是可重复的,则读取那些不满足WHERE条件的锁,直到事务结束。
当MySQL出于某种原因搜索索引列时,它不会在不满足WHERE条件的行上设置锁。是的,它使用了另一种算法,允许它在3-4取中找到行,但在找到正确的行之前,它仍然会触及一些行。
发布于 2021-05-31 15:56:31
实际上,真正的问题不是为什么MySQL在使用索引时不锁定行,而是为什么它在不使用索引的情况下锁定这些行。
简化一点(并且取决于您的隔离级别),为查询发出的锁将阻止两件事:
c=1的行不应被另一个事务更改,例如改为c=2,因为它将不再满足您的原始条件c=2行不应更改为c=1 (不应插入带有c=1的新行),因为它现在将满足您的原始条件(因此,如果其他事务优先,则查询会选择它)。
对于第一个便笺点的锁定基本上只需要用c=1锁定行。索引和未索引大小写之间没有根本区别:当前拥有c=1的行最终将被锁定。
然而,对于第二个公报来说,这是比较棘手的:
不幸的是,对于未编入索引的情况,MySQL无法区分另一个事务是否将c=2的行更改为c=5 (这很好),还是将c=2的行更改为c=1 (必须防止)。因为锁太多行要比锁得不够好,所以MySQL只会这样做:锁定所有行。这确保它防止将c=2修改为c=1。其他行上的锁都是抵押品,这是为了获得更大的利益而必须付出的代价(或者不添加索引)。
MySQL将保持这种“过度保护行为”:为了防止使用c=1插入新行,它基本上将通过锁定所有行(和空白,我在这里不详细介绍)来防止任何插入(进入主键)。
对于已索引的情况,MySQL还有另一个选项:如果修改想要将带有c=2的行更改为c=1,则需要该行在索引的c=1区域中获得一个新条目。因此,MySQL可以“只是”在那里放置一个锁,以防止在c=1的索引中注入(插入或更新)。基本上,为了安全起见,它不必先发制人地锁定所有行,但事后可以检测到不允许的修改。
https://stackoverflow.com/questions/67773933
复制相似问题