14.7.2.3 Согласованные чтения без блокировок
Это означает, что InnoDB использует многоверсионность для предоставления запросу моментального снимка базы данных на определенный момент времени. Запрос видит изменения, внесенные транзакциями, которые были завершены до этого момента, и не видит изменений, внесенных более поздними или незавершенными транзакциями. Исключением из этого правила является то, что запрос видит изменения, внесенные предыдущими операторами в рамках той же транзакции. Это исключение приводит к следующей аномалии: если вы обновляете некоторые строки в таблице, то SELECT увидит последнюю версию обновлённых строк, но также может увидеть более старые версии любых других строк. Если другие сеансы одновременно обновляют ту же таблицу, аномалия означает, что вы можете увидеть таблицу в состоянии, которое никогда не существовало в базе данных.
Если транзакция использует изоляцию уровня REPEATABLE READ (по умолчанию), все согласованные чтения в рамках одной транзакции считывают снимок, созданный первым таким чтением в этой транзакции. Вы можете получить более свежий снимок для своих запросов, завершив текущую транзакцию и после этого выполнив новые запросы.
При уровне изоляции READ COMMITTED, каждое согласованное чтение в рамках транзакции устанавливает и считывает свой собственный свежий снимок.
Согласованное чтение является режимом по умолчанию, в котором InnoDB обрабатывает SELECT операторы в уровнях изоляции READ COMMITTED и REPEATABLE READ. Согласованное чтение не устанавливает никаких блокировок на таблицах, к которым оно обращается, поэтому другие сеансы могут свободно изменять эти таблицы одновременно с выполнением согласованного чтения таблицы.
Предположим, что вы работаете в режиме изоляции по умолчанию REPEATABLE READ. Когда вы выполняете согласованное чтение (то есть обычный SELECT оператор), InnoDB присваивает вашей транзакции временную метку, согласно которой ваш запрос видит базу данных. Если другая транзакция удаляет строку и завершает её после того, как вашей транзакции была присвоена метка, вы не увидите, что строка была удалена. Вставки и обновления обрабатываются аналогично.
Моментальный снимок состояния базы данных относится к SELECT операторам в рамках транзакции, а не обязательно к другим операторам. Если вы вставляете или изменяете некоторые строки, а затем завершаете эту транзакцию, DELETE или UPDATE оператор, выпущенный из другой параллельной REPEATABLE READ транзакции, может повлиять на эти только что завершенные строки, даже если сеанс не может их запросить. Если транзакция обновляет или удаляет строки, завершённые другой транзакцией, эти изменения становятся видимыми для текущей транзакции. Например, вы можете столкнуться со следующей ситуацией:
SELECT COUNT(c1) FROM t1 WHERE c1 = 'xyz';
-- Returns 0: no rows match.
DELETE FROM t1 WHERE c1 = 'xyz';
-- Deletes several rows recently committed by other transaction.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'abc';
-- Returns 0: no rows match.
UPDATE t1 SET c2 = 'cba' WHERE c2 = 'abc';
-- Affects 10 rows: another txn just committed 10 rows with 'abc' values.
SELECT COUNT(c2) FROM t1 WHERE c2 = 'cba';
-- Returns 10: this txn can now see the rows it just updated.
Вы можете переместить свою временную метку, завершив свою транзакцию, а затем выполнив другой SELECT или START TRANSACTION WITH
CONSISTENT SNAPSHOT.
Это называется многоверсионным управлением одновременностью.
В следующем примере сеанс A видит строку, вставленную сеансом B, только когда B завершил вставку, а A также завершил свою операцию, так что временная метка A переместилась за завершение B.
Session A Session B
SET autocommit=0; SET autocommit=0;
time
| SELECT * FROM t;
| empty set
| INSERT INTO t VALUES (1, 2);
|
v SELECT * FROM t;
empty set
COMMIT;
SELECT * FROM t;
empty set
COMMIT;
SELECT * FROM t;
---------------------
| 1 | 2 |
---------------------
Если вы хотите увидеть “самое свежее” состояние базы данных, используйте уровень изоляции READ
COMMITTED или:
SELECT * FROM t LOCK IN SHARE MODE;
При уровне изоляции READ COMMITTED, каждое согласованное чтение в рамках транзакции устанавливает и считывает свой собственный свежий снимок. При LOCK IN SHARE
MODE происходит блокирующее чтение: A SELECT блокируется до завершения транзакции, содержащей самые свежие строки (см. Раздел 14.7.2.4, «Блокирующие чтения»).
Согласованное чтение не работает с определенными операторами DDL:
Согласованное чтение не работает с
DROP TABLE, потому что MySQL не может использовать таблицу, которая была удалена, иInnoDBуничтожает таблицу.Согласованное чтение не работает с операциями
ALTER TABLE, которые создают временную копию исходной таблицы и удаляют исходную таблицу при создании временной копии. При повторном выполнении согласованного чтения в рамках транзакции строки в новой таблице не видны, потому что эти строки не существовали, когда был создан снимок транзакции. В этом случае транзакция возвращает ошибку: , “Определение таблицы изменилось, пожалуйста, повторите транзакцию”.
Тип чтения меняется для запросов в предложениях, таких как INSERT INTO ...
SELECT, UPDATE
... (SELECT) и CREATE TABLE ...
SELECT, которые не указывают FOR
UPDATE или LOCK IN SHARE MODE:
По умолчанию,
InnoDBиспользует более сильные блокировки в этих операторах, и частьSELECTведет себя какREAD COMMITTED, где каждое согласованное чтение, даже в рамках одной транзакции, устанавливает и считывает свой собственный свежий снимок.Чтобы выполнить чтение без блокировки в таких случаях, включите параметр
innodb_locks_unsafe_for_binlogи установите уровень изоляции транзакции наREAD UNCOMMITTED,READ COMMITTEDилиREPEATABLE READ, чтобы избежать установки блокировок на строки, считанные из выбранной таблицы.
© 2025 Oracle
Licensed under the GPLv2 License.