Основная идея блокировок заключается в том, что если для выполнения некоторой транзакции необходимо, чтобы некоторый объект не изменялся без ведома этой транзакции, то этот объект должен быть заблокирован, т.е. доступ к этому объекту со стороны других транзакций ограничивается на время выполнения транзакции, вызвавшей блокировку.
Различают два типа блокировок: Монопольные блокировки (X-блокировки, X-locks - eXclusive locks) - блокировки без взаимного доступа (блокировка записи). Разделяемые блокировки (S-блокировки, S-locks - Shared locks) - блокировки с взаимным доступом (блокировка чтения).
Если транзакция A блокирует объект при помощи X-блокировки, то всякий доступ к этому объекту со стороны других транзакций отвергается.
Если транзакция A блокирует объект при помощи S-блокировки, то запросы со стороны других транзакций на X-блокировку этого объекта будут отвергнуты, запросы со стороны других транзакций на S-блокировку этого объекта будут приняты.
Правила взаимного доступа к заблокированным объектам можно представить в виде следующей матрицы совместимости блокировок. Если транзакция A наложила блокировку на некоторый объект, а транзакция B после этого пытается наложить блокировку на этот же объект, то успешность блокирования транзакцией B объекта описывается таблицей:
Эффект фиктивных элементов несколько отличается от предыдущих транзакций тем, что здесь за один шаг выполняется достаточно много операций - чтение одновременно нескольких строк, удовлетворяющих некоторому условию.
Транзакция A дважды выполняет выборку строк с одним и тем же условием. Между выборками вклинивается транзакция B, которая добавляет новую строку, удовлетворяющую условию отбора.
Транзакция A дважды выполняет выборку строк с одним и тем же условием. Между выборками вклинивается транзакция B, которая добавляет новую строку, удовлетворяющую условию отбора.
В данной главе изучаются возможности параллельного выполнения транзакций несколькими пользователями, т.е. свойство (И) - изолированность транзакций.
Современные СУБД являются многопользовательскими системами, т.е. допускают параллельную одновременную работу большого количества пользователей. При этом пользователи не должны мешать друг другу. Т.к. логической единицей работы для пользователя является транзакция, то работа СУБД должна быть организована так, чтобы у пользователя складывалось впечатление, что их транзакции выполняются независимо от транзакций других пользователей.
Простейший и очевидный способ обеспечить такую иллюзию у пользователя состоит в том, чтобы все поступающие транзакции выстраивать в единую очередь и выполнять строго по очереди. Такой способ не годится по очевидным причинам - теряется преимущество параллельной работы. Таким образом, транзакции необходимо выполнять одновременно, но так, чтобы результат был бы такой же, как если бы транзакции выполнялись по очереди. Трудность состоит в том, что если не предпринимать никаких специальных мер, то данные измененные одним пользователем могут быть изменены транзакцией другого пользователя раньше, чем закончится транзакция первого пользователя. В результате, в конце транзакции первый пользователь увидит не результаты своей работы, а неизвестно что.
Одним из способов (не единственным) обеспечить независимую параллельную работу нескольких транзакций является метод блокировок.
Итак, анализ проблем параллелизма показывает, что если не предпринимать специальных мер, то при работе в смеси нарушается свойство (И) транзакций - изолированность. Транзакции реально мешают друг другу получать правильные результаты.
Однако не всякие транзакции мешают друг другу. Очевидно, что транзакции не мешают друг другу, если они обращаются к разным данным или выполняются в разное время.
Использование блокировок гарантирует сериальность планов выполнения смеси транзакций за счет общего замедления работы - конфликтующие транзакции ожидают, когда транзакция, первой заблокировавшая некоторый объект, не освободит его. Без блокировок не обойтись, если все транзакции изменяют данные. Но если в смеси транзакций присутствуют как транзакции, изменяющие данные, так и только читающие данные, можно применить альтернативный механизм обеспечения сериальности, свободный от недостатков метода блокировок. Этот метод состоит в том, что транзакциям, читающим данные, предоставляется как бы "своя" версия данных, имевшаяся в момент начала читающей транзакции. При этом транзакция не накладывает блокировок на читаемые данные, и, поэтому, не блокирует другие транзакции, изменяющие данные. Такой механизм называется механизм выделения версий и заключается в использовании журнала транзакций для генерации разных версий данных.
Журнал транзакций предназначен для выполнения операции отката при неуспешном выполнении транзакции или для восстановления данных после сбоя системы. Журнал транзакций содержит старые копии данных, измененных транзакциями.
Кратко суть метода состоит в следующем: Для каждой транзакции (или запроса) запоминается текущий системный номер (SCN - System Current Number). Чем позже начата транзакция, тем больше ее SCN. При записи страниц данных на диск фиксируется SCN транзакции, производящей эту запись. Этот SCN становится текущим системным номером страницы данных. Транзакции, только читающие данные не блокируют ничего в базе данных. Если транзакция A читает страницу данных, то SCN транзакции A сравнивается с SCN читаемой страницы данных. Если SCN страницы данных меньше или равен SCN транзакции A, то транзакция A читает эту страницу. Если SCN страницы данных больше SCN транзакции A, то это означает, что некоторая транзакция B, начавшаяся позже транзакции A, успела изменить или сейчас изменяет данные страницы. В этом случае транзакция A просматривает журнал транзакция назад в поиске первой записи об изменении нужной страницы данных с SCN меньшим, чем SCN транзакции A. Найдя такую запись, транзакция A использует старый вариант данных страницы.
Рассмотрим, как решается проблема несовместного анализа с использованием механизма выделения версий.
Длинная транзакция выполняет некоторый анализ по всей таблице, например, подсчитывает общую сумму денег на счетах клиентов банка для главного бухгалтера. Пусть на всех счетах находятся одинаковые суммы, например, по $100. Короткая транзакция в этот момент выполняет перевод $50 с одного счета на другой так, что общая сумма по всем счетам не меняется.
Альтернативный метод сериализации транзакций, хорошо работающий в условиях редких конфликтов транзакций и не требующий построения графа ожидания транзакций основан на использовании временных меток.
Основная идея метода состоит в следующем: если транзакция A началась раньше транзакции B, то система обеспечивает такой режим выполнения, как если бы A была целиком выполнена до начала B.
Для этого каждой транзакции T предписывается временная метка t, соответствующая времени начала T. При выполнении операции над объектом r базы данных транзакция T помечает его своей временной меткой и типом операции (чтение или изменение).
Перед выполнением операции над объектом r транзакция B выполняет следующие действия: Проверяет, не закончилась ли транзакция A, пометившая этот объект. Если A закончилась, B помечает объект r своей временной меткой и выполняет операцию. Если транзакция A не завершилась, то B проверяет конфликтность операций. Если операции неконфликтны, при объекте r остается или проставляется временная метка с меньшим значением (более ранняя), и транзакция B выполняет свою операцию. Если операции B и A конфликтуют, то если t(A) > t(B) (т.е. транзакция A является более "молодой", чем B), то транзакция A откатывается и, получив новую временную метку, начинается заново. Транзакция B продолжает работу. Если же t(A) < t(B) (A "старше" B), то транзакция B откатывается и, получив новую временную метку, начинается заново. Транзакция A продолжает работу.
В итоге система обеспечивает такую работу, при которой при возникновении конфликтов всегда откатывается более молодая транзакция (начавшаяся позже).
Очевидным недостатком метода временных меток является то, что может откатиться более дорогая транзакция, начавшаяся позже более дешевой.
К другим недостаткам метода временных меток относятся потенциально более частые откаты транзакций, чем в случае использования блокировок. Это связано с тем, что конфликтность транзакций определяется более грубо.
Транзакция A дважды читает одну и ту же строку. Между этими чтениями вклинивается транзакция B, которая изменяет значения в строке.
Транзакция A дважды читает одну и ту же строку. Между этими чтениями вклинивается транзакция B, которая изменяет значения в строке.
Другим способом блокирования является блокировка не объектов базы данных, а условий, которым могут удовлетворять объекты. Такие блокировки называются предикатными блокировками.
Поскольку любая операция над реляционной базой данных задается некоторым условием (т.е. в ней указывается не конкретный набор объектов базы данных, над которыми нужно выполнить операцию, а условие, которому должны удовлетворять объекты этого набора), то удобным способом было бы S или X-блокирование именно этого условия. Однако при попытке использовать этот метод в реальной СУБД возникает трудность определения совместимости различных условий. Действительно, в языке SQL допускаются условия с подзапросами и другими сложными предикатами. Проблема совместимости сравнительно легко решается для случая простых условий, имеющих вид:
{Имя атрибута {= | <> | > | >= | < | <=} Значение}
[{OR | AND} {Имя атрибута {= | <> | > | >= | < | <=} Значение}.,..]
Проблема фиктивных элементов (фантомов) легко решается с использованием предикатных блокировок, т.к. вторая транзакция не может вставить новые строки, удовлетворяющие уже заблокированному условию.
Заметим, что блокировка всей таблицы в каком-либо режиме фактически есть предикатная блокировка, т.к. каждая таблица имеет предикат, определяющий какие строки содержатся в таблице и блокировка таблицы есть блокировка предиката этой таблицы.
Как видно из анализа поведения транзакций, при использовании протокола доступа к данным не решается проблема фантомов. Это происходит оттого, что были рассмотрены только блокировки на уровне строк. Можно рассматривать блокировки и других объектов базы данных: Блокировка самой базы данных. Блокировка файлов базы данных. Блокировка таблиц базы данных. Блокировка страниц (Единиц обмена с диском, обычно 2-16 Кб. На одной странице содержится несколько строк одной или нескольких таблиц). Блокировка отдельных строк таблиц. Блокировка отдельных полей.
Кроме того, можно блокировать индексы, заголовки таблиц или другие объекты.
Чем крупнее объект блокировки, тем меньше возможностей для параллельной работы. Достоинством блокировок крупных объектов является уменьшение накладных расходов системы и решение проблем, не решаемых с использованием блокировок менее крупных объектов. Например, использование монопольной блокировки на уровне таблицы, очевидно, решает проблему фантомов.
Современные СУБД, как правило, поддерживают минимальный уровень блокировки на уровне строк или страниц. (В старых версиях настольной СУБД Paradox поддерживалась блокировка на уровне отдельных полей.).
При использовании блокировок объектов разной величины возникает проблема обнаружения уже наложенных блокировок. Если транзакция A пытается заблокировать таблицу, то необходимо иметь информацию, не наложены ли уже блокировки на уровне строк этой таблицы, несовместимые с блокировкой таблицы. Для решения этой проблемы используется протокол преднамеренных блокировок, являющийся расширением протокола доступа к данным. Суть этого протокола в том, что перед тем, как наложить блокировку на объект (например, на строку таблицы), необходимо наложить специальную преднамеренную блокировку (блокировку намерения) на объекты, в состав которых входит блокируемый объект - на таблицу, содержащую строку, на файл, содержащий таблицу, на базу данных, содержащую файл. Тогда наличие преднамеренной блокировки таблицы будет свидетельствовать о наличии блокировки строк таблицы и для другой транзакции, пытающейся блокировать целую таблицу не нужно проверять наличие блокировок отдельных строк. Более точно, вводятся следующие новые типы блокировок: Преднамеренная блокировка с возможностью взаимного доступа (IS-блокировка - Intent Shared lock). Накладывается на некоторый составной объект T и означает намерение блокировать некоторый входящий в T объект в режиме S-блокировки. Например, при намерении читать строки из таблицы T, эта таблица должна быть заблокирована в режиме IS (до этого в таком же режиме должен быть заблокирован файл). Преднамеренная блокировка без взаимного доступа (IX-блокировка - Intent eXclusive lock). Накладывается на некоторый составной объект T и означает намерение блокировать некоторый входящий в T объект в режиме X-блокировки. Например, при намерении удалять или модифицировать строки из таблицы T эта таблица должна быть заблокирована в режиме IX (до этого в таком же режиме должен быть заблокирован файл). Преднамеренная блокировка как с возможностью взаимного доступа, так и без него (SIX-блокировка - Shared Intent eXclusive lock). Накладывается на некоторый составной объект T и означает разделяемую блокировку всего этого объекта с намерением впоследствии блокировать какие-либо входящие в него объекты в режиме X-блокировок. Например, если выполняется длинная операция просмотра таблицы с возможностью удаления некоторых просматриваемых строк, то можно заблокировать эту таблицу в режиме SIX (до этого захватить файл в режиме IS).
IS, IX и SIX-блокировки должны накладываться на сложные объекты базы данных (таблицы, файлы). Кроме того, на сложные объекты могут накладываться и блокировки типов S и X. Для сложных объектов (например, для таблицы базы данных) таблица совместимости блокировок имеет следующий вид:
Проблема несовместимого анализа включает несколько различных вариантов:
Неповторяемое считывание.
Фиктивные элементы (фантомы).
Собственно несовместимый анализ.
Транзакция B изменяет данные в строке. После этого транзакция A читает измененные данные и работает с ними. Транзакция B откатывается и восстанавливает старые данные.
Транзакция B изменяет данные в строке. После этого транзакция A читает измененные данные и работает с ними. Транзакция B откатывается и восстанавливает старые данные.
Две транзакции по очереди записывают некоторые данные в одну и ту же строку и фиксируют изменения.
Две транзакции по очереди записывают некоторые данные в одну и ту же строку и фиксируют изменения.
Каким образом транзакции различных пользователей могут мешать друг другу? Различают три основные проблемы параллелизма: Проблема потери результатов обновления. Проблема незафиксированной зависимости (чтение "грязных" данных, неаккуратное считывание). Проблема несовместимого анализа.
Рассмотрим подробно эти проблемы.
Рассмотрим две транзакции, A и B, запускающиеся в соответствии с некоторыми графиками. Пусть транзакции работают с некоторыми объектами базы данных, например со строками таблицы. Операцию чтение строки , где в строку .
Транзакция рассматривается как последовательность элементарных атомарных операций. Атомарность отдельной элементарной операции состоит в том, что СУБД гарантирует, что, с точки зрения пользователя, будут выполнены два условия: Эта операция будет выполнена целиком или не выполнена вовсе (атомарность - все или ничего). Во время выполнения этой операции не выполняются никакие другие операции других транзакций (строгая очередность элементарных операций).
Например, элементарными операциями транзакции будут считывание страницы данных с диска или запись страницы данных на диск (страница данных - это минимальная единица для дисковых операций СУБД). Условие 2 на самом деле является именно логическим условием, т.к. реально система может выполнять несколько различных элементарных операций в один и тот же момент. Например, данные могут храниться на нескольких физически различных дисках и операции чтения-записи на эти диски могут выполняться одновременно.
Элементарные операции различных транзакций могут выполняться в произвольной очередности (конечно, внутри каждой транзакции последовательность элементарных операций этой транзакции является строго определенной). Например, если есть несколько транзакций, состоящих из последовательности операций элементарных:
то реальная последовательность, в которой СУБД выполняет эти транзакции может быть, например, такой:
Итак, при использовании протокола доступа к данным с использованием блокировок часть проблем разрешилось (не все), но возникла новая проблема - тупики: Проблема потери результатов обновления - возник тупик. Проблема незафиксированной зависимости (чтение "грязных" данных, неаккуратное считывание) - проблема разрешилась. Неповторяемое считывание - проблема разрешилась. Появление фиктивных элементов - проблема не разрешилась. Проблема несовместимого анализа - возник тупик.
Общий вид тупика (dead locks) следующий:
Рассмотрим, как будут себя вести транзакции, вступающие в конфликт при доступе к данным, если они подчиняются протоколу доступа к данным.
Уровень изоляции транзакции задается следующим оператором:
SET TRANSACTION {ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE} | {READ ONLY | READ WRITE}}.,..
Этот оператор определяет режим выполнения следующей транзакции, т.е. этот оператор не влияет на изменение режима той транзакции, в которой он подается. Обычно, выполнение оператора SET TRANSACTION выделяется как отдельная транзакция: … (предыдущая транзакция выполняется со своим уровнем изоляции) COMMIT; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; COMMIT; … (следующая транзакция выполняется с уровнем изоляции REPEATABLE READ)
Если задано предложение ISOLATION LEVEL, то за ним должно следовать один из параметров, определяющих уровень изоляции.
Кроме того, можно задать признаки READ ONLY или READ WRITE. Если указан признак READ ONLY, то предполагается, что транзакция будет только читать данные. При попытке записи для такой транзакции будет сгенерирована ошибка. Признак READ ONLY введен для того, чтобы дать производителям СУБД возможность уменьшать количество блокировок путем использования других методов сериализации (например, метод выделения версий).
Оператор SET TRANSACTION должен удовлетворять следующим условиям:
Если предложение ISOLATION LEVEL отсутствует, то по умолчанию принимается уровень SERIALIZABLE.
Если задан признак READ WRITE, то параметр ISOLATION LEVEL не может принимать значение READ UNCOMMITTED.
Если параметр ISOLATION LEVEL определен как READ UNCOMMITTED, то транзакция становится по умолчанию READ ONLY. В противном случае по умолчанию транзакция считается как READ WRITE.
Эффект собственно несовместимого анализа также отличается от предыдущих примеров тем, что в смеси присутствуют две транзакции - одна длинная, другая короткая.
Длинная транзакция выполняет некоторый анализ по всей таблице, например, подсчитывает общую сумму денег на счетах клиентов банка для главного бухгалтера. Пусть на всех счетах находятся одинаковые суммы, например, по $100. Короткая транзакция в этот момент выполняет перевод $50 с одного счета на другой так, что общая сумма по всем счетам не меняется.
Длинная транзакция выполняет некоторый анализ по всей таблице, например, подсчитывает общую сумму денег на счетах клиентов банка для главного бухгалтера. Пусть на всех счетах находятся одинаковые суммы, например, по $100. Короткая транзакция в этот момент выполняет перевод $50 с одного счета на другой так, что общая сумма по всем счетам не меняется.
Чтение | --- | |
--- | Чтение | |
Запись | --- | |
--- | Запись | |
Фиксация транзакции | --- | |
--- | Фиксация транзакции | |
--- | Чтение | |
--- | Запись | |
Чтение | --- | |
Работа с прочитанными данными | --- | |
--- | Откат транзакции | |
Фиксация транзакции | --- | |
Чтение | --- | |
--- | Чтение | |
--- | Запись | |
--- | Фиксация транзакции | |
Повторное чтение | --- | |
Фиксация транзакции | --- | |
Выборка строк, удовлетворяющих условию (Отобрано n строк) |
--- | |
--- | Вставка новой строки, удовлетворяющей условию | |
--- | Фиксация транзакции | |
Выборка строк, удовлетворяющих условию (Отобрано n+1 строк) |
--- | |
Фиксация транзакции | --- | |
Чтение счета |
--- | |
--- | Снятие денег со счета |
|
--- | Помещение денег на счет |
|
--- | Фиксация транзакции | |
Чтение счета |
--- | |
Чтение счета |
--- | |
Фиксация транзакции | --- | |
Транзакция B пытается наложить блокировку: | ||
Транзакция A наложила блокировку: | S-блокировку | X-блокировку |
S-блокировку | Да | НЕТ|
X-блокировку | НЕТ
Таблица 1 Матрица совместимости S- и X-блокировок
Три случая, когда транзакция B не может блокировать объект, соответствуют трем видам конфликтов между транзакциями.
Доступ к объектам базы данных на чтение и запись должен осуществляться в соответствии со следующим протоколом доступа к данным:
Прежде чем прочитать объект, транзакция должна наложить на этот объект S-блокировку.
Прежде чем обновить объект, транзакция должна наложить на этот объект X-блокировку. Если транзакция уже заблокировала объект S-блокировкой (для чтения), то перед обновлением объекта S-блокировка должна быть заменена X-блокировкой.
Если блокировка объекта транзакцией B отвергается оттого, что объект уже заблокирован транзакцией A, то транзакция B переходит в состояние ожидания. Транзакция B будет находиться в состоянии ожидания до тех пор, пока транзакция A не снимет блокировку объекта.
X-блокировки, наложенные транзакцией A, сохраняются до конца транзакции A.
S-блокировка | --- | |
Чтение | --- | |
--- | S-блокировка | |
--- | Чтение | |
X-блокировка | --- | |
Ожидание… | X-блокировка | |
Ожидание… | Ожидание… | |
Ожидание… |
--- | S-блокировка | |
--- | Чтение | |
--- | X-блокировка | |
--- | Запись | |
S-блокировка | --- | |
Ожидание… | Откат транзакции (Блокировка снимается) |
|
S-блокировка | --- | |
Чтение | --- | |
Работа с прочитанными данными | --- | |
--- | --- | |
Фиксация транзакции | --- | |
S-блокировка | --- | |
Чтение | --- | |
--- | X-блокировка | |
--- | Ожидание… | |
Повторное чтение | Ожидание… | |
Фиксация транзакции (Блокировка снимается) |
Ожидание… | |
--- | X-блокировка | |
--- | Запись | |
--- | Фиксация транзакции (Блокировка снимается) |
|
S-блокировка строк, удовлетворяющих условию (Заблокировано n строк) |
--- | |
Выборка строк, удовлетворяющих условию (Отобрано n строк) |
--- | |
--- | Вставка новой строки, удовлетворяющей условию | |
--- | Фиксация транзакции | |
S-блокировка строк, удовлетворяющих условию (Заблокировано n+1 строка) |
--- | |
Выборка строк, удовлетворяющих условию (Отобрано n+1 строк) |
--- | |
Фиксация транзакции | --- | |
S-блокировка счета | --- | |
Чтение счета |
--- | |
--- | X-блокировка счета | |
--- | Снятие денег со счета |
|
--- | X-блокировка счета | |
--- | Ожидание… | |
S-блокировка счета | Ожидание… | |
Чтение счета | Ожидание… | |
S-блокировка счета | Ожидание… | |
Ожидание… | Ожидание… | |
Ожидание… |
Блокировка объекта | --- | |
--- | Блокировка объекта | |
Блокировка объекта | --- | |
Ожидание… | Блокировка объекта | |
Ожидание… | Ожидание… | |
Ожидание… |
Транзакция B пытается наложить на таблицу блокировку: | |||||
Транзакция A наложила на таблицу блокировку: | IS | S | IX | SIX | X |
IS | Да Да Да Да Нет|||||
S | Да Да Нет Нет Нет|||||
IX | Да Нет Да Нет Нет|||||
SIX | Да Нет Нет Нет Нет|||||
X | Нет Нет Нет Нет Нет
Таблица 2 Расширенная таблица совместимости блокировок Более точная формулировка протокола преднамеренных блокировок для доступа к данным выглядит следующим образом: При задании X-блокировки для сложного объекта неявным образом задается X-блокировка для всех дочерних объектов этого объекта. При задании S- или SIX-блокировки для сложного объекта неявным образом задается S-блокировка для всех дочерних объектов этого объекта. Прежде чем транзакция наложит S- или IS-блокировку на заданный объект, она должна задать IS-блокировку (или более сильную) по крайней мере для одного родительского объекта этого объекта. Прежде чем транзакция наложит X-, IX- или SIX-блокировку на заданный объект, она должна задать IX-блокировку (или более сильную) для всех родительских объектов этого объекта. Прежде чем для данной транзакции будет отменена блокировка для данного объекта, должны быть отменены все блокировки для дочерних объектов этого объекта. Понятие относительной силы блокировок можно описать при помощи следующей диаграммы приоритета (сверху - более сильные блокировки, снизу - более слабые):
Таблица 3 Диаграмма приоритета блокировокЗамечание. Протокол преднамеренных блокировок не определяет однозначно, какие блокировки должны быть наложены на родительский объект при блокировании дочернего объекта. Например, при намерении задать S-блокировку строки таблицы, на таблицу, включающую эту строку, можно наложить любую из блокировок типа IS, S, IX, SIX, X. При намерении задать X-блокировку строки, на таблицу можно наложить любую из блокировок типа IX, SIX, X.
Посмотрим, как разрешается проблема фиктивных элементов (фантомов) с использованием протокола преднамеренных блокировок для доступа к данным.
Транзакция A дважды выполняет выборку строк с одним и тем же условием. Между выборками вклинивается транзакция B, которая добавляет новую строку, удовлетворяющую условию отбора.
Транзакция B перед попыткой вставить новую строку должна наложить на таблицу IX-блокировку, или более сильную (SIX или X). Тогда транзакция A, для предотвращения возможного конфликта, должна наложить такую блокировку на таблицу, которая не позволила бы транзакции B наложить IX-блокировку. По таблице совместимости блокировок определяем, что транзакция A должна наложить на таблицу S, или SIX, или X-блокировку. (Блокировки IS недостаточно, т.к. эта блокировка позволяет транзакции B наложить IX-блокировку для последующей вставки строк).
S-блокировка таблицы ( с целью потом блокировать строки) - успешна | --- | |
S-блокировка строк, удовлетворяющих условию (Заблокировано n строк) |
--- | |
Выборка строк, удовлетворяющих условию (Отобрано n строк) |
--- | |
--- | IX-блокировка таблицы (с целью потом вставлять строки) - отвергается из-за конфликта с S-блокировкой, наложенной транзакцией A | |
--- | Ожидание… | |
--- | Ожидание… | |
S-блокировка строк, удовлетворяющих условию (Заблокировано n строк) |
Ожидание… | |
Выборка строк, удовлетворяющих условию (Отобрано n строк) |
Ожидание… | |
Фиксация транзакции - блокировки снимаются | Ожидание… | |
--- | IX-блокировка таблицы (с целью потом вставлять строки) - успешна | |
--- | Вставка новой строки, удовлетворяющей условию | |
--- | Фиксация транзакции | |
Проверка SCN счета Чтение счета |
--- | |
--- | X-блокировка счета | |
--- | Снятие денег со счета |
|
--- | X-блокировка счета | |
--- | Помещение денег на счет |
|
--- | Фиксация транзакции
(Снятие блокировок) |
|
Проверка SCN счета Чтение счета |
--- | |
Проверка SCN счета МЕНЬШЕ SCN счета.
Чтение старого варианта счета |
--- | |
Фиксация транзакции | --- | |
Да | Да | Да |
Да | Да | |
Да | ||
Таблица 4 Уровни изоляции стандарта SQL
Протокол называется двухфазным, потому что он характеризуется двумя фазами: 1 фаза - нарастание блокировок. Во время этой фазы накладываются блокировки, и производится работа с заблокированными объектами. 2 фаза - снятие блокировок. Во время этой фазы блокировки только снимаются. Работа с ранее заблокированными данными может продолжаться.
Работа транзакции может выглядеть приблизительно, как на рисунке:
Рисунок 1 Работа транзакции по протоколу двухфазной блокировки
На следующем рисунке показан пример транзакции, не подчиняющийся протоколу двухфазной блокировки:
Рисунок 2 Транзакция, не подчиняющаяся протоколу двухфазной блокировки
На практике, как правило, вторая фаза сводится к одной операции завершения транзакции (или отката транзакции) с одновременным снятием всех блокировок.
Если некоторая транзакция A не подчиняется протоколу двухфазной блокировки (и, следовательно, состоит не менее чем из двух операция блокирования и разблокирования), то всегда можно построить другую транзакцию B, которая при чередующемся выполнении вместе с A приводит к графику, не подлежащему упорядочению и неверному.
Транзакции, используемые в этом протоколе, не различаются по типам и считаются монопольными. Описанные выше протоколы доступа к данным с использованием S- и X-блокировок и протокол преднамеренных блокировок являются модификациями протокола двухфазной блокировки для случая, когда блокировки имеют различные типы.
Есвараном сформулирована следующая теорема:
Уровни изоляции
Уровни изоляции
Стандарт SQL не предусматривает понятие блокировок для реализации сериализуемости смеси транзакций. Вместо этого вводится понятие уровней изоляции. Этот подход обеспечивает необходимые требования к изолированности транзакций, оставляя возможность производителям различных СУБД реализовывать эти требования своими способами (в частности, с использованием блокировок или выделением версий данных).
Стандарт SQL предусматривает 4 уровня изоляции: READ UNCOMMITTED - уровень незавершенного считывания. READ COMMITTED - уровень завершенного считывания. REPEATABLE READ - уровень повторяемого считывания. SERIALIZABLE - уровень способности к упорядочению.
Если все транзакции выполняются на уровне способности к упорядочению (принятом по умолчанию), то чередующееся выполнение любого множества параллельных транзакций может быть упорядочено. Если некоторые транзакции выполняются на более низких уровнях, то имеется множество способов нарушить способность к упорядочению. В стандарте SQL выделены три особых случая нарушения способности к упорядочению, фактически именно те, которые были описаны выше как проблемы параллелизма: Неаккуратное считывание ("Грязное" чтение, незафиксированная зависимость). Неповторяемое считывание (Частный случай несовместного анализа). Фантомы (Фиктивные элементы - частный случай несовместного анализа).
Потеря результатов обновления стандартом SQL не допускается, т.е. на самом низком уровне изолированности транзакции должны работать так, чтобы не допустить потери результатов обновления.
Различные уровни изоляции определяются по возможности или исключению этих особых случаев нарушения способности к упорядочению. Эти определения описываются следующей таблицей: