- •Алгоритмы совместного доступа к базам данных
- •Конкуренция, параллельность и согласованность
- •Алгоритмы Oracle, обеспечивающие параллельность и согласованность
- •Транзакции и взаимовлияние
- •Потери изменений
- •Черновое чтение
- •Повторяемое и неповторяемое чтение
- •Уровни изоляции
- •Isolation level read committed;
- •Алгоритмы блокирования Oracle
- •Автоматическое и явное блокирование
- •Уровни блокировок
- •Разделяемые блокировки
- •Исключающие блокировки
- •Блокировки dml
- •Строчные блокировки
- •Табличные блокировки
- •In exclusive mode
- •Повышение блокировок
- •Запросы и блокирование
- •Блокировки ddl
- •Исключающие блокировки ddl
- •Разделяемые блокировки ddl
- •Блокировки синтаксического анализа
- •Внутренние фиксаторы
- •Многовариантность
- •Системный номер изменения
- •Неблокирующие запросы
- •Многовариантность и согласованность чтения на уровне транзакций
- •Ошибки "слишком старый моментальный снимок"
- •Автоматическое функционирование системы
Табличные блокировки
Когда транзакция блокирует строку, она автоматически устанавливает блокировку таблицы, содержащей заблокированную строку, чтобы предотвратить возникновение конфликтов между операциями DDLи операциями обновления строк таблицы.
Например, при обновлении строки таблицы CUSTOMERSтранзакция устанавливает исключающую блокировку обновляемой строки. Кроме того, устанавливается и блокировка таблицыCUSTOMERSтак, что другие транзакции не могут изменить или удалить эту таблицу до завершения первой транзакции.
Разделяемые или исключающие блокировки таблиц могут устанавливаться во время обработки транзакций. Транзакция всегда устанавливает разделяемую блокировку таблицы при выполнении таких базовых операций DML, какINSERT,UPDATEиDELETE. Транзакция устанавливает исключающую блокировку таблицы только в том случае, когда эта транзакция содержит операторLOCKTABLE(блокировать таблицу), явно требующий исключающей блокировки. Например, когда в транзакции содержится приведенный ниже операторLOCKTABLE, она устанавливает исключающую блокировку таблицыCUSTOMERS:
LOCK TABLE customers
In exclusive mode
NOWAIT;
Здесь, как и в приведенном выше примере, ключевое слово NOWAITтакже передает управление пользователю, еслиOracleне может немедленно установить запрашиваемую табличную блокировку; без ключевого словаNOWAITтранзакция будет находиться в режиме ожидания до тех пор, пока не сможет установить исключающую блокировку таблицыCUSTOMERS.
В Oracleсуществуют различные уровни табличных блокировок, не упомянутые здесь: строчный разделяемый, строчный исключающий, разделяемый, разделяемый строчный исключающий и исключающий; каждый последующий тип табличной блокировки ограничивает более, чем предшествующий. Однако для простоты обсуждения были рассмотрены только основные различия между разделяемыми и исключающими блокировками, а также между блокировками на уровне строк и на табличном уровне.
Тупики
Тупик (deadlock) —это достаточно интересная ситуация, когда две транзакции не могут продолжать свою работу из-за того, что каждая из них запрашивает конфликтный набор блокировок. На рис. 2 показана ситуация, когда две транзакции взаимоблокированы.
На рис. 2 транзакция 1 устанавливает исключающую блокировку строки 1 таблицы и ждет, пока транзакция 2 снимет исключающую блокировку строки 2. Одновременно транзакция 2 устанавливает исключающую блокировку строки 2 и ждет, пока транзакция 1 снимет свою блокировку строки 1. В результате ни одна из этих транзакций не может продолжить работу, и они, оказавшись в тупике, ждут друг друга.
Транзакция
1
Имеет
блокировку
Ожидает
блокировки Таблица
Строка
#1 Строка
#2 … Транзакция
2
Ожидает
блокировки
Имеет
блокировку
Рис. 2. Две транзакции в тупике.
Тупики обычно возникают из-за неграмотно спроектированных транзакций. Для примера рассмотрим две такие транзакции, в каждой из которых содержится несколько операторов обновления данных таблицы PARTS. Каждая транзакция блокирует те строки, которые требуются другой транзакции, что приводит к тупику.
Транзакция 1 |
Транзакция 2 |
UPDATE sales.parts SET onhand = onhand - 10 WHERE id =1; |
UPDATE sales.parts SET onhand = onhand - 10 WHERE id =2; |
UPDATE sales.parts SET onhand = onhand - 10 WHERE id = 2; |
UPDATE sales.parts SET onhand = onhand - 10 WHERE id = 1; |
ждет, пока транзакция 2 снимет блокировку эл-та 2 |
ждет, пока транзакция 1 снимет блокировку эл-та 1 |
Недостаток обеих транзакций заключается в том, что в каждой из них содержится несколько несвязанных операторов обновления таблицы PARTS. Лучший вариант выполнения этих транзакций, устраняющий опасность тупика, — каждый раз обновлять таблицыPARTSв отдельной транзакции:
Транзакция 1 |
Транзакция 2 |
UPDATE sales.parts SET onhand = onhand - 10 WHERE id = 1; |
UPDATE sales, parts SET onhand = onhand - 10 WHERE id = 2; |
COMMIT; — блокировка строки снята |
COMMIT; — блокировка строки снята |
UPDATE sales.parts SET onhand = onhand - 10 WHERE id = 2; |
UPDATE sales.parts SET onhand = onhand - 10 WHERE id = 1; |
COMMIT; — блокировка строки снята |
COMMIT; — блокировка строки снята |
При такой структуре транзакций строчные блокировки, устанавливаемые во время каждой операции обновления, вскоре снимаются, что помогает избежать тупика.
УСТРАНЕНИЕ ТУПИКОВ.Когда транзакция выполняет оператор, вызывающий тупик,Oracleавтоматически распознает тупик и откатывает такой оператор.