8 Механизмы упорядочиваемости транзакций
8.1 Сериализация транзакций
Для того, чтобы добиться изолированности транзакций и избежать проблем параллелизма, в СУБД должны использоваться какие-либо методы регулирования совместного выполнения транзакций.
План (способ) выполнения набора транзакций называется сериальным, если результат совместного выполнения транзакций эквивалентен результату некоторого последовательного выполнения этих же транзакций.
Набор из нескольких транзакций, элементарные операции которых чередуются друг с другом, называется смесью транзакций. Последовательность, в которой выполняются элементарные операции заданного набора транзакций, называется графиком запуска набора транзакций. Элементарные операции различных транзакций смогут выполняться в произвольной очередности при соблюдении строгой очередности операций внутри каждой транзакции. Очевидно, что для заданного набора транзакций существует достаточно много графиков запуска, из которых выбирается оптимальный график.
Для того чтобы избежать проблем параллелизма, необходимо выработать некоторую методику управления параллельным и согласованным выполнением транзакций. Такая методика называется сериализацией транзакций и полностью отвечает свойству изоляции.
Эта методика должна удовлетворять следующим правилам:
− в ходе выполнения транзакции пользователь видит только согласованные данные. Пользователь не должен видеть несогласованных промежуточных данных;
− когда в БД две транзакции выполняются параллельно, то СУБД гарантированно поддерживает принцип независимого выполнения транзакций, который гласит, что результаты выполнения транзакций будут такими же, как если бы вначале выполнялась транзакция 1, а потом транзакция 2, или наоборот, сначала транзакция 2, а потом транзакция 1.
Проблемой может стать выбор метода сериализации набора транзакций, который бы не слишком ограничивал их параллельность. Самым тривиальным решением является действительно последовательное выполнение транзакций. Но существуют ситуации сохранения сериальности. Примерами могут служить только читающие транзакции, а также те, в которых можно выполнять операторы разных транзакций в любом порядке, то есть транзакции, не конфликтующие по объектам базы данных.
8.2 Блокировки
Наиболее распространенным механизмом, используемым в СУБД для сериализации транзакций, является механизм блокировок.
Блокировка – это временное ограничение доступа к данным, участвующим в транзакции, со стороны других транзакций.
Основная идея блокировки заключается в том, что если для выполнения некоторой транзакции необходимо, чтобы какой-либо объект (как правило, это строка таблицы) не изменился без ведома этой транзакции, то этот объект блокируется. Доступ к заблокированному объекту со стороны других транзакций ограничивается. Следовательно, вызвавшая блокировку транзакция в состоянии выполнить необходимую обработку с учетом того, что обрабатываемый объект не будет самопроизвольно изменяться (с точки зрения данной транзакции) столько времени, сколько потребуется. Блокировки по-другому называют синхронизационными захватами.
Самый простой вариант блокировки — это блокировка объекта на все время действия транзакции. Подобный пример рассмотрен на рисунке 8.1. Здесь две транзакции, названные условно А и В, работают с тремя таблицами: Т1, Т2 и Т3. В момент начала работы с любым объектом этот объект блокируется транзакцией, которая с ним начала работу, и он становится недоступным всем другим транзакциям до окончания транзакции, заблокировавшей ("захватившей") данный объект. После окончания транзакции все заблокированные ею объекты разблокируются и становятся доступными другим транзакциям. Если транзакция обращается к заблокированному объекту, то она остается в состоянии ожидания до момента разблокировки этого объекта, после чего она может продолжать обработку данного объекта. Поэтому транзакция В ожидает разблокировки таблицы Т2 транзакцией А. Над прямоугольниками стоит условное время выполнения операций.
Рисунок 8.1 - Блокировка объекта на все время действия транзакции
В общем случае на момент выполнения транзакция получает как бы монопольный доступ к объектам БД, с которыми она работает. В этом случае другие транзакции не получают доступа к объектам БД до момента окончания транзакции. Такой механизм действительно ликвидирует все перечисленные ранее проблемы: пропавшие изменения, неподтвержденные данные, несогласованные данные, строки-фантомы. Однако такая блокировка создает новые проблемы — задержку выполнения транзакций из-за блокировок.
Различают следующие типы блокировок:
− по степени доступности данных: разделяемые и исключающие (монопольные);
− по множеству блокируемых данных;
− по способу установки: автоматические и явные.
Монопольные блокировки (X-блокировки, X-Locks - eXclusive locks) - жесткие блокировки без взаимного доступа, устанавливаются только одним пользователем, получающим эксклюзивный доступ к данным. Данный тип блокировки называют блокировкой записи. Объекты, заблокированные такой блокировкой, остаются в монопольном режиме обработки и недоступны для других транзакций до момента окончания работы данной транзакции;
Разделяемые блокировки (S-блокировки, S-Locks - Shared locks) - блокировки с взаимным доступом, могут одновременно устанавливаться несколькими пользователями. Данный тип блокировки называют блокировкой чтения. Объекты, заблокированные блокировкой чтения, не изменяются в ходе выполнения транзакции и доступны другим транзакциям.
Блокировки могут быть применены к разному типу объектов. Наибольшим объектом блокировки может быть вся БД (dbspace-level locking), однако этот вид блокировки сделает БД недоступной для всех приложений, которые работают с данной БД.
Следующий тип объекта блокировки — это таблицы (table-level locking). Транзакция, которая работает с таблицей, блокирует ее на все время выполнения транзакции. Этот вид блокировки предпочтительнее предыдущего, потому что позволяет параллельно выполнять транзакции, которые работают с другими таблицами. Иногда используются блокировки на уровне элемента таблицы (item-level locking) или блокировка на уровне табличного пространства (tablespace-level locking).
В ряде СУБД реализована блокировка на уровне страниц (page-level locking). В этом случае СУБД блокирует только отдельные страницы на диске, когда транзакция обращается к ним. Этот вид блокировки еще более мягок и позволяет разным транзакциям работать даже с одной и той же таблицей, если они обращаются к разным страницам данных.
В некоторых СУБД возможна блокировка на уровне строк (row-level locking), однако такой механизм блокировки требует дополнительных затрат на поддержку этого вида блокировки.
Блокировка может быть автоматической и явной. Если запускается новая транзакция, СУБД сначала проверяет, не заблокирована ли другой транзакцией строка, требуемая этой транзакции: если нет, то строка автоматически блокируется и выполняется операция над данными; если строка заблокирована, транзакция ожидает снятия блокировки. Явная блокировка, накладываемая командой LOCK (SQL), обычно используется тогда, когда транзакция затрагивает существенную часть отношения.
Правила взаимного доступа к заблокированным объектам можно представить в виде матрицы совместимости блокировок. Если транзакция A устанавливает блокировку на некоторый объект, а транзакция B в следующий момент времени пытается выполнить аналогичные действия, то успешность блокирования объекта транзакцией B определяется матрицей совместимости (таблица 8.1).
Таблица 8.1 - Матрица совместимости X- и S- блокировок
|
Транзакция В |
|||
Разблокирована |
S-блокировка |
Х-блокировка |
||
Транзакция А |
Разблокирована |
Да |
Да |
Да |
S-блокировка |
Да |
Да |
Нет |
|
Х-блокировка |
Да |
Нет |
Нет |
Три случая, когда транзакция B не может блокировать объект, соответствуют трем видам конфликтов между транзакциями. Конфликты доступа к данным возникают в результате конкуренции. Транзакции называются конкурирующими, если они пересекаются по времени и обращаются к одним и тем же данным.
Различают следующие виды конфликтов:
- W-W (Запись–Запись). Транзакция A изменила объект и не закончилась. Транзакция B пытается изменить тот же объект. Результат - потеря обновления;
- R-W (Чтение–Запись). Транзакция B пытается изменить объект, прочитанный не закончившейся транзакцией A. Результат - несовместимый анализ (неповторимое чтение);
- W-R (Запись–Чтение). Транзакция B пытается читать объект, измененный еще незакончившейся транзакцией A.
Доступ к объектам БД на чтение и запись осуществляется в соответствии с протоколом доступа к данным, который состоит из следующих требований:
1. прежде чем прочитать объект, транзакция должна наложить на этот объект S-блокировку;
2. прежде чем обновить объект, транзакция должна наложить на этот объект X-блокировку. Если транзакция уже заблокировала объект S-блокировкой (для чтения), то перед обновлением объекта S-блокировка должна быть заменена X-блокировкой;
3. если блокировка объекта транзакцией B отвергается от того, что объект уже заблокирован транзакцией A, то транзакция B переходит в состояние ожидания. Транзакция B находится в состоянии ожидания до тех пор, пока транзакция A не снимет блокировку объекта;
4. X-блокировки, наложенные транзакцией A, сохраняются до конца транзакции A.
Рассмотрим, как будут себя вести транзакции, вступающие в конфликт при доступе к данным, если они подчиняются протоколу доступа к данным.
На рисунке приведен ранее рассмотренный пример с выполнением транзакций 1 и 2, но с учетом разных типов блокировки. На рисунке 8.2 видно, что, применив нежесткую блокировку к таблице 2 со стороны транзакции 1, мы обеспечили существенное уменьшение времени выполнения транзакции 2. Теперь транзакция 2 не ждет окончания транзакции 1, и поэтому завершает свою работу намного раньше.
Рисунок 8.2 - Использование жесткой и нежесткой блокировки
К сожалению, применения разных типов блокировок приводит к проблеме тупиков.
Рассмотрим пример. Пусть транзакция А сначала жестко блокирует таблицу 1, а потом жестко блокирует таблицу 2. Транзакция B, наоборот, сначала жестко блокирует таблицу 2, а потом жестко блокирует таблицу 1. Если обе эти транзакции начали работу одновременно, то после выполнения операций модификации первыми объектами каждой транзакции они обе окажутся в бесконечном ожидании: транзакция А будет ждать завершения работы транзакции B и разблокировки таблицы 2, а транзакция В также безрезультатно будет ждать окончания работы транзакции А и разблокировки таблицы 1.
Рисунок 8.3 - Взаимная блокировка транзакций
8.3 Решение проблем параллелизма с применением механизма блокировок
Потеря результатов обновления возникает в ситуации, когда две транзакции одновременно читают и изменяют одну и ту же запись в БД. Причем одна транзакция записывает в строку БД свое значение, например, y1, а вторая транзакция вносит в эту же строку БД свои изменения, например, y2. В результате фиксации более поздней транзакции строка БД будет содержать значение, которая внесла именно эта транзакция, а ранее закончившаяся транзакция никогда не увидит тех значений, которые вносила она в строку БД, то есть ее значения становятся пропавшими.
Естественно, она противоречит требованию изолированности пользователей. Чтобы избежать такой ситуации в транзакции 1 требуется, чтобы до завершения транзакции 1 никакая другая транзакция не могла изменять объект.
Таблица 8.2 - Потеря результата обновления в момент времени t6
Транзакция 1 |
Время |
Транзакция 2 |
S-блокировка tbl1 (успешна) |
t1 |
|
SELECT f2 (f2=40) FROM tbl1 WHERE f1=1; |
t2 |
|
|
t3 |
S-блокировка tbl1 (успешна) |
|
t4 |
SELECT f2 (f2=40) FROM tbl1 WHERE f1=1; |
X-блокировка tbl1 отменяется |
t5 |
|
Ожидание … |
t6 |
X-блокировка tbl1 отменяется |
Ожидание … |
t7 |
Ожидание … |
Операция обновления объекта tbl1 для транзакции 1 в момент времени t5 не будет выполнена, так как она является запросом, требующим X-блокировки строки tbl1, а этот запрос вступает в конфликт с S-блокировкой, заданной транзакцией 2. Таким образом, транзакция 1 переходит в состояние ожидания. По аналогичным причинам транзакция 2 переходит в состояние ожидания в момент времени t7. Как видим, блокировка не решает проблемы потери результатов обновления, более того, возникает новая проблема, которая называется тупиком.
Незафиксированная зависимость (чтение "грязных данных") возникает, если одна транзакция выполняет чтение некоторой строки таблицы БД, которая в данный момент обновляется другой транзакцией, но это обновление еще не зафиксировано. Первая транзакция выполнила чтение «грязных» данных, которых нет и не было в базе данных в результате аннулирования изменения более поздним откатом транзакции второй транзакции.
Проблема незафиксированной зависимости разрешается за счет некоторого увеличения времени работы транзакции 2, ожидающей снятия блокировки транзакцией 1.
Таблица 8.3 - Разрешение проблемы незафиксированной зависимости (грязные данные)
Транзакция 1 |
Время |
Транзакция 2 |
S-блокировка tbl1 (успешна) |
t1 |
|
SELECT f2 (f2=40) FROM tbl1 WHERE f1=1; |
t2 |
|
Х-блокировка tbl1 (успешна) |
t3 |
|
UPDATE tbl1 SET f2=f2-30 (f2=10) WHERE f1=1; |
t4 |
|
|
t5 |
S-блокировка tbl1 (отменяется) |
ROLLBACK WORK; (блокировка снимается) |
t6 |
Ожидание … |
|
t7 |
S-блокировка tbl1 (успешна) |
|
t8 |
SELECT f2 (f2=10 FROM tbl1 WHERE f1=1; |
|
t9 |
COMMIT (блокировка снимается) |
Проблема несовместимого анализа разрешается в ситуации неповторяемого чтения. Неповторяемое чтение возникает тогда, когда между двумя, подряд идущими, операциями чтения транзакции 1 вклинивается транзакция 2, изменяющее считываемое значение в строке таблицы.
Чтобы избежать неповторяющихся чтений, до завершения транзакции 1 никакая другая транзакция не должна изменять объект A.
Транзакция 1 притормаживается до момента окончания транзакции 2. В результате транзакция 2 дважды читает одни и те же данные правильно.
Таблица 8.4 - Разрешение проблемы неповторяемого чтения
Транзакция 1 |
Время |
Транзакция 2 |
S-блокировка tbl1 (успешна) |
t1 |
|
SELECT f2 (f2=40) FROM tbl1 WHERE f1=1; |
t2 |
|
|
t3 |
S-блокировка tbl1 (успешна) |
|
t4 |
SELECT f2 (f2=40) FROM tbl1 WHERE f1=1; |
X-блокировка tbl1 отвергается |
|
|
Ожидание… |
|
SELECT f2 (f2=10) FROM tbl1 WHERE f1=1; |
Ожидание… |
|
COMMIT (блокировка снимается) |
X-блокировка tbl1 - успешна |
|
|
UPDATE tbl1 SET f2=F2-30 (f2=10) WHERE f1=1; |
t5 |
|
COMMIT(блокировка снимается) |
t6 |
|
Сложнее обстоит дело с фантомами и собственно несовместимым анализом данных.
Фантомы появляются в результате вставки новой строки (строк) транзакцией 1 по условию U1 между двумя, подряд идущими, выборками, удовлетворяющими условию U1 и выполняемыми транзакцией 2.
В ситуации появления строк-призраков блокировка не влияет на результат, так как S-блокировка строк, удовлетворяющих условию U1, предшествующая выбору строк никак не влияет на операцию вставки новой строки, которая может быть выполнена успешно. После фиксации транзакции 2 строки-призраки по-прежнему появляются в таблице базы данных.
Таблица 8.5 - Разрешение проблемы фантомов
Транзакция A |
Время |
Транзакция B |
|
t1 |
S-блокировка строк, удовлетворяющих условию U1. (Заблокировано n строк) |
|
t2 |
SELECT SUM(f2) FROM tbl1 Where f1=10.01.09; |
Х-блокировка строк, удовлетворяющих условию U1. (Заблокировано n строк) |
|
|
INSERT INTO tbl1 (f1,f2) VALUES (10.01.09,20); |
t3 |
|
COMMIT (снятие блокировки) |
t4 |
|
|
t5 |
S-блокировка строк, удовлетворяющих условию U1. (Заблокировано n строк) |
|
t6 |
SELECT f2 FROM tbl1 Where f1=10.01.09; |
|
t7 |
COMMIT (снятие блокировки) |
Блокировка на уровне строк не решила проблему появления фиктивных элементов.
В ситуации собственно несовместимого анализа возникает тупик, так как S-блокировка счета СЧЕТ1, установленная операцией чтения СЧЕТ1=40, отвергает X-блокировку данного объекта, которую пытается установить транзакция 2 для обновления СЧЕТ1 (перевод суммы 10 на СЧЕТ3), и транзакция B переходит в состояние ожидания.
Таблица 8.6 - Несовместимый анализ. Возникновение тупиковой ситуации
Транзакция A |
Время |
Транзакция B |
S-блокировка tbl1 (СЧЕТ1, СЧЕТ2) |
t1 |
|
SELECT Сч1 (Сч1=40) FROM tbl1 WHERE f1=1; |
t2 |
– |
SUM=SUM+ Сч1 (SUM=40) |
t3 |
|
SELECT Сч2 (Сч1=50) FROM tbl1 WHERE f1=1; |
t4 |
|
SUM=SUM+ Сч2 (SUM=90) |
t5 |
|
|
t6 |
S-блокировка tbl1 (СЧЕТ3) |
|
t7 |
SELECT Сч3 (Сч3=30) FROM tbl1 WHERE f1=1; |
|
t8 |
Х-блокировка tbl1 (СЧЕТ3) |
|
t9 |
UPDATE tbl1 SET Сч3= Сч3-10 (Сч3=20); |
|
t10 |
Х-блокировка tbl1 (отменяется) |
S-блокировка СЧЕТ3 отменяется |
t11 |
Ожидание… |
Ожидание … |
|
|
Таким образом, использование протокола доступа к данным на основе блокировок разрешает часть проблем параллелизма, но возникает новая проблема — тупики:
- проблема потери результатов обновления - возник тупик;
- проблема незафиксированной зависимости (чтение "грязных" данных, неаккуратное считывание) - проблема разрешилась;
- неповторяемое считывание - проблема разрешилась;
- появление фиктивных элементов - проблема не разрешилась;
- проблема несовместимого анализа - возник тупик.
8.4 Тупики
Тупиковые ситуации (deadlocks) возникают при взаимных блокировках транзакций, выполняющихся на пересекающихся множествах данных.
Анализ разрешения проблем параллелизма позволяет утверждать, что ситуация тупика может возникнуть при наличии в смеси не менее двух транзакций, каждая из которых выполняет не менее двух операций. На практике ситуации могут быть гораздо более сложными из-за наличия большого числа взаимно заблокированных транзакций. Очевидно, что для разрешения тупиковых ситуаций необходимо предпринимать некоторые дополнительные действия. Для обнаружения тупиковой ситуации используется несколько подходов:
1) откат одной из транзакций (транзакции-жертвы). После разрешения тупика транзакция-жертва выполняется заново. СУБД не отслеживает тупиковые ситуации. Транзакции самостоятельно принимают решение о выборе жертвы;
2) вводится таймаут (time-out) – максимальное время, в течение которого транзакция может находиться в состоянии ожидания. Если транзакция находится в состоянии ожидания дольше таймаута, считается, что она находится в состоянии тупика, и СУБД инициирует её откат с последующим рестартом через случайный промежуток времени;
3) обнаружение и разрешение тупиковой ситуации средствами СУБД.
Первый и второй подходы характерны для настольных СУБД (FoxPro, Access, Paradox и др.). Этот метод прост и не требует дополнительных ресурсов системы. Для транзакций задается время ожидания (или число попыток), в течение которого транзакция пытается установить нужную блокировку. Если за указанное время блокировка не завершится успешно, то транзакция откатывается. Недостаток метода заключается в том, что транзакции-жертвы выбираются случайным образом. В результате из-за одной простой транзакции может откатится «дорогая» транзакция, которая уже использовала много времени и ресурсов вычислительной системы.
Третий подход характерен для промышленных СУБД (Oracle, MS SQL Server, Sybase и т.п.). Он основан на постоянной поддержке СУБД графа ожиданий транзакций. Граф ожидания транзакций - это ориентированный двудольный граф, в котором существует два типа вершин: вершины, соответствующие транзакциям, и вершины, соответствующие объектам захвата (блокирования). В этом графе существует дуга, ведущая из вершины-транзакции к вершине-объекту, если для этой транзакции существует удовлетворенный захват объекта. В графе существует дуга из вершины-объекта к вершине-транзакции, если транзакция ожидает удовлетворения захвата объекта.
Основой обнаружения тупиковых ситуаций является построение (или постоянное поддержание) графа ожидания транзакций. Для распознавания тупика здесь производится построение графа ожидания транзакций и в этом графе ищутся циклы.
Граф ожидания — это направленный граф, в вершинах которого расположены имена транзакций. Если транзакция А ждет окончания транзакции В, то из вершины А в вершину В идет стрелка. Дополнительно стрелки могут быть помечены именами заблокированных объектов и типом блокировки. Пример такого графа ожиданий приведен на рисунке 8.4.
Этот граф ожиданий построен для транзакций Т1, Т2, …,Т12, которые работают с объектами БД A,В,...,Н.
Рисунок 8.4 - Пример графа ожиданий транзакций
На графе объекты блокировки помечены типами блокировок, S — нежесткая (разделяемая) блокировка, X — жесткая (эксклюзивная) блокировка.
На диаграмме состояний ожидания видно, что транзакции Т9, Т8, Т2 и Т3 образуют цикл. Именно наличие цикла и является признаком возникновения тупиковой ситуации. Поэтому в момент 3 перечисленные транзакции будут заблокированы.
Разрушение тупика начинается с выбора в цикле транзакций так называемой транзакции-жертвы, то есть транзакции, которой решено пожертвовать, чтобы обеспечить возможность продолжения работы других транзакций.
Критерием выбора является стоимость транзакции; жертвой выбирается самая дешевая транзакция. Стоимость транзакции определяется на основе многофакторной оценки, в которую с разными весами входят время выполнения, число накопленных захватов, приоритет.
После выбора транзакции-жертвы выполняется откат этой транзакции, который может носить полный или частичный характер. При этом, естественно, освобождаются захваты и может быть продолжено выполнение других транзакций.
Заметим, что в централизованных системах стоимость построения графа ожидания сравнительно невелика, но она становится слишком большой в по-настоящему распределенных СУБД, в которых транзакции могут выполняться в разных узлах сети. Поэтому в таких системах обычно используются другие методы сериализации транзакций.
8.4.1 Теорема Есварана о сериализуемости
Общепринятым критерием правильности управления параллельной работой транзакций является способность к упорядочению: чередующееся выполнение заданного множества транзакций будет верным, если оно упорядочено, то есть при его выполнении будет получен такой же результат, как и при последовательном выполнении тех же транзакций. Концепция способности к упорядочению была впервые предложена Есвараном. Им была доказана важная теорема двухфазной блокировки.
Теорема Есварана: если все транзакции подчиняются протоколу двухфазной блокировки, то для всех возможных чередующихся графиков запуска существует возможность упорядочения.
Протокол двухфазной блокировки (или двухфазный протокол синхронизационных захватов) определяет следующие правила:
− перед выполнением каких-либо операций с некоторым объектом, транзакция должна заблокировать этот объект;
− после снятия блокировки, транзакция не должна накладывать никаких других блокировок.
Рисунок 8.5 - Протокол двухфазной блокировки
Таким образом, транзакция, которая подчиняется данному протоколу, характеризуется двумя фазами:
1) нарастания блокировок: накладываются блокировки, и производится работа с заблокированными объектами;
2) снятия блокировок: работа с ранее заблокированными объектами может продолжаться; на второй фазе блокировки только снимаются.
На практике вторая фаза часто сводится к единственной операции завершения транзакции (фиксация либо откат) с одновременным снятием всех блокировок. Если A и B являются любыми двумя транзакциями с графиком запуска, способным к упорядочению, то либо A логически предшествует B, либо B использует результаты выполнения транзакции A (символ ÿ - работа с объектом БД; ○ — блокирование объекта; Ä — разблокирование).
Если некоторая транзакция A не подчиняется протоколу двухфазной блокировки (и, следовательно, состоит не менее чем из двух операция блокирования и разблокирования), то всегда можно построить другую транзакцию B, которая при чередующемся выполнении вместе с A приводит к графику, не подлежащему упорядочению и неверному.
8.5 Изолированность пользователей
В многопользовательских системах с одной базой данных одновременно могут работать несколько пользователей или прикладных программ. Предельной задачей системы является обеспечение изолированности пользователей, т.е. создание достоверной и надежной иллюзии того, что каждый из пользователей работает с БД в одиночку.
Стандарт SQL не предусматривает понятие блокировки для реализации сериализуемости транзакций. Вместо этого вводятся уровни изолированности пользователей, связанные с проблемами параллелизма транзакций. Этот подход обеспечивает различным производителям СУБД возможность реализовать требования изолированности произвольными способами. В стандарте SQL-92 определено четыре уровня изолированности:
1) READ UNCOMMITED - уровень незавершенного чтения;
2) READ COMMITED - уровень завершенного чтения;
3) REPEATABLE READ - уровень повторяемого чтения;
4) SERIALIZABLE - уровень способности к упорядочению, соответствующий протоколу сериализации транзакций.
Самый высокий четвертый уровень изолированности пользователей SERIALIZABLE - последовательное выполнение (используется по умолчанию). Этот уровень гарантирует предотвращение всех конфликтных ситуаций, но, соответственно, при нем наблюдается самая низкая степень параллелизма;
Уровень REPEATABLE READ - повторяющееся чтение. На этом уровне разрешено выполнение операторов INSERT, приводящих к конфликтной ситуации "фантомная вставка". Проблема "фантомной вставки" может быть решена алгоритмически исключением из алгоритма повторного выполнения запроса в одной транзакции. Этот уровень целесообразно использовать, если на выполняющиеся SQL-операторы не влияет добавление новых строк. Этот уровень не допускает пропавшие обновления, неповторяемое чтение, незафиксированные зависимости, однако проблема фантомов остается.
На уровне READ COMMITTED - фиксированное чтение - транзакция не имеет доступа к промежуточным результатам других транзакций, поэтому проблемы неаккуратного чтения данных не возникают. Остаются неразрешенными проблемы фантомов и неповторяемого чтения. Этот уровень позволяет получать разные результаты для одинаковых запросов, но только после фиксации транзакции, повлекшей изменение данных.
На самом низком уровне изолированности пользователей READ UNCOMMITTED - нефиксированное чтение - транзакция видит промежуточные и несогласованные данные, поэтому проблемы неаккуратного чтения, неповторяемого чтения и фантомов не разрешаются. Тем не менее, даже на самом низком уровне изолированности, СУБД предотвращает пропавшие обновления.
Таблица 8.7 - Уровни изолированности пользователей
Уровень изоляции |
Предотвращение конфликтной ситуации |
|||
Неповторяющееся чтение (non-repeatable read) |
"Грязное" чтение (dirty read) |
Потерянное обновление (lost update) |
Фантомная вставка (phantom insert) |
|
SERIALIZABLE |
+ |
+ |
+ |
+ |
REPEATABLE READ |
+ |
+ |
+ |
- |
READ COMMITTED |
- |
+ |
+ |
- |
READ UNCOMMITTED |
- |
- |
+ |
- |