Проблема, которую мы пытаемся решить, выглядит так.
Наше решение - присвоить карте статус и сохранить дату резервирования. При бронировании карты мы делаем это с помощью инструкции «выбрать для обновления». Запрос ищет доступные карты и карты, которые были зарезервированы давным-давно.
Однако наш запрос работает не так, как ожидалось.
Я подготовил упрощенную ситуацию, чтобы объяснить проблему. У нас есть таблица card_numbers, полная данных - все строки имеют ненулевые идентификационные номера. Теперь давайте попробуем заблокировать некоторые из них.
-- first, in session 1
set autocommit off;
select id from card_numbers
where id is not null
and rownum <= 1
for update skip locked;
Здесь мы не фиксируем транзакцию, строка должна быть заблокирована.
-- later, in session 2
set autocommit off;
select id from card_numbers
where id is not null
and rownum <= 1
for update skip locked;
Ожидаемое поведение состоит в том, что в обоих сеансах мы получаем одну разную строку, удовлетворяющую условиям запроса.
Однако так не работает. В зависимости от того, используем ли мы часть запроса с пропуском блокировки или нет - поведение меняется:
Итак, после этого длинного вступления возникает вопрос.
Возможно ли в Oracle желаемое поведение блокировки? Если да, то что мы делаем не так? Какое решение будет правильным?