В прежнем понимании концепции транзакций базы данных было много несовершенств.Сегодня я буду использовать простой пример для объяснения концепций транзакций базы данных и уровней изоляции, что также удобно для обзора прошлого и изучения нового в будущем.
1. Что такое транзакция
Транзакция является базовой единицей управления параллелизмом. Так называемая транзакция, это последовательность операций, эти операции либо выполняются, либо не выполняются, это неделимая единица работы. Например, работает банковский перевод: дебетование одной учетной записи и добавление другой учетной записи, либо оба действия, либо ни то, ни другое. Поэтому их следует рассматривать как одну транзакцию. Транзакция — это единица, с помощью которой база данных поддерживает согласованность данных.В конце каждой транзакции согласованность данных может поддерживаться.
Давайте возьмем в качестве примера работу с базой данных Msql, а затем подробнее объясним транзакцию с базой данных:
Во-первых, мы используем следующую команду для просмотра уровня изоляции транзакций сеанса Mysql.Мы подробно представим уровень изоляции транзакций и его функции в следующих главах.Здесь, если вы просто знаете, что база данных может устанавливать разные транзакции уровни изоляции и различные уровни изоляции Это может по-разному влиять на работу транзакции. Используйте следующую команду, чтобы запросить уровень изоляции транзакций текущего сеанса Mysql.Вы можете видеть, что уровень изоляции транзакций Mysql по умолчанию — REPEATABLE-READ.
mysql> select @@tx_isolation;
+-----------------+
| @@tx_isolation |
+-----------------+
| REPEATABLE-READ |
+-----------------+
Чтобы объяснить транзакцию на примере, мы создали следующую таблицу банковских данных и вставили часть данных,
mysql> describe bank;
+---------+---------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+---------+---------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(40) | NO | | NULL | |
| balance | decimal(10,2) | YES | | NULL | |
+---------+---------------+------+-----+---------+----------------+
mysql> select * from bank;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| 3 | fufu | 2000.00 |
+----+------+---------+
Используйте команду запуска транзакции, чтобы запустить транзакцию базы данных,
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
Обновите значение баланса строки с идентификатором 3 до 3000,00,
mysql> update bank set balance = 3000 where id = 3;
Query OK, 1 row affected (0.09 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from bank;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| 3 | fufu | 3000.00 |
+----+------+---------+
1 row in set (0.00 sec)
На данный момент мы видим, что значение баланса строки с идентификатором 3, запрошенное оператором select, было изменено на 3000, 00. Далее мы попытаемся вставить новый фрагмент данных.
mysql> insert into bank (name, balance) values ('melo', 1000);
Query OK, 1 row affected (0.06 sec)
mysql> select * from bank;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| 3 | fufu | 3000.00 |
| 4 | melo | 1000.00 |
+----+------+---------+
2 rows in set (0.00 sec)
Поскольку вышеуказанные операции обновления и вставки выполняются после того, как команда запуска транзакции открывает транзакцию, эти операции принадлежат одной и той же транзакции до конца транзакции Предположим, у нас есть ошибка во время операции вставки, мы можем знать из определения транзакции что они принадлежат одной и той же транзакции.Все операции транзакции либо выполняются, либо не выполняются, мы можем проверить это, используя команду отката для имитации неудачного отката транзакции,
mysql> rollback;
Query OK, 0 rows affected (0.01 sec)
В этот момент, когда мы запрашиваем все данные в базе данных, мы обнаруживаем, что данные восстановлены в состояние до выполнения команды обновления, а значение баланса строки с id 3, равным 2000, не изменилось.
mysql> select * from bank;
+----+------+---------+
| id | name | balance |
+----+------+---------+
| 3 | fufu | 2000.00 |
+----+------+---------+
1 row in set (0.00 sec)
До сих пор мы объяснили определение транзакции базы данных и объяснили режим работы транзакции с помощью простой операции Mysql.Мы можем обобщить жизненный цикл транзакции базы данных следующим образом:
- граница начала транзакции
- Обычная конечная граница транзакции (COMMIT) фиксирует транзакцию и постоянно сохраняет состояние базы данных, обновленное транзакцией.
- Аномальная конечная граница транзакции (ROLLBACK): транзакция отменяется, и база данных возвращается в исходное состояние до выполнения транзакции.
Теперь давайте вернемся и подумаем о приведенном выше примере. Все операции в этом примере выполняются в сеансе Mysql, то есть другие пользователи не подключаются к базе данных одновременно для работы. В этом сценарии использования без одновременных сеансов независимо от того, является ли транзакция нормальным или ненормальным завершением, это не окажет никакого влияния на чтение данных отдельным пользователем, поскольку все его операции являются последовательными. Однако в реальном сценарии приложения база данных постоянно обслуживает множество сеансов. Предположим, что транзакция пользователя A начинает обновлять данные базы данных. В это время пользователь B начинает читать данные, а пользователь B будет читать новые данные. ценность. Однако если транзакция А выдает ошибку при выполнении следующего оператора SQL и откатывает транзакцию А, данные, считанные пользователем Б, являются неверными и недействительными данными. Это всего лишь простая проблема, которая возникает из-за транзакций базы данных в параллельной среде, поэтому далее будут подробно рассмотрены проблемы, возникающие из-за параллельных транзакций.
2. Проблемы, вызванные одновременными транзакциями
В этом разделе мы в основном объясняем проблемы, которые могут возникнуть в параллельных транзакциях, используя в качестве примеров моменты времени и таблицы операций транзакций.
2.1 Потерянные обновления
2.1.1 Потерянные обновления типа 1
Определение: когда транзакция A отзывается, обновленные данные транзакции B, которые были отправлены, перезаписываются.
момент времени | Транзакция А | Транзакция Б |
---|---|---|
T1 | начать транзакцию | |
T2 | начать транзакцию | |
T3 | Баланс счета запроса составляет 1000 юаней. | |
T4 | Баланс счета запроса составляет 1000 юаней. | |
T5 | Внесите 100 юаней, чтобы изменить баланс на 1100 юаней | |
T6 | совершить транзакцию | |
T7 | Выньте 100 юаней и измените баланс на 900 юаней. | |
T8 | отменить транзакцию | |
T9 | Баланс восстановлен до 1000 юаней (утеряно обновление) |
Приведенный выше пример демонстрирует первый тип проблемы потери обновлений.Хотя транзакция B завершается успешно, сделанные ею обновления не сохраняются постоянно.Эта проблема параллелизма вызвана полным отсутствием изолированных транзакций. Когда две транзакции обновляют одни и те же данные, если одна транзакция фиксируется, а другая отзывается, обновления, сделанные первой транзакцией, также отменяются. (Это то, чего полностью избегают) Время начала и время окончания транзакции A включают время начала и окончания транзакции B. Когда транзакция A откатывает транзакцию, она также откатывает зафиксированную транзакцию B, что избегается. , который является первым типом отсутствующих обновлений.
2.1.2 Второй тип потерянного обновления
Определение. Когда транзакция A фиксируется, обновленные данные отправленной транзакции B перезаписываются.
момент времени | Транзакция А | Транзакция Б |
---|---|---|
T1 | начать транзакцию | |
T2 | начать транзакцию | |
T3 | Баланс счета запроса составляет 1000 юаней. | |
T4 | Баланс счета запроса составляет 1000 юаней. | |
T5 | Выньте 100 юаней и измените баланс на 900 юаней. | |
T6 | совершить транзакцию | |
T7 | Внесите 100 юаней, чтобы изменить баланс на 1100 | |
T8 | совершить транзакцию | |
T9 | Баланс восстановлен до 1100 юаней (утеряно обновление) |
Разница между вторым типом потерянного обновления и первым типом фактически заключается в том, вызвано ли влияние на данные отзывом или отправкой транзакции A. По сути, это тот же тип проблемы параллелизма, что и неповторяющееся чтение (представленное ниже), который обычно рассматривается как Do, является частным случаем неповторяющихся чтений. Две или более транзакций запрашивают одни и те же данные. Затем все они обновляют данные на основе результатов своих собственных запросов. В это время последняя отправленная транзакция обновления перезапишет другие отправленные транзакции обновления.
2.2 Грязные чтения
Определение: чтение незафиксированных данных обновления
момент времени | Транзакция А | Транзакция Б |
---|---|---|
T1 | начать транзакцию | |
T2 | начать транзакцию | |
T3 | Баланс счета запроса составляет 1000 юаней. | |
T4 | Снять 500 юаней и изменить баланс на 500 юаней | |
T5 | Баланс счета запроса 500 юаней (грязное чтение) | |
T6 | отменить транзакцию, баланс восстановлен до 1000 юаней | |
T7 | Внесите 100 юаней, чтобы изменить баланс на 600 юаней | |
T8 | совершить транзакцию |
Транзакция a queries a a queries Неподвижные данные обновления транзакции B и транзакции A продолжают выполнять соответствующие операции на основе результата запроса. Но затем транзакция B отзывает обновление, которое приведет к тому, что транзакция A для эксплуатации грязных данных. В приведенном выше примере грязное чтение происходит во время T5, что в конечном итоге приводит к неправильному балансу учетной записи при совершении транзакции A. Некоторые люди могут иметь сомнения Транзакция B не была совершена или отозвана, почему транзакция может прочитать измененные данные в T5? Что нужно сказать, что здесь данные в таблице данных изменяются в режиме реального времени, и транзакция контролирует только финал Состояние данных, то есть, если без правильного уровня изоляции после завершения операции обновления операции заканчивается, другие транзакции уже могут прочитать измененное значение данных, даже если транзакция не завершена.
Пока: все базы данных избегают грязных чтений, вы можете использовать два сеанса Mysql для проверки вышеуказанных операций.При уровне изоляции по умолчанию (REPEATABLE-READ) баланс, прочитанный транзакцией A во время T5, составляет 1000 юаней, а не 500 юаней.
2.3 Неповторяемое чтение
Определение: чтение данных, которые были обновлены, но два идентичных запроса в транзакции возвращают разные данные.
момент времени | Транзакция А | Транзакция Б |
---|---|---|
T1 | начать транзакцию | |
T2 | начать транзакцию | |
T3 | Баланс счета запроса составляет 1000 юаней. | |
T4 | Баланс счета запроса составляет 1000 юаней. | |
T5 | Выньте 100 юаней и измените баланс на 900 юаней. | |
T6 | совершить транзакцию | |
T7 | Баланс учетной записи запроса составляет 900 юаней (не соответствует счету, прочитанному T4, и не может быть прочитан повторно) |
2.4 Фантомное чтение
Определение: чтение зафиксированных вставленных данных, фантомное чтение аналогично неповторяемому чтению, фантомное чтение — запросить вновь вставленные данные, которые были зафиксированы другой транзакцией, а неповторяемое чтение — запросить обновленные данные, которые были зафиксированы другой транзакцией. другая транзакция.
момент времени | Транзакция А | Транзакция Б |
---|---|---|
T1 | начать транзакцию | |
T2 | начать транзакцию | |
T3 | По статистике общее количество депозитов пользователя Z составляет 1000 юаней. | |
T4 | Добавьте депозитный счет Z, внесите 100 юаней | |
T5 | совершить транзакцию | |
T6 | ||
T7 | Снова подсчитайте общие депозиты пользователя Z, чтобы они составили 1100 юаней (несовместимо с тем, что было прочитано T4, фантомное чтение) |
Когда транзакция A была запрошена в первый раз, проблем не возникло, но новые вставленные данные, отправленные транзакцией B, были обнаружены во втором запросе, что привело к различным результатам двух запросов.
Разница между неповторяемым чтением и фантомным чтением:Проще говоря, неповторяющиеся чтения вызываются модификацией данных, а фантомные чтения — вставкой или удалением данных.
Он не очень читается, относится к двум идентичным запросам в диапазоне транзакций в базе данных доступа, возвращает разные данные. Это вызвано другими модификациями транзакции в системе при запросе. Например, транзакция T1 считывает определенные данные, транзакция T2 читает и изменяет данные, T1 - это разные результаты, чтобы снова прочитать данные, чтобы проверить значение чтения.
Еще легко понять: в одном бизнесе прочитайте те же данные несколько раз. Когда эта транзакция не закончилась, другая транзакция также доступна одинаковых данных. Затем между двумя чтениями данных первой транзакции. Из-за модификации второй транзакции данные, прочитанные первой транзакцией, могут быть не одинаковыми, так что данные, прочитанные дважды в транзакции, отличаются, так что это называется не повторяется, то есть оригинал прочитал его без повторения.
Так называемое фантомное чтение означает, что транзакция А читает несколько строк, соответствующих условиям поиска. Транзакция B изменяет набор результатов транзакции A, вставляя или удаляя строки и т. д., а затем фиксирует.
Фантомное чтение относится к явлению, которое возникает, когда транзакции не выполняются независимо друг от друга. Например, первая транзакция изменяет данные в таблице. Например, это изменение затрагивает «все строки данных» в таблице. В то же время вторая транзакция также изменяет данные в этой таблице, вставляя в таблицу «новую строку данных». Тогда в дальнейшем пользователь, оперирующий первой транзакцией, обнаружит, что в таблице нет измененных строк данных, как будто произошла галлюцинация.Общее решение галлюцинации — увеличить диапазон блокировки RangeS, а блокировку диапазон обнаружения только считывается, чтобы избежать фантомных чтений.
3. Уровень изоляции транзакций
Выше перечислены пять основных проблем, вызванных одновременными транзакциями базы данных. В итоге две из них связаны с проблемами обновления и три — с проблемами чтения. Как база данных избегает этой проблемы параллельных транзакций? Ответ заключается в разных уровнях изоляции транзакций.При разных уровнях изоляции результаты чтения данных параллельными транзакциями различны.Например, как описано в разделе «Грязное чтение», если он находится на уровне изоляции ПОВТОРЯЕМОЕ-ЧТЕНИЕ, транзакция находится в состоянии Чтение в T5 не может прочитать незафиксированные данные транзакции B. Нам необходимо установить различные уровни изоляции в соответствии с требованиями бизнеса, чтобы найти баланс между эффективностью и безопасностью данных.
Стандарт SQL определяет четыре типа уровней изоляции, включая некоторые специальные правила, ограничивающие, какие изменения внутри и вне транзакции видны, а какие невидимы. Низкоуровневые уровни изоляции обычно поддерживают более высокую параллельную обработку и имеют меньшую нагрузку на систему.
3.1 SERIALIZABLE (сериализация)
Когда система базы данных использует уровень изоляции SERIALIZABLE, транзакция не может видеть обновления, сделанные в базе данных другими транзакциями во время выполнения. Когда две транзакции работают с одними и теми же данными в базе данных одновременно, если первая транзакция уже обращается к данным, вторая транзакция может только остановиться и ждать, и должна ждать, пока первая транзакция не завершится, прежде чем она сможет возобновить работу. Таким образом, две транзакции фактически выполняются последовательно.
3.2 ПОВТОРЯЕМОЕ ЧТЕНИЕ
Когда система базы данных использует уровень изоляции REPEATABLE READ, транзакция может видеть только что вставленные записи, зафиксированные другими транзакциями в процессе выполнения, но не может видеть обновления существующих записей другими транзакциями.
3.3 READ COMMITTED (чтение зафиксированных данных)
Когда система базы данных использует уровень изоляции READ COMMITTED, транзакция может видеть только что вставленные записи, зафиксированные другими транзакциями в процессе выполнения, а также обновления существующих записей, зафиксированные другими транзакциями.
3.4 READ UNCOMMITTED (чтение незафиксированных данных)
Когда система базы данных использует уровень изоляции READ UNCOMMITTED, транзакция может видеть вновь вставленные записи, которые не были зафиксированы другими транзакциями во время выполнения, а также может видеть обновления существующих записей, которые не были зафиксированы другими транзакциями.
Вышеупомянутые четыре уровня изоляции отсортированы сверху вниз, можно сказать, выберите SERIALIZABLE, потому что он самый безопасный! Да, это самый безопасный, но и самый медленный! Безопасность четырех уровней изоляции обратно пропорциональна производительности! Самый безопасный имеет худшую производительность, а наименее безопасный — лучшую производительность!
4. Уровень изоляции и параллелизм
Благодаря определениям вышеприведенных четырех уровней изоляции мы уже можем проанализировать, каких проблем параллелизма можно избежать с помощью каждого уровня изоляции.В следующей таблице приведены сводные данные:
уровень изоляции | Потерянные обновления категории 1 | Вторая категория потерянных обновлений | грязное чтение | неповторяемое чтение | галлюцинации |
---|---|---|---|---|---|
SERIALIZABLE (сериализовать) | избегать | избегать | избегать | избегать | избегать |
Повторяемое чтение (повторяемое чтение) | избегать | избегать | избегать | избегать | позволять |
ПРОЧИТАТЬ СОВЕРШЕНО | избегать | позволять | избегать | позволять | позволять |
ЧИТАТЬ БЕЗ ЗАЯВЛЕНИЙ | избегать | позволять | позволять | позволять | позволять |
Мы можем легко проанализировать эту таблицу самостоятельно через определение уровня изоляции, Например, определение уровня изоляции повторяемого чтения состоит в том, что транзакция может видеть вновь вставленные записи, отправленные другими транзакциями в процессе выполнения, но не может видеть другие пары транзакций. , Обновление существующей записи. Следовательно, на этом уровне изоляции во время T5 примера грязного чтения и во время T7 неповторяемого чтения транзакция A не может прочитать обновление транзакции B для существующих записей независимо от того, зафиксирована транзакция B или нет. . , поэтому не будет грязных и неповторяемых чтений, а поскольку новые вставленные записи, которые были зафиксированы другими транзакциями, можно увидеть на этом уровне изоляции, фантомные чтения, естественно, неизбежны. Кроме того, стоит отметить, что все уровни изоляции избегают первого класса потерянных обновлений.
Большинство реляционных баз данных по умолчанию используют зафиксированный уровень изоляции Read, а Mysql InnoDB по умолчанию использует повторяемый уровень изоляции Read, который связан с форматом журнала операторов, используемым механизмом репликации Mysql. Реализация каждого уровня изоляции базы данных также различается. Например, Oracle поддерживает уровни изоляции Read commited и Serializable. Кроме того, неповторяющиеся операции чтения могут быть запрещены на уровне Read commited с помощью моментальных снимков чтения; MySQL использует уровень изоляции RR с помощью по умолчанию, а стандарт SQL — RR требуется для решения проблемы неповторяющихся чтений, но поскольку MySQL использует блокировку пробелов, фактически уровень изоляции MySQL RR также решает проблему фантомных чтений, то есть Mysql InnoDB использует следующий Стратегия блокировки ключей на повторяющемся уровне чтения, чтобы избежать явления фантомного чтения.