mysql - 为什么 MySQL InnoDB 还为更新/删除操作获取 Gap 锁?
问题描述
据我所知,间隙锁用于防止幻读,我发现间隙锁是通过谷歌搜索在大多数文章中锁定读取设置的。
间隙锁是在索引记录之间的间隙上的锁,或在第一条索引记录之前或最后一条索引记录之后的间隙上的锁。例如,SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE;防止其他事务将值 15 插入 t.c1 列,无论该列中是否已经存在任何此类值,因为该范围内所有现有值之间的间隙都已锁定。
https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html#innodb-gap-locks
我想这(在锁定读取时设置间隙锁定)就足够了。为什么更新、删除还要设置间隙锁。
UPDATE ... WHERE ...在搜索遇到的每条记录上设置一个排他的下一个键锁。但是,对于使用唯一索引锁定行以搜索唯一行的语句,只需要一个索引记录锁。
https://dev.mysql.com/doc/refman/8.0/en/innodb-locks-set.html
另一个问题是如果没有合适的索引可以附加间隙锁会发生什么?是否回退锁定整个表?
这里我们假设使用默认的事务隔离级别Repeatable Read。
解决方案
这取决于您的 SELECT、UPDATE 或 DELETE 中的条件。他们设置间隙锁以防止其他并发会话将行添加到条件匹配的集合中。
在 InnoDB 中,锁定语句总是锁定最近提交的行版本。所以他们并没有真正遵守 REPEATABLE READ 快照。它们的行为更像 READ-COMMITTED。
因此,如果你做这样的声明:
UPDATE FROM MyTable SET ... WHERE created_at > '2020-03-22';
它必须锁定 created_at 最大值之后的间隙,这将阻止其他会话添加新行。
这是为了模拟REPEATABLE READ,以确保如果再次运行相同的 UPDATE,它将影响相同的行,并且不会意外影响新行。
推荐阅读
- python - 无法从 Celery 访问数据库 - OperationalError('no such table: products_product')
- python-3.x - 如何在数据块上为 ML 运行时环境启用 GPU 可见?
- latex - 如何在乳胶中的某些列上居中表的列名?
- python - 计算公式,其中一行与熊猫中所有其他行的差异之和
- javascript - 使用 useEffect 响应登录验证
- css - 如何为使用自定义 SVG 形状遮罩的图像添加嵌入阴影?
- docker - Docker 卷对不同图像的行为不同
- java - EJB 远程 JNDI 查找不适用于托管在 aws ec2 上的 glassfish4 服务器
- reactjs - 为什么我们不为 npm start 提及像 node app.js 这样的文件名?
- python - Tensorflow:初始化连接张量的正确方法?