Oracle: как ограничить количество строк в «выберите .. для обновления пропустить заблокирован» - PullRequest
0 голосов
/ 19 февраля 2019

У меня есть таблица:

table foo{
  bar number,
  status varchar2(50)
}

У меня есть несколько потоков / хостов, каждый из которых использует таблицу.Каждый поток обновляет статус, т.е. пессимистически блокирует строку.

В Oracle 12.2.

select ... for update skip locked, кажется, делает эту работу, но я хочу ограничить количество строк.Новый FETCH NEXT звучит правильно, но я не могу понять правильный синтаксис:

SELECT * FROM foo ORDER BY bar 
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY 
FOR UPDATE SKIP LOCKED;

Какой самый простой способ добиться этого, то есть с минимальным кодом 1 (в идеале без pl /функция sql)

Я хочу что-то вроде этого:

select * from (select * from foo 
               where status<>'baz' order by bar
) where rownum<10 for update skip locked

PS 1. Мы рассматриваем отход от оракула. ​​

1 Ответ

0 голосов
/ 19 февраля 2019

Я предлагаю создать функцию pl / sql и использовать динамический sql для контроля количества заблокированных записей.Блокировка получается во время получения.Таким образом, выборка N записей автоматически блокирует их.Имейте в виду, что записи разблокируются после завершения транзакции - фиксация или откат.Ниже приведен пример блокировки N записей и возврата их значений идентификаторов в виде массива (предположим, что вы добавили столбец идентификатора первичного ключа в таблицу):

create or replace function get_next_unlocked_records(iLockSize number)
return sys.odcinumberlist
is
  cRefCursor sys_refcursor;
  aIds       sys.odcinumberlist := sys.odcinumberlist();
begin
  -- open cursor. No locks so far
  open cRefCursor for 
    'select id from foo '||
    'for update skip locked';

  -- we fetch and lock at the same time 
  fetch cRefCursor bulk collect into aIds limit iLockSize;

  -- close cursor
  close cRefCursor;

  -- return locked ID values, 
  -- lock is kept until the transaction is finished
  return aIds; 

end;

sys.odcinumberlist - встроенный массивчисел.

Вот тестовый скрипт для запуска в db:

declare 
  aRes sys.odcinumberlist;
begin
  aRes := get_next_unlocked_records(10);
  for c in (
    select column_value id
    from   table(aRes)
  ) loop
    dbms_output.put_line(c.id);
  end loop;
end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...