Oracle:如何限制“选择..以便更新跳过锁定”中的行数

时间:2019-02-19 12:35:03

标签: sql oracle

我有一张桌子:

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 :(得分:1)

我建议创建pl / sql函数并使用动态sql来控制锁定记录的数量。该锁在获取时获取。因此,获取N条记录会自动将其锁定。请记住,一旦完成事务(提交或回滚),记录便会解锁。 以下是锁定N条记录并以数组形式返回其ID值的示例(假设您已在表中添加了主键ID列):

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;