Пессимистичный режим
В пессимистичном режиме предполагается, что к записям, которые будет использовать текущая транзакция, будут пытаться осуществить доступ другие транзакции. Поэтому перед любым изменением записей в БД (операторы UPDATE, DELETE) на объект накладывается блокировка, которая называется эксклюзивной (EXCLUSIVE). После успешного установления такой блокировки происходит изменение данных. В случае если объект до этого был заблокирован другим клиентским приложением (транзакцией), текущая транзакция переходит в состояние ожидания снятия блокировки. Выполнение ее будет временно приостановлено. Снятие блокировки осуществляется при завершении выполнения транзакции с помощью команды COMMIT или ROLLBACK. Установление такой блокировки позволяет предотвратить конфликт «потерянных изменений». Транзакция не переходит в состояние ожидания, если выставляет блокировку повторно на уже заблокированную для себя запись.
Ожидание блокировки не производится, если SQL-запрос выполняется с опцией NOWAIT, в этом случае клиентскому приложению возвращается соответствующий код завершения («Требуемая запись заблокирована»).
SQL-запрос UPDATE в СУБД ЛИНТЕР всегда выставляет «длинную» по времени блокировку на запись. Это означает снятие такой блокировки только в конце транзакции.
Конфликт «грязного чтения» автоматически предотвращается в СУБД за счет установления «коротких» блокировок на чтение (SHARED) при выполнении SELECT-запроса. Это означает проверку каждой записи, попавшей в выборку данных, на присутствие у нее блокировки на запись (EXCLUSIVE). В случае если хотя бы одна запись в выборке данных заблокирована, выполнение SELECT-запроса приостанавливается до снятия блокировки другой транзакцией.
Для предотвращения конфликта «неповторяемого чтения» необходимо наличие «длинных» блокировок на чтение для тех записей, к которым был получен доступ.
Существует еще один конфликт, который присущ механизму блокировок. Этот конфликт носит
название «фантомной записи». Механизм установления блокировки на одиночную
запись здесь не является решением. Заблокировать запись, которой нет на момент выполнения
транзакции, невозможно. Решение состоит в предварительном блокировании
всей таблицы с помощью SQL-запроса LOCK TABLE … IN SHARED|EXCLUSIVE MODE
.
В таблице 6 приведены конфликты, требуемые блокировки и используемые для этого SQL-запросы.
Конфликт | Необходимый протокол блокирования | Используемые SQL-запросы | Производительность СУБД и возможность совместного доступа |
---|---|---|---|
Потерянные изменения | Длинные блокировки на запись |
update … select … | Высокая |
Грязное чтение | Длинные блокировки на запись, короткие блокировки на чтение |
update … select … | Высокая |
Неповторяемое чтение | Длинные блокировки на запись и на чтение |
update … select … for browse|update или lock table in shared mode | Средняя |
Фантомные записи | Длинные блокировки на запись и на чтение, предотвращение вставки данных |
update … select … for browse|update или lock table in shared|exclusive mode | Низкая |
Пессимистичный режим обработки транзакций необходимо применять в тех случаях, когда требуется изменять записи, которые с высокой вероятностью могут также изменяться другими параллельно работающими транзакциями.
В СУБД ЛИНТЕР для упрощения работы в пессимистичном режиме существует модификация этого режима – режим AUTOCOMMIT. В этом случае оператор COMMIT автоматически выполняется после каждого DML-оператора (запроса манипулирования данными).
Примечание
Большое количество блокировок уменьшает производительность СУБД, т.к. необходимы вычислительные ресурсы для их поддержки. Поэтому в случае, если в одной таблице одновременно блокировано большое число записей, СУБД автоматически пытается блокировать сразу всю таблицу.