Базы данных Oracle - статьи

         

Объектная привилегия SELECT разрешает блокирование


Вопрос. Нашим разработчикам (по крайней мере, нашим разработчикам группы технической поддержки) необходим доступ только для чтения (READ ONLY) к нашим промышленным базам данных, поэтому в каждой промышленной базе данных у нас есть роль с объектными привилегиями SELECT на каждую таблицу приложения и эта роль предоставляется разработчикам.

Несколько недель назад один из наших новых разработчиков заблокировал главную таблицу промышленной базы данных и приостановил всю пакетную обработку. Все администраторы базы данных клялись, что нельзя установить блокировку, имея только объектную привилегию SELECT, и мы потеряли много времени выясняя, как разработчик заблокировал таблицу. Мы открыли в Oracle запрос на техническую поддержку (TAR) и получили ответ: "Да, вы можете заблокировать строки, имея только объектную привилегию SELECT. Фактически, вы можете заблокировать всю таблицу оператором LOCK TABLE". Я хочу знать, сколько администраторов баз данных не знают об этом, и понять причину разрешения блокирования, когда нельзя модифицировать данные.

Ответ. Такое блокирование "известно" и допускается, я согласен, что немногие знают об этой особенности (в этом заключается основная причина моего решения о публикации этого вопроса – повысить уровень знаний). В описании оператора LOCK TABLE (Сервер Oracle Database. Справочное руководство по языку SQL), например, сказано: "Необходимые условия: таблица или представление должны принадлежать вашей собственной схеме либо вы должны иметь системную привилегию LOCK ANY TABLE или любую объектную привилегию на таблицу или представление. (выделено мною)

Заметим, эти необходимые условия не обязательно означают возможность модификации данных, но и возможность чтения данных указывает на возможность блокирования этих данных (обеспечивать их устойчивое состояние, "замораживать", запрещать модификацию). Так работает оператор SELECT ... FOR UPDATE. Итак, почему это правильно?

Следующий сценарий показывает, почему это правильно. Предположим, я имею доступ по чтению к таблице конференц-залов и доступ по чтению-записи к таблице расписания заседаний. Мне нужно зарезервировать конференц-зал X. Для того чтобы сделать это надежно (чтобы избежать наложений) и никто другой не мог зарезервировать конференц-зал X, я должен заблокировать этот конференц-зал (в таблице конференц-залов). Транзакция, в которой резервируются залы, – хранимая процедура, как это должно и быть – все попытки модификации таблицы расписания заседаний выполняются с помощью этой процедуры. Хранимая процедура блокирует этот конференц-зал (в таблице конференц-залов) оператором SELECT ... FOR UPDATE, чтобы никто другой не мог зарезервировать его.

Другой сценарий, который показывает, почему чтение может заблокировать таблицу: я хочу удалить строку из таблицы P, которая является родительской таблицей таблицы C. У меня есть доступ по чтению-записи к таблице P и доступ только по чтению к таблице С. Я пытаюсь удалить строку из таблицы P, но перед этим я должен заблокировать часть таблицы C (если существуют индексированные внешние ключи) или всю эту таблицу (если нет индекса по внешнему ключу).



Содержание раздела