Я не уверен на 100%, что происходит с Select for update
, возвращающим те же строки. Но это моя текущая ментальная модель того, что происходит:
Первый выбор / поток выбирает и блокирует строки. Второй выбирает те же строки и пытается получить блокировку, но не может, пока первая не зафиксируется. Я ожидал, что он увидит обновленную версию строки и не вернет ее. Но в любом случае вы блокируете, что, кажется, не имеет особого смысла для вашего случая.
Блокировка optimisti c тоже не поможет, потому что блокировка optimisti c не является блокировкой в общепринятый смысл. Он позволяет обрабатывать данные и только при их обратной записи в базу данных проверяет, что никто другой не изменил их. Насколько я могу судить, это не то, что вам нужно.
Что вам нужно сделать, так это отметить книги как обрабатываемые заданным процессом. Это можно сделать с помощью следующего процесса:
Обновить первые N строк как обрабатываемые текущим заданием. Подойдет следующий оператор:
update books b
set book_status = 'processed by ' || :jobname
where id in (
select id
from books b2
where book_status = 'available'
ORDER BY name
NEXT 10 ROWS ONLY
)
Выполнить это в отдельной транзакции, которая немедленно фиксируется. Пружины TransactionTemplate
часто лучше подходят для таких недолговечных транзакций.
Теперь основная часть задания может выбирать отмеченные строки без вмешательства других заданий, пока не будет установлено book_status
на unavailable
или обратно на available
, если вы хотите снова сделать книгу доступной для других заданий.
Если обработка происходит в одной транзакции, вы сможете получить в основном тот же эффект с SELECT FOR UPDATE SKIP LOCKED
Этот вопрос касается той же основной c проблемы, но с немного другой точки зрения.