sql – Oracle选择更新行为

前端之家收集整理的这篇文章主要介绍了sql – Oracle选择更新行为前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我们试图解决的问题看起来像这样.

>我们有一张充满行代表桌子的桌子.预约交易的目的是将卡分配给客户端
>卡不能属于许多客户端
>经过一段时间(如果没有购买),必须将卡片退回到可用的复制池中
>许多客户可以同时进行预订
>我们使用Oracle数据库来存储数据,所以解决方案必须至少在Oracle 11上运行

我们的解决方案是为卡分配状态,并存储它的预约日期.在预订卡时,我们使用“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;

预期的行为是在两个会话中,我们得到一个满足查询条件的单独的不同行.

但是它不会这样工作.根据我们是否使用查询的“跳过锁定”部分,而不是行为变化:

>没有“跳过锁定” – 第二个会话被阻止 – 等待会话中的事务提交或回滚
>用“skip locked” – 第二个查询立即返回空结果集

所以,在这个漫长的介绍之后出现的问题.

在Oracle中可以使用所需的锁定方式吗?如果是,那我们做错了什么?什么是正确的解决方案?

解决方法

对于FOR UPDATE SKIP LOCKED遇到的行为已在 this blog note中进行了描述.我的理解是,在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

由于我明确地获取了游标,所以只会返回一行(只有一行被锁定).

猜你在找的MsSQL相关文章