14.7.2.1 Уровни изоляции транзакций
Изоляция транзакций является одним из фундаментов обработки данных в базе данных. Изоляция — это буква «И» в аббревиатуре; уровень изоляции — это настройка, которая точно настраивает баланс между производительностью и надёжностью, согласованностью и воспроизводимостью результатов, когда несколько транзакций производят изменения и выполняют запросы одновременно.
InnoDB предлагает все четыре уровня изоляции транзакций, описанные в стандарте SQL:1992: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ и SERIALIZABLE. По умолчанию уровень изоляции для InnoDB — REPEATABLE READ.
Пользователь может изменить уровень изоляции для отдельной сессии или для всех последующих подключений с помощью оператора SET
TRANSACTION. Чтобы установить уровень изоляции по умолчанию для сервера для всех подключений, используйте опцию --transaction-isolation в командной строке или в файле конфигурации. Для получения подробной информации об уровнях изоляции и синтаксисе установки уровней см. Раздел 13.3.6, «Оператор SET TRANSACTION».
InnoDB поддерживает каждый из описанных здесь уровней изоляции транзакций, используя различные стратегии. Вы можете обеспечить высокую степень согласованности с уровнем по умолчанию REPEATABLE READ для операций с важными данными, где важна согласованность. Или вы можете ослабить правила согласованности с READ COMMITTED или даже READ UNCOMMITTED в ситуациях, таких как генерация отчетов, где точная согласованность и повторяемость результатов менее важны, чем минимизация накладных расходов на блокировку. SERIALIZABLE применяет ещё более строгие правила, чем REPEATABLE
READ, и используется в основном в специализированных ситуациях, например, при транзакциях и для устранения проблем с конкурентностью.
В следующем списке описывается, как MySQL поддерживает различные уровни транзакций. Список идет от наиболее часто используемого уровня к наименее часто используемому.
-
REPEATABLE READЭто уровень изоляции по умолчанию для
InnoDB. В рамках одной транзакции чтение будет соответствовать состоянию, установленного первым чтением. Это означает, что если вы выполните несколько обычных (без блокировок)SELECTоператоров в рамках одной транзакции, этиSELECTоператоры будут согласованы также и друг с другом. Смотрите Раздел 14.7.2.3, «Согласованные чтения без блокировок».Для (
SELECTсFOR UPDATEилиLOCK IN SHARE MODE),UPDATEиDELETEоператоров, блокировка зависит от того, использует ли оператор уникальный индекс с уникальным условием поиска или условием поиска типа диапазона.Для уникального индекса с уникальным условием поиска,
InnoDBблокирует только найденную запись индекса, а не предшествующую ей.Для других условий поиска,
InnoDBблокирует диапазон индекса, просканированный, используя или для блокировки вставок другими сеансами в пробелы, охватываемые диапазоном. Сведения о блокировках пробелов и блокировках следующей записи см. в Разделе 14.7.1, «Блокировка InnoDB».
Не рекомендуется смешивать операторы с блокировкой (
UPDATE,INSERT,DELETEилиSELECT ... FOR ...) с операторами без блокировкиSELECTв одной транзакции уровня изоляцииREPEATABLE READ, поскольку обычно в таких случаях вам требуетсяSERIALIZABLE. Это связано с тем, что оператор без блокировкиSELECTпредставляет состояние базы данных из точки зрения чтения, которое состоит из транзакций, завершенных до создания точки зрения чтения и до собственных записей текущей транзакции, в то время как операторы с блокировкой видят и изменяют наиболее последнее состояние базы данных для использования блокировок. В целом, эти два различных состояния таблиц несовместимы и трудно интерпретируются. -
READ COMMITTEDКаждое согласованное чтение, даже в рамках одной транзакции, устанавливает и считывает свою собственную свежую моментальную копию. Дополнительную информацию о согласованных чтениях см. в Разделе 14.7.2.3, «Согласованные чтения без блокировок».
Для операций чтения с блокировкой (
SELECTсFOR UPDATEилиLOCK IN SHARE MODE),UPDATEиDELETEоператоров,InnoDBблокирует только записи индекса, а не пробелы перед ними, и, следовательно, разрешает свободную вставку новых записей рядом с заблокированными записями. Блокировка пробелов используется только для проверки ограничений внешнего ключа и проверки дублирующихся ключей.Поскольку блокировка пробелов отключена, могут возникнуть проблемы с фиктивными строками, поскольку другие сеансы могут вставить новые строки в пробелы. Сведения о фиктивных строках см. в Разделе 14.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;
В этом случае таблица не имеет индексов, поэтому для поиска и сканирования индекса используется скрытый кластеризованный индекс для блокировки записей (см. Раздел 14.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 сохранил блокировки на всех строках), и не продолжает работу, пока первый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 мог определить, соответствует ли строка условиюWHEREоператораUPDATE: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такие же, как включение устаревшей переменнойinnodb_locks_unsafe_for_binlog, за исключением следующих пунктов:Включение
innodb_locks_unsafe_for_binlog— это глобальная настройка, влияющая на все сеансы, в то время как уровень изоляции может быть настроен глобально для всех сеансов или индивидуально для каждого сеанса.innodb_locks_unsafe_for_binlogможет быть установлен только при запуске сервера, в то время как уровень изоляции может быть установлен при запуске или изменён во время работы.
READ COMMITTEDпоэтому обеспечивает более точный и гибкий контроль, чемinnodb_locks_unsafe_for_binlog. -
READ UNCOMMITTEDОператоры
SELECTвыполняются без блокировок, но может использоваться возможная более ранняя версия строки. Таким образом, при использовании этого уровня изоляции такие чтения не согласованы. Это также называется . В противном случае этот уровень изоляции работает какREAD COMMITTED.
-
SERIALIZABLEЭтот уровень похож на
REPEATABLE READ, ноInnoDBнеявно преобразует все обычныеSELECTоператоры вSELECT ... LOCK IN SHARE MODE, еслиautocommitотключено. Еслиautocommitвключено, тоSELECTявляется своей собственной транзакцией. Поэтому она известна как только для чтения и может быть сериализована, если выполняется как согласованное (без блокировок) чтение, и не должна блокироваться другими транзакциями. (Чтобы заставить обычныйSELECTблокироваться, если другие транзакции изменили выбранные строки, отключитеautocommit.)
© 2025 Oracle
Licensed under the GPLv2 License.