больше не потребуется. однако, сама транзакция продолжает блокировать другие элементы данных и после того, как блокировка элемента будет отменена. Хотя подобные действия внешне способствуют повышению уровня параллельности обработки в системе, они позволяют транзакциям оказывать влияние на работу друг друга, что может послужить причиной потери полной изолированности и атомарности транзакций.
Таблица 6.8 Пример неверного графика с использованием блокировок
Транзакция Т1 |
Транзакция Т2 |
начало |
|
чтение а1 |
|
а1=а1+100 |
|
запись а1 |
начало |
|
чтение а1 |
|
а1=а1*1.1 |
|
запись |
|
в1=в1*1.1 |
|
запись в1 |
чтение в1 |
commit |
в1=в1-100 |
|
запись в1 |
|
commit |
|
Для обеспечения упорядоченности следует использовать дополнительный протокол, определяющий моменты установки и снятия блокировки для каждой из транзакций. Самым известным из таких протоколов является метод двухфазной блокировки.
Двухфазная блокировка – транзакция выполняется по протоколу двухфазной блокировки, если в ней все операции блокирования предшествуют первой операции разблокирования.
В соответствии с основным правилом этого протокола, каждая транзакция может быть разделена на две фазы: фазу
176
нарастания, в которой выполняются все необходимые блокировки и не освобождается ни одного из элементов данных; и фазу сжатия, в которой освобождаются все выполненные ранее блокировки и не может быть затребовано ни одной новой. Как правило, транзакция устанавливает некоторые блокировки. выполняет, определенную обработку, после чего может затребовать установку дополнительных необходимых ей блокировок. Однако, она не может освободить ни одного из блоков, пока не достигнет той стадии, на которой ей уже не потребуется установка новых блокировок.
Если СУБД поддерживает операции расширения уровня блокировки, то их выполнение допускается только на фазе нарастания. Подобные действия могут перевести транзакцию в состояние ожидания на то время, пока другие транзакции отменят установленные ими блокировки для чтения данного элемента. Снижение уровня блокировки допускается только в фазе сжатия.
Пример устранения проблемы потерянного обновления (табл. 6.9)
Таблица 6.9 Пример устранения проблемы потерянного обновления
Время |
Транзакция Т3 |
Транзакция Т4 |
Поле а1 |
t1 |
|
начало |
100 |
t2 |
начало |
блокировка записи |
100 |
|
|
а1 |
|
t3 |
блокировка |
чтение а1 |
100 |
|
записи а1 |
|
|
t4 |
Ожидание |
а1=а1+100 |
100 |
t5 |
Ожидание |
запись а1 |
200 |
t6 |
Ожидание |
rollback/unlock(а1) |
200 |
|
|
(повторный прогон) |
|
t7 |
чтение а1 |
|
200 |
t8 |
а1=а1-100 |
|
200 |
t9 |
запись а1 |
|
190 |
t10 |
commit/ unlock(а1) |
|
190 |
177
Чтобы избежать потери выполненного обновления, транзакция Т2 должна предварительно установить блокировку счета а1 для записи. В момент запуска Т1 также потребует установить блокировку а1 для записи. Однако, поскольку этот элемент уже будет заблокирован, запрос Т1 удовлетворить не удастся, поэтому данная транзакция будет переведена в состояние ожидания освобождения Т2 необходимого ей элемента. Однако это произойдет только после фиксации результатов транзакции Т2 в БД.
Пример использования протокола двухфазной блокировки для устранения проблемы зависимости от нефиксированных результатов
Пример использования протокола двухфазной блокировки для устранения проблемы зависимости от нефиксированных результатов представлен в табл. 6.10.
Таблица 6.10 Пример использования протокола двухфазной блокировки
для устранения проблемы зависимости от нефиксированных результатов
Время |
Транзакция Т3 |
Транзакция Т4 |
Поле а1 |
t1 |
|
начало |
100 |
t2 |
|
блокировка записи а1 |
100 |
t3 |
|
чтение а1 |
100 |
t4 |
начало |
а1=а1+100 |
100 |
t5 |
блокировка |
запись а1 |
200 |
|
записи а1 |
|
|
t6 |
Ожидание |
rollback/unlock(а1) |
100 |
|
|
(повторный прогон, |
|
|
|
откат) |
|
t7 |
чтение а1 |
|
100 |
t8 |
а1=а1-100 |
|
100 |
t9 |
запись а1 |
|
90 |
t10 |
commit |
|
90 |
178
Во избежании возникновения данной ошибки Т4 должна предварительно установить блокировку а1 для записи. После выполнения отката этой транзакции выполненное ею обновление а1 будет отменено и этому элементу данных будет возвращено прежнее значение (100). В момент начала Т3 она тоже потребует блокировку для записи, но ее можно будет выполнить только после снятия блокировки Т4, поэтому Т3 переводится в состояние ожидания.
Пример использования протокола двухфазной блокировки для устранения проблемы несогласованной обработки
Пример использования протокола двухфазной блокировки для устранения проблемы несогласованной обработки представлен в табл. 6.11.
Таблица 6.11 Пример использования протокола двухфазной блокировки
для устранения проблемы несогласованной обработки
Время |
Транзакция |
Транзакция |
Поле |
Поле |
Поле |
Поле |
|
Т5 |
Т6 |
а1 |
в1 |
с1 |
Sum |
||
|
|||||||
t1 |
|
начало |
100 |
50 |
25 |
0 |
|
t2 |
начало |
Sum=0 |
100 |
50 |
25 |
0 |
|
t3 |
блокировка |
|
100 |
50 |
25 |
0 |
|
|
записи а1 |
|
|
|
|
|
|
t4 |
чтение а1 |
блокировка |
100 |
50 |
25 |
0 |
|
|
|
чтения а1 |
|
|
|
|
|
t5 |
а1=а1-100 |
Ожидание |
100 |
50 |
25 |
0 |
|
t6 |
запись а1 |
Ожидание |
90 |
50 |
25 |
0 |
|
t7 |
блокировка |
Ожидание |
90 |
50 |
25 |
0 |
|
|
записи с1 |
|
|
|
|
|
|
t8 |
чтение с1 |
Ожидание |
90 |
50 |
25 |
0 |
|
t9 |
с1=с1+10 |
Ожидание |
90 |
50 |
25 |
0 |
|
t10 |
запись с1 |
Ожидание |
90 |
50 |
35 |
0 |
|
t11 |
commit/unlo |
Ожидание |
90 |
50 |
35 |
0 |
|
|
ck(а1, с1) |
|
|
|
|
|
179
Продолжение табл. 6.11
Время |
Транзакция |
Транзакция |
Поле |
Поле |
Поле |
Поле |
|
Т5 |
Т6 |
а1 |
в1 |
с1 |
Sum |
||
|
|||||||
t12 |
|
чтение а1 |
90 |
50 |
35 |
0 |
|
t13 |
|
Sum = Sum |
90 |
50 |
35 |
90 |
|
|
|
+а1 |
|
|
|
|
|
t14 |
|
блокировка |
90 |
50 |
35 |
90 |
|
|
|
чтения в1 |
|
|
|
|
|
t15 |
|
чтение в1 |
90 |
50 |
35 |
90 |
|
t16 |
|
Sum = Sum |
90 |
50 |
35 |
140 |
|
|
|
+в1 |
|
|
|
|
|
t17 |
|
блокировка |
90 |
50 |
35 |
140 |
|
|
|
чтения с1 |
|
|
|
|
|
t18 |
|
чтение с1 |
90 |
50 |
35 |
140 |
|
t19 |
|
Sum = Sum |
90 |
50 |
35 |
175 |
|
|
|
+с1 |
|
|
|
|
|
t20 |
|
commit/unl |
90 |
50 |
35 |
175 |
|
|
|
ock(а1, |
|
|
|
|
|
|
|
в1,с1) |
|
|
|
|
Для устранения этой проблемы в Т5 операциям чтения должна предшествовать установка блокировки соответствующих элементов данных для записи, тогда как в Т6 операциям чтения должна предшествовать установка блокировки считываемых элементов данных для чтения.
Можно доказать, что если все транзакции в графике следуют двухфазному протоколу блокировки, этот график гарантированно будет конфликтно упорядоченным.
Каскадный откат
Однако, несмотря на то, что двухфазный протокол гарантирует упорядоченность, могут иметь место проблемы с интерпретацией допустимого момента выполнения отмены блокировок.
В табл. 6.12 транзакция Т14 выполняет блокировку счета а1 для записи, после чего суммирует его текущее значение с текущим значением в1, для которого устанавливается блокировка для чтения. Полученное новое значение заносится в
180