mat*_*lka 18 sql oracle locking blocking
我们试图解决的问题看起来像这样.
我们的解决方案是为卡分配状态,并存储它的预订日期.在预订卡时,我们使用"select for update"语句来完成.该查询查找可用的卡和很久以前保留的卡.
但是,我们的查询无法正常工作.
我准备了一个简化的情况来解释这个问题.我们有一个card_numbers表,充满了数据 - 所有行都有非空的id号.现在,让我们试着锁定其中一些.
-- 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中可能存在所需的锁定行为吗?如果是,那么我们做错了什么?什么是正确的解决方案?
Vin*_*rat 17
此博客说明中描述了您为FOR UPDATE SKIP LOCKED遇到的行为.我的理解是在WHERE子句之后评估FOR UPDATE子句.SKIP LOCKED就像一个额外的过滤器,可以保证在返回的行中没有一个被锁定.
您的语句在逻辑上等同于:查找第一行card_numbers并在未锁定时返回它.显然这不是你想要的.
这是一个小测试用例,可以重现您描述的行为:
SQL> CREATE TABLE t (ID PRIMARY KEY)
  2  AS SELECT ROWNUM FROM dual CONNECT BY LEVEL <= 1000;
Table created
SESSION1> select id from t where rownum <= 1 for update skip locked;
        ID
----------
         1
SESSION2> select id from t where rownum <= 1 for update skip locked;
        ID
----------
第二个选择不返回任何行.您可以使用游标解决此问题:
SQL> CREATE FUNCTION get_and_lock RETURN NUMBER IS
  2     CURSOR c IS SELECT ID FROM t FOR UPDATE SKIP LOCKED;
  3     l_id NUMBER;
  4  BEGIN
  5     OPEN c;
  6     FETCH c INTO l_id;
  7     CLOSE c;
  8     RETURN l_id;
  9  END;
 10  /
Function created
SESSION1> variable x number;
SESSION1> exec :x := get_and_lock;
PL/SQL procedure successfully completed
x
---------
1
SESSION2> variable x number;
SESSION2> exec :x := get_and_lock;
PL/SQL procedure successfully completed
x
---------
2
由于我明确地获取了游标,因此只返回一行(并且只锁定一行).
虽然其他答案已经充分解释了数据库中各种SELECT .. FOR UPDATE变体的情况,但我认为值得一提的是,Oracle不鼓励FOR UPDATE SKIP LOCKED直接使用并鼓励使用Oracle AQ:
http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_10002.htm#i2066346
我们Oracle AQ在我们的应用程序中使用,我可以确认,在经过一段陡峭的学习曲线后,它可以是一种非常方便的方式直接在数据库中处理生产者/消费者