транзакции MySQL
Когда речь заходит о транзакциях, первое, что приходит на ум, это, конечно же, четыре характеристики транзакций: атомарность, непротиворечивость, изоляция и долговечность. Транзакции реализуются на уровне ядра, поэтому разные механизмы хранения могут иметь разные реализации для транзакций. Например, движок MySQL MyISAM не реализует транзакции, что является одной из причин, по которой он был заменен на InnoDB.
Четыре характеристики транзакций
Атомарность:Все операции транзакции либо корректно отражаются в базе данных, либо не отражаются вовсе.
последовательность:Данные в базе данных непротиворечивы до и после выполнения транзакции.
Изоляция:Когда несколько транзакций выполняются одновременно, для любой пары транзакций Ti и Tj, с точки зрения Ti, Tj либо завершает выполнение до Ti, либо начинает выполняться после завершения Ti. Таким образом, каждая транзакция не чувствует, что другие транзакции выполняются одновременно в системе.
Упорство:После успешного завершения транзакции ее изменения в базе данных должны быть постоянными, и данные не могут быть потеряны, даже если машина выйдет из строя сразу после фиксации транзакции.
Атомарность и долговечность транзакций легче понять, но согласованность более абстрактна. Для согласованности часто приводится пример перевода: когда А переводит деньги Б, сумма счетов А и Б до и после перевода одинакова. Этот пример на первый взгляд кажется очень понятным, но потом я думаю о том, может ли атомарность также достичь этой цели? Ответ таков: нет, атомарность может гарантировать, что вычет на счете А и увеличение на счете Б будут успешными или неудачными одновременно, но она не гарантирует, что сумма вычета на счете А будет равна сумме увеличения на счете В. Б. На самом деле, для достижения согласованности необходимо одновременное выполнение трех других условий.
Другая изоляция транзакций более сложна, потому что транзакции MySQL могут иметь несколько уровней изоляции, давайте посмотрим.
уровень изоляции транзакций
При одновременном выполнении нескольких транзакций могут иметь место грязные чтения, неповторяющиеся чтения и фантомные чтения.Для решения этих проблем вводятся разные уровни изоляции.
Грязное чтение:Когда транзакция A и транзакция B выполняются одновременно, транзакция B может прочитать незафиксированные данные транзакции A, и произойдет грязное чтение. Суть грязного чтения заключается в том, что транзакция B считывает незафиксированные данные транзакции A. Если транзакция A откатывается, данные, прочитанные транзакцией B, фактически недействительны. Как показано в следующем случае: Результат запроса транзакции B к значению равен 100, но поскольку транзакция A откатилась, значение value не обязательно равно 100.
Транзакция А | Транзакция Б |
---|---|
begin | begin |
update t set value = 100 | |
select value from t | |
rollback | |
commit | commit |
Неповторимое чтение:В транзакции многократный запрос одних и тех же данных приведет к разным результатам, что называется неповторяемым чтением. Как показано в следующем случае: результат транзакции B, запрашивающей значение дважды, несовместим.
Транзакция А | Транзакция Б |
---|---|
begin | begin |
update t set value = 100 | |
select value from t ( value = 100 ) | |
update t set value = 200 | |
select value from t ( value = 200 ) | |
commit | commit |
Фантомное чтение:Запрос диапазона выполняется в транзакции, и запрашивается определенное количество фрагментов данных, но в это время вставляются новые данные, в результате чего в базе данных появляется еще одна строка данных, которая фантомно считывается. Как показано в следующем случае: Количество строк данных, запрошенных транзакцией B, отличается.
Транзакция А | Транзакция Б |
---|---|
begin | begin |
select * from t | |
insert into t ... | |
commit | |
select * from t | |
commit |
Уровни изоляции транзакций MySQL включают в себя: незафиксированное чтение, зафиксированное чтение, повторяемое чтение и сериализуемое.
Незафиксированное чтение:Транзакция еще не зафиксирована, и ее обновления видны другим транзакциям. Это создает грязные чтения.
Чтение коммитов:После фиксации транзакции ее изменения не видны другим транзакциям. Чтение фиксации решает проблему грязных чтений.
Повторяемое чтение:В транзакции чтение одних и тех же данных несколько раз всегда дает один и тот же результат, даже если другие транзакции обновляют данные и успешно фиксируются. Повторяющиеся чтения решают проблему неповторяющихся чтений. Но есть еще галлюцинации. Механизм InnoDB решает проблему фантомного чтения с помощью управления параллельным выполнением нескольких версий (MVCC).
Сериализация:Последовательная связь — самый строгий уровень изоляции.Блокировки чтения добавляются к операциям чтения, а блокировки записи — к операциям записи в транзакции, поэтому может быть много сценариев конфликта блокировок.
Сверху вниз уровень изоляции становится все выше и выше, а эффективность соответственно будет снижаться.Для разных уровней изоляции нужно сделать разумный выбор согласно бизнес-сценарию.
Запрос и изменение уровня изоляции транзакции
Следующая команда может запросить глобальный уровень изоляции механизма InnoDB и уровень изоляции текущего сеанса.
mysql> select @@global.tx_isolation,@@tx_isolation;
+-----------------------+-----------------+
| @@global.tx_isolation | @@tx_isolation |
+-----------------------+-----------------+
| REPEATABLE-READ | REPEATABLE-READ |
+-----------------------+-----------------+
Способ установки уровня транзакции innodb:
set 作用域 transaction isolation level 事务隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
mysql> set global transaction isolation level read committed; // 设定全局的隔离级别为读提交
mysql> set session transaction isolation level read committed; // 设定当前会话的隔离级别为读提交
Как была запущена транзакция
-
В MySQL транзакцию можно запустить явно с помощью команды begin или start transaction. Отображает открытые транзакции, которые необходимо зафиксировать с помощью команды commit.
-
Если MySQL не отображает команду выполнения для запуска транзакции, MySQL также автоматически запускает транзакцию при выполнении первой команды. Если автофиксация включена, то автоматически открытые транзакции также будут автоматически зафиксированы. Затем, когда выполняется оператор выбора, MySQL сначала автоматически открывает транзакцию и автоматически фиксирует ее после выполнения оператора выбора. Следовательно, выполнение оператора в MySQL также является завершенной транзакцией.
-
Выполните команду set autocommit=0 в MySQL, чтобы отключить автоматическую фиксацию транзакции. Если автоматическая фиксация отключена, выполнение оператора select по-прежнему будет открывать транзакцию и не будет выполняться автофиксация после завершения выполнения.
-
Команды begin и start transaction не запускают транзакцию сразу после выполнения, а только при выполнении первого оператора. Запуск транзакции с последовательной командой моментального снимка запускает транзакцию сразу после выполнения.
Пример, иллюстрирующий влияние различных уровней изоляции
Затем мы используем случай, чтобы увидеть, как будут получены разные результаты при разных уровнях изоляции.
create table t (k int) ENGINE=InnoDB;
insert into t values (1);
Транзакция А | Транзакция Б |
---|---|
begin | |
1: select k from t | |
begin; update t set k = k + 1 | |
2: select k from t | |
commit | |
3: select k from t | |
commit | |
4: select k from t |
Когда уровень изоляции не зафиксирован, прочитайте: Для транзакции A результат первого оператора запроса равен 1, результат второго оператора запроса равен 2, а результаты третьего и четвертого операторов запроса также равны 2.
Когда уровень изоляции read commit: для транзакции A результат первого оператора запроса равен 1, результат второго оператора запроса равен 1, результат третьего оператора запроса равен 2, а результат четвертого оператора запроса тоже 2.
Когда уровень изоляции является повторяемым, прочитайте: Для транзакции A результаты первого, второго и третьего операторов запроса равны 1, а результат четвертого оператора запроса равен 2.
Когда уровень изоляции сериализуется: для транзакции A результат первого оператора запроса равен 1. В это время транзакция B будет заблокирована при выполнении оператора update, поскольку транзакция A добавила блокировку чтения для этих данных, а транзакция B должна добавить блокировку записи для обновления этих данных.Из-за конфликта между блокировкой чтения и блокировкой блокировка записи, только транзакция B. Перед обновлением можно подождать, пока транзакция A не зафиксирует снятие блокировки чтения. Следовательно, результаты 2-го и 3-го операторов запроса транзакции A также равны 1, а результат 4-го оператора запроса равен 2.
Реализация изоляции транзакций
Изоляция транзакций достигается за счет журнала отмены. Для одних и тех же данных InnoDB будет хранить несколько версий, а несколько версий реализуются через журнал журнала отмены. Текущее значение можно откатить в разное время, чтобы получить разные более низкие версии. , данные, которые представляют собой средство управления параллельным доступом к нескольким версиям базы данных (MVCC). Конечно, только журнала отмен недостаточно.Как транзакция Ti узнает, какую версию данных следует использовать, чтобы поддерживать два уровня изоляции: фиксированное чтение и повторяемое чтение? Подход InnoDB состоит в том, чтобы поддерживать непротиворечивое представление о реальности.
InnoDB поддерживает уникальный идентификатор транзакции для каждой транзакции, и идентификатор транзакции выделяется строго инкрементально, то есть идентификатор транзакции, открытой позже, должен быть больше, чем идентификатор транзакции, открытой первой. Поскольку через журнал отмены операций можно получить несколько версий данных, можно предположить, что в базе данных имеется несколько версий каждых данных. Когда каждая транзакция обновляет часть данных, создается новая версия данных, и в эту версию данных вставляется собственный идентификатор транзакции, чтобы идентифицировать версию данных.
Когда запускается новая транзакция, InnoDB поддерживает массив для каждой транзакции, в котором хранится идентификатор текущей активной транзакции.Так называемая активная транзакция относится к транзакции, которая была запущена, но еще не зафиксирована. Наименьший идентификатор транзакции в этом массиве называется минимальной отметкой, а наибольший идентификатор транзакции плюс 1 называется максимальной отметкой. Когда транзакция считывает часть данных, она начинается с самой старшей версии данных. Если она может быть прочитана, она берет данные. Если она не может их прочитать, она берет более раннюю версию данных и т. д. до тех пор, пока он не сможет быть эффективно прочитан.
При суждении, читать или нет, бывают только следующие ситуации:
-
Номер версии данных больше или равен верхнему уровню транзакции, что указывает на то, что он был создан последующей транзакцией и не может быть прочитан;
-
Если номер версии данных меньше или равен минимальному уровню воды, это означает, что транзакция была отправлена до того, как транзакция была открыта, или транзакция была изменена сама по себе и может быть прочитана;
-
Номер версии данных находится между высоким уровнем воды и низким уровнем воды.Если номер версии находится в массиве, это означает, что он не зафиксирован и не может быть прочитан.
-
Номер версии данных находится между высоким уровнем воды и низким уровнем воды.Если номер версии не находится в массиве, это означает, что он был отправлен и может быть прочитан.
Разница между чтением фиксации и повторным чтением заключается в том, что чтение фиксации обновляет массив перед выполнением инструкции каждый раз, так что отправленные данные не будут в массиве и будут видны.Повторяемое чтение всегда использует массив, сгенерированный при открытии транзакции. .
Моментальный снимок текущего чтения и чтения
Метод InnoDB создания уникального идентификатора транзакции для каждой транзакции называется созданием моментального снимка, поэтому этот сценарий называется чтением моментального снимка. Однако чтение моментального снимка нельзя использовать для обновления данных, поскольку чтение моментального снимка может перезаписать изменения других транзакций при обновлении данных. Кроме того, текущий метод чтения будет использоваться, если во время запроса применяется блокировка. Текущее чтение — это чтение последних представленных данных из этих данных. Многоверсионный контроль параллелизма InnoDB реализует блокировки без чтения на сериализованном уровне изоляции, улучшая производительность параллелизма.
Ниже приведен пример понимания чтения моментального снимка и текущего чтения:
Сначала создайте таблицу t и вставьте часть данных.
mysql-> create table t(k int)ENGINE=InnoDB;
mysql-> insert into t(k) values (1);
Затем установите уровень изоляции транзакции REPEATABLE-READ, затем откройте три транзакции и выполните их в следующем порядке.
Транзакция А | Транзакция Б | Транзакция С |
---|---|---|
start transaction with consistent snapshot | ||
start transaction with consistent snapshot | ||
select k fromt t; | ||
select k from t; | ||
update t set k = k + 1; | ||
update t set k = k + 1; | ||
select k from t; commit; | ||
select k from t; commit; |
Результат: результат двух чтений транзакцией A равен 1, результат первого чтения транзакции B равен 1, а результат второго чтения равен 3. Транзакция A — это моментальный снимок, считанный дважды с уровнем изоляции повторяемого чтения, поэтому результаты двух чтений одинаковы. Транзакция B представляет собой моментальный снимок, считанный в первый раз, но оператор обновления выполняет текущее чтение, чтобы обновить значение k до результата 2, зафиксированного транзакцией C, и добавить к нему 1, чтобы получить 3. При выполнении операции обновления будет создана новая версия данных, а в качестве номера версии данных будет использоваться собственный идентификатор транзакции, чтобы обновленные данные можно было прочитать в транзакции. Таким образом, результат последнего запроса транзакции B равен 3.
В последнее время я изучаю принципы MySQL, и я возьму на заметку в статье.
Ссылаться на
[1] Концепции системы баз данных (6-е издание)
[2] Курс MySQL по борьбе с 45 лекциями, Линь Сяобинь
[3] Высокая производительность MySQL (3RD Edition)
[4] Уровень изоляции транзакций Mysql и изменения уровня изоляции транзакций