是否可以对刚刚更新的行进行幻读?
Is it possible to do a Phantom read to a row someone just updated?
来自 MySQL 词汇表:
phantom: A row that appears in the result set of a query, but not in the result set of an earlier query. For example, if a query is run twice within a transaction, and in the meantime, another transaction commits after inserting a new row or updating a row so that it matches the WHERE clause of the query.
加粗部分正确吗?如果我有
CREATE TABLE t1 (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`c1` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
隔离级别是可重复读的,我也是
mysql> start transaction;
mysql> SELECT * FROM t1 WHERE c1 < 10;
+----+------+
| id | c1 |
+----+------+
| 1 | 4 |
+----+------+
mysql> SELECT * FROM t1 WHERE c1 < 10;
+----+------+
| id | c1 |
+----+------+
| 1 | 4 |
+----+------+
我有时会从后面的查询中得到不同的结果,即使没有人执行任何插入而只执行更新?我的 MySQL 版本是 5.7.
SQL 标准表示幻读仅与并发 INSERT 相关,尽管 generate 这个词有点令人困惑。来自 ISO/IEC 9075:1992,数据库语言 SQL- 1992 年 7 月 30 日(第二次非正式审查草案):
P3 ("Phantom"): SQL-transaction T1 reads the set of rows N that satisfy some search condition. SQL-transaction T2 then executes SQL-statements that generate one or more rows that satisfy the search condition used by SQL-transaction T1. If SQL-transaction T1 then repeats the initial read with the same search condition, it obtains a different collection of rows.
据我所知,在使用 REPEATABLE READ 的事务中,不可能(不应该?)获得幻像行。
在可重复读锁中创建事务时,一旦事务中的第一个查询是 运行.
,mysql 就会创建数据的 "snapshot"
因此,任何 select 语句都将获取该快照中的数据。
据我所知,文档中的两个警告可能会导致意外结果:
- 在 事务中进行的任何读取查询都会影响未来的
SELECT
语句(这可能并不意外,但我想可能会引起混淆)。
- 从其他事务对数据库进行的其他写入查询可能会影响在当前[]中进行的写入查询=39=]交易。
第 2 点更令人困惑 - 请参阅 the note in the docs here 以获得更多解释。这也详细介绍了可重复读取隔离级别。
看起来像 InnoDB guards against phantom rows。
To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row locking with gap locking. InnoDB performs row-level locking in such a way that when it searches or scans a table index, it sets shared or exclusive locks on the index records it encounters. Thus, the row-level locks are actually index-record locks.
Gap locking can be disabled as discussed in Section 15.7.1, “InnoDB Locking”. This may cause phantom problems because other sessions can insert new rows into the gaps when gap locking is disabled.
我很想知道您的情况是否有不同的设置!链接的任何文档是否阐明了这一点?如果这是一个相当 "deep" mysql 的问题,也许 DBA 堆栈交换可能是一个更好的尝试。
InnoDB REPEATABLE-READ 事务隔离级别可防止幻像行,但前提是您的 SELECT 查询是非锁定查询。
因此您可以 SELECT 在一个事务中多次使用相同的查询条件,并且保证您一次又一次获得相同的结果,即使其他会话正在插入、更新或删除行以会影响您的结果集的方式。一旦开始新事务,您的查询就会看到同时发生的行更改。
但是 InnoDB 有一个奇怪的情况:如果你 运行 一个 locking read query 像以下之一:
SELECT * FROM t1 WHERE c1 < 10 FOR UPDATE
SELECT * FROM t1 WHERE c1 < 10 LOCK IN SHARE MODE
SELECT * FROM t1 WHERE c1 < 10 FOR SHARE -- MySQL 8.0 syntax
然后 SELECT 将 "see" 数据并发更改的结果,就好像您的事务已作为 READ-COMMITTED 事务启动一样。
您甚至可以在同一个 REPEATABLE-READ 事务中在锁定读取查询和非锁定读取查询之间来回切换,并且您会看到每个查询的不同结果集。因此,如果您使用锁定 SELECT 语句,请注意这一点。
我认为您显示的摘录中的 "generate" 一词适用于 INSERT 或 UPDATE。他们需要一个术语来适用于这两种情况,因为我猜他们不想写一个更清晰的短语,比如 "insert or update."
来自 MySQL 词汇表:
phantom: A row that appears in the result set of a query, but not in the result set of an earlier query. For example, if a query is run twice within a transaction, and in the meantime, another transaction commits after inserting a new row or updating a row so that it matches the WHERE clause of the query.
加粗部分正确吗?如果我有
CREATE TABLE t1 (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`c1` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
隔离级别是可重复读的,我也是
mysql> start transaction;
mysql> SELECT * FROM t1 WHERE c1 < 10;
+----+------+
| id | c1 |
+----+------+
| 1 | 4 |
+----+------+
mysql> SELECT * FROM t1 WHERE c1 < 10;
+----+------+
| id | c1 |
+----+------+
| 1 | 4 |
+----+------+
我有时会从后面的查询中得到不同的结果,即使没有人执行任何插入而只执行更新?我的 MySQL 版本是 5.7.
SQL 标准表示幻读仅与并发 INSERT 相关,尽管 generate 这个词有点令人困惑。来自 ISO/IEC 9075:1992,数据库语言 SQL- 1992 年 7 月 30 日(第二次非正式审查草案):
P3 ("Phantom"): SQL-transaction T1 reads the set of rows N that satisfy some search condition. SQL-transaction T2 then executes SQL-statements that generate one or more rows that satisfy the search condition used by SQL-transaction T1. If SQL-transaction T1 then repeats the initial read with the same search condition, it obtains a different collection of rows.
据我所知,在使用 REPEATABLE READ 的事务中,不可能(不应该?)获得幻像行。
在可重复读锁中创建事务时,一旦事务中的第一个查询是 运行.
,mysql 就会创建数据的 "snapshot"因此,任何 select 语句都将获取该快照中的数据。
据我所知,文档中的两个警告可能会导致意外结果:
- 在 事务中进行的任何读取查询都会影响未来的
SELECT
语句(这可能并不意外,但我想可能会引起混淆)。 - 从其他事务对数据库进行的其他写入查询可能会影响在当前[]中进行的写入查询=39=]交易。
第 2 点更令人困惑 - 请参阅 the note in the docs here 以获得更多解释。这也详细介绍了可重复读取隔离级别。
看起来像 InnoDB guards against phantom rows。
To prevent phantoms, InnoDB uses an algorithm called next-key locking that combines index-row locking with gap locking. InnoDB performs row-level locking in such a way that when it searches or scans a table index, it sets shared or exclusive locks on the index records it encounters. Thus, the row-level locks are actually index-record locks.
Gap locking can be disabled as discussed in Section 15.7.1, “InnoDB Locking”. This may cause phantom problems because other sessions can insert new rows into the gaps when gap locking is disabled.
我很想知道您的情况是否有不同的设置!链接的任何文档是否阐明了这一点?如果这是一个相当 "deep" mysql 的问题,也许 DBA 堆栈交换可能是一个更好的尝试。
InnoDB REPEATABLE-READ 事务隔离级别可防止幻像行,但前提是您的 SELECT 查询是非锁定查询。
因此您可以 SELECT 在一个事务中多次使用相同的查询条件,并且保证您一次又一次获得相同的结果,即使其他会话正在插入、更新或删除行以会影响您的结果集的方式。一旦开始新事务,您的查询就会看到同时发生的行更改。
但是 InnoDB 有一个奇怪的情况:如果你 运行 一个 locking read query 像以下之一:
SELECT * FROM t1 WHERE c1 < 10 FOR UPDATE
SELECT * FROM t1 WHERE c1 < 10 LOCK IN SHARE MODE
SELECT * FROM t1 WHERE c1 < 10 FOR SHARE -- MySQL 8.0 syntax
然后 SELECT 将 "see" 数据并发更改的结果,就好像您的事务已作为 READ-COMMITTED 事务启动一样。
您甚至可以在同一个 REPEATABLE-READ 事务中在锁定读取查询和非锁定读取查询之间来回切换,并且您会看到每个查询的不同结果集。因此,如果您使用锁定 SELECT 语句,请注意这一点。
我认为您显示的摘录中的 "generate" 一词适用于 INSERT 或 UPDATE。他们需要一个术语来适用于这两种情况,因为我猜他们不想写一个更清晰的短语,比如 "insert or update."