17.7.2.1 Уровни изоляции транзакций
Изоляция транзакций является одним из фундаментов обработки баз данных. Изоляция — это I в аббревиатуре; уровень изоляции — это настройка, которая точно настраивает баланс между производительностью и надёжностью, согласованностью и воспроизводимостью результатов, когда несколько транзакций вносят изменения и выполняют запросы одновременно.
InnoDB предлагает все четыре уровня изоляции транзакций, описанные в стандарте SQL:1992: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ и SERIALIZABLE. По умолчанию для InnoDB установлен уровень изоляции REPEATABLE READ.
Пользователь может изменить уровень изоляции для одной сессии или для всех последующих подключений с помощью оператора SET
TRANSACTION. Для установки уровня изоляции по умолчанию для сервера для всех подключений используйте опцию --transaction-isolation в командной строке или файле настроек. Более подробную информацию об уровнях изоляции и синтаксисе установки уровней см. в разделе 15.3.7, «Оператор SET TRANSACTION».
InnoDB поддерживает каждый из описанных здесь уровней изоляции транзакций, используя различные стратегии. Вы можете обеспечить высокую степень согласованности с уровнем по умолчанию REPEATABLE READ, для операций с важными данными, где важна соответствие. Или вы можете ослабить правила согласованности с READ COMMITTED или даже READ UNCOMMITTED в ситуациях, таких как создание массовых отчётов, где точная согласованность и воспроизводимые результаты менее важны, чем минимизация накладных расходов на блокировку. SERIALIZABLE применяет ещё более строгие правила, чем REPEATABLE
READ, и используется в основном в специализированных ситуациях, например, с транзакциями и для устранения проблем с конкурентностью.
В следующем списке описывается, как MySQL поддерживает различные уровни транзакций. Список идёт от наиболее часто используемого уровня к наименее часто используемому.
-
REPEATABLE READЭто уровень изоляции по умолчанию для
InnoDB. В рамках одной транзакции чтение выполняется с использованием установленного первого чтения. Это означает, что если вы выполните несколько обычных (без блокировок)SELECTинструкций в рамках одной транзакции, этиSELECTинструкции будут согласованы и друг с другом. Смотрите Раздел 17.7.2.3, «Согласованные чтения без блокировок».Для (
SELECTсFOR UPDATEилиFOR SHARE),UPDATEиDELETEинструкций, блокировка зависит от того, использует ли инструкция уникальный индекс с уникальным условием поиска или условие поиска типа диапазона.Для уникального индекса с уникальным условием поиска,
InnoDBблокирует только найденную запись индекса, а не перед ней.Для других условий поиска,
InnoDBблокирует сканируемый диапазон индекса, используя или для блокирования вставок другими сессиями в промежутки, охватываемые диапазоном. Подробности о блокировках промежутков и блокировках смежных записей см. в Разделе 17.7.1, «Блокировка InnoDB».
Не рекомендуется смешивать инструкции с блокировкой (
UPDATE,INSERT,DELETEилиSELECT ... FOR ...) с инструкциями без блокировкиSELECTв одной транзакцииREPEATABLE READ, потому что, как правило, в таких случаях вам требуетсяSERIALIZABLE. Это связано с тем, что инструкция без блокировкиSELECTотображает состояние базы данных по состоянию на момент чтения, которое состоит из транзакций, завершенных до создания состояния чтения и до собственных записей текущей транзакции, в то время как инструкции с блокировкой используют последнее состояние базы данных для использования блокировки. В общем случае эти два различных состояния таблицы не согласованы между собой и сложны для анализа. -
READ COMMITTEDКаждое согласованное чтение, даже в рамках одной транзакции, создаёт и считывает свой свежий снимок. Дополнительная информация о согласованных чтениях доступна в Разделе 17.7.2.3, «Согласованные чтения без блокировок».
Для чтений с блокировкой (
SELECTсFOR UPDATEилиFOR SHARE),UPDATEинструкций иDELETEинструкций,InnoDBблокирует только записи индекса, а не промежутки перед ними, что позволяет свободно вставлять новые записи рядом с заблокированными записями. Блокировка промежутков используется только для проверки ограничений внешнего ключа и проверки уникальности ключей.Поскольку блокировка промежутков отключена, могут возникнуть проблемы с фантомными строками, поскольку другие сессии могут вставлять новые строки в промежутки. Дополнительную информацию о фантомных строках см. в Разделе 17.7.4, «Фантомные строки».
Поддерживается только протоколирование строк с бинарным логом в режиме изоляции
READ COMMITTED. Если вы используетеREAD COMMITTEDсbinlog_format=MIXED, сервер автоматически использует протоколирование строк.Использование
READ COMMITTEDимеет дополнительные эффекты:Для
UPDATEилиDELETEинструкций,InnoDBудерживает блокировки только для строк, которые он обновляет или удаляет. Блокировки записей для несовпадающих строк снимаются после того, как MySQL оценил условиеWHERE. Это значительно уменьшает вероятность тупиковых ситуаций, но они всё же могут возникнуть.Для
UPDATEинструкций, если строка уже заблокирована,InnoDBвыполняет “полусогласованное” чтение, возвращая последнюю подтвержденную версию MySQL, чтобы MySQL мог определить, соответствует ли строка условиюWHEREинструкцииUPDATE. Если строка соответствует (должна быть обновлена), MySQL повторно считывает строку, и на этот разInnoDBлибо блокирует её, либо ожидает блокировки.
Рассмотрим таблицу, созданную и заполненную следующим образом:
CREATE TABLE t (a INT NOT NULL, b INT) ENGINE = InnoDB; INSERT INTO t VALUES (1,2),(2,3),(3,2),(4,3),(5,2); COMMIT;
В этом случае таблица не имеет индексов, поэтому поиск и сканирование индексов используют скрытый кластеризованный индекс для блокировки записей (см. Раздел 17.6.2.1, «Кластеризованные и вторичные индексы») вместо индексированных столбцов.
Предположим, что одна сессия выполняет обновление
UPDATEс помощью следующих инструкций:# Session A START TRANSACTION; UPDATE t SET b = 5 WHERE b = 3;
Предположим также, что вторая сессия выполняет обновление
UPDATEс помощью следующих инструкций после инструкций первой сессии:# Session B UPDATE t SET b = 4 WHERE b = 2;
По мере выполнения
InnoDBкаждойUPDATE, он сначала приобретает эксклюзивную блокировку для каждой строки, а затем определяет, нужно ли её изменять. ЕслиInnoDBне изменяет строку, он снимает блокировку. В противном случаеInnoDBсохраняет блокировку до конца транзакции. Это влияет на обработку транзакций следующим образом.При использовании уровня изоляции по умолчанию
REPEATABLE READ, перваяUPDATEприобретает блокировку x для каждой строки, которую он считывает и не снимает ни одну из них:x-lock(1,2); retain x-lock x-lock(2,3); update(2,3) to (2,5); retain x-lock x-lock(3,2); retain x-lock x-lock(4,3); update(4,3) to (4,5); retain x-lock x-lock(5,2); retain x-lock
Вторая
UPDATEблокируется, как только пытается приобрести какие-либо блокировки (потому что первое обновление сохранило блокировки на всех строках), и не продолжает работу до тех пор, пока первоеUPDATEне подтвердит или не откатит:x-lock(1,2); block and wait for first UPDATE to commit or roll back
Если используется
READ COMMITTED, перваяUPDATEприобретает блокировку x для каждой строки, которую он считывает, и снимает эти блокировки для строк, которые он не изменяет:x-lock(1,2); unlock(1,2) x-lock(2,3); update(2,3) to (2,5); retain x-lock x-lock(3,2); unlock(3,2) x-lock(4,3); update(4,3) to (4,5); retain x-lock x-lock(5,2); unlock(5,2)
Для второй
UPDATE,InnoDBвыполняет “полусогласованное” чтение, возвращая последнюю подтвержденную версию каждой строки, которую он считывает MySQL, чтобы MySQL мог определить, соответствует ли строка условиюWHEREUPDATE:x-lock(1,2); update(1,2) to (1,4); retain x-lock x-lock(2,3); unlock(2,3) x-lock(3,2); update(3,2) to (3,4); retain x-lock x-lock(4,3); unlock(4,3) x-lock(5,2); update(5,2) to (5,4); retain x-lock
Однако, если условие
WHEREвключает индексированный столбец, иInnoDBиспользует индекс, при получении и сохранении блокировок записей учитывается только индексированный столбец. В приведенном ниже примере первое обновлениеUPDATEполучает и сохраняет блокировку x для каждой строки, где b = 2. Второе обновлениеUPDATEблокируется при попытке получить блокировки x для тех же записей, поскольку оно также использует индекс, определенный для столбца b.CREATE TABLE t (a INT NOT NULL, b INT, c INT, INDEX (b)) ENGINE = InnoDB; INSERT INTO t VALUES (1,2,3),(2,2,4); COMMIT; # Session A START TRANSACTION; UPDATE t SET b = 3 WHERE b = 2 AND c = 3; # Session B UPDATE t SET b = 4 WHERE b = 2 AND c = 4;
Уровень изоляции
READ COMMITTEDможет быть задан при запуске или изменён во время работы. Во время работы он может быть установлен глобально для всех сессий или индивидуально для каждой сессии. -
READ UNCOMMITTEDИнструкции
SELECTвыполняются без блокировки, но может быть использована возможная более ранняя версия строки. Таким образом, используя этот уровень изоляции, такие чтения не согласованы. Это также называется . В противном случае этот уровень изоляции работает какREAD COMMITTED.
-
SERIALIZABLEЭтот уровень похож на
REPEATABLE READ, ноInnoDBнеявным образом преобразует все обычныеSELECTзапросы вSELECT ... FOR SHARE, еслиautocommitотключен. Еслиautocommitвключён, тоSELECTявляется собственной транзакцией. Следовательно, она известна как только для чтения и может быть сериализована, если выполняется как согласованное (без блокировок) чтение, и не должна блокироваться другими транзакциями. (Чтобы заставить обычныйSELECTзаблокироваться, если другие транзакции изменили выбранные строки, отключитеautocommit.)Операции DML, которые считывают данные из таблиц MySQL (через список соединений или подзапрос), но не изменяют их, не приобретают блокировки чтения на таблицах MySQL, независимо от уровня изоляции. Более подробную информацию можно найти в разделе Совместимость таблиц разрешений.
© 2025 Oracle
Licensed under the GPLv2 License.