Как я могу выбрать и заблокировать строку для каждого потока в Oracle? (Есть рабочий пример для PostgreSQL) - PullRequest
0 голосов
/ 10 января 2019

У меня есть стол products:

id  name count description          status  expiration_date
1   Hz    1    Test1537208034036    NEW     2018-09-17
2   Pz    3    Test1537209516789    NEW     2018-10-17
3   Uz    7    Test1537210999618    NEW     2018-08-17
4   Mz    12   Test1537212483215    NEW     2018-11-17

Мне нужно выбрать строку с наибольшим счетом и статусом = NEW . Для этого я могу написать на postgreSQL:

Select * 
from products 
where status = 'NEW' 
order by count desc 
LIMIT 1

Но если 4 потока начнут делать это, выберите - каждый поток получит равную строку (с количеством = 12). Я могу переписать этот запрос, и он отлично работает:

Select * 
from products 
where status = 'NEW' 
order by count desc 
LIMIT 1 
for update of products skip locked 

Но я не могу повторить это в Oracle .

SELECT p.* 
from (
  Select * 
  from products 
  where status = 'NEW' 
  order by count desc
) p 
WHERE p.ROWNUM = 1 
FOR UPDATE OF products SKIP LOCKED

Oracle не имеет LIMIT 1 и rownum работает по-другому. Мне нужно получить первый ряд из заказанной таблицы (order by desc) but this row not locked.

Как мне повторить логику, подобную PostgreSQL. Может быть, мой выбор неверен.

Если ты выглядишь проще, вот чего я хочу - у меня есть таблица и много тем. Мне нужно, чтобы каждый поток получал самую старую строку из базы данных (или наибольшее количество), и только она одна. другие темы не должны получать его. Следующий поток должен получить самую старую (или самую большую) строку, следующую за ним.

1 Ответ

0 голосов
/ 10 января 2019

Предлагаю использовать динамический sql. Блокировка получается во время получения. Вы получаете одну запись, и она блокируется одновременно. Имейте в виду, что запись разблокируется после завершения транзакции - фиксация или откат.

Вот краткий пример функции, которая возвращает следующий products.id для вашего потока.

create or replace function get_next_unlocked_id
return number
is
  cRefCursor sys_refcursor;
  rRecord    products%rowtype;
begin
  -- open cursor. No locks so far
  open cRefCursor for 
    'select * from products '||
    'where status = ''NEW'' '||
    'order by count desc '||
    'for update skip locked';

  -- we fetch and lock at the same time one record
  fetch cRefCursor into rRecord;

  -- close cursor
  close cRefCursor;

  -- return ID or any other attribute(s)
  return rRecord.id; 

end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...