首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Orace行锁用于在相同数据时进行更新

Orace行锁用于在相同数据时进行更新
EN

Stack Overflow用户
提问于 2019-08-12 21:18:43
回答 1查看 61关注 0票数 1

在我的表格中有5个优惠券代码,这些优惠券代码是相同的。如果10个客户的将同时申请优惠券代码FIRST5,那么我只需要更新优惠券为“锁定”和CUST_ID分别为5个客户。对于这种情况,我尝试了下面的SQL来锁定行,并让P_KEY在客户申请优惠券时更新状态和客户id。但是我无法为各自的客户更新最新的P_KEY。请指点正确的做法。

代码语言:javascript
运行
复制
SELECT P_KEY FROM
(SELECT P_KEY FROM COUPON_DETAILS WHERE COUPON_CODE = 'FIRST5' 
AND (STATUS  = 'UNLOCK' OR STATUS IS NULL))
WHERE ROWNUM = 1 FOR UPDATE;

P_KEY   COUPON_CODE     STATUS  CUST_ID
1       FIRST5          UNLOCK
2       FIRST5          UNLOCK
3       FIRST5          UNLOCK
4       FIRST5          UNLOCK
5       FIRST5          UNLOCK
EN

回答 1

Stack Overflow用户

发布于 2019-08-12 22:52:13

如果10个客户将同时应用优惠券代码FIRST5,那么我只需要为5个客户分别更新优惠券为“锁定”和CUST_ID。

我不知道有什么好的纯SQL方法可以做到这一点,因为FOR UPDATE子句不会影响查询的结果集。它只影响提取行的方式。

因此,您可能会考虑尝试以下操作:

代码语言:javascript
运行
复制
SELECT p_key 
FROM   coupon_details
WHERE  coupon_code = 'FIRST5'
AND    (status = 'UNLOCK' OR status IS NULL)
AND    rownum = 1
FOR UPDATE SKIP LOCKED;

可以合理地认为,这将导致Oracle读取所有匹配的coupon_details行,跳过任何锁定的行,然后在第一行之后停止。但是,只有在for update子句之后应用rownum=1条件时,这才能起作用。

不幸的是,它的工作方式是首先应用rownum=1条件,因为FOR UPDATE只在获取过程中发生。因此,最终发生的情况是,每个会话只查看第一行。如果未锁定,则返回该p_key。但是,如果第一行被锁定,则不返回任何数据。(或者,在您发布的查询中,不包括SKIP LOCKED,第一个会话之后的会话将等待。)

您真正需要做的是选择所有行,然后获取它们(跳过锁定的行),然后在第一行之后停止。

为此,您需要PL/SQL。下面是一个示例:

代码语言:javascript
运行
复制
DECLARE
  c SYS_REFCURSOR;
  l_key coupon_details.p_key%TYPE;
BEGIN
    -- Open a cursor on all the coupon details that are available to lock
    OPEN c FOR
        SELECT p_key 
        FROM   coupon_details
        WHERE  coupon_code = 'FIRST5'
        AND    (status = 'UNLOCK' OR status IS NULL)
        FOR UPDATE SKIP LOCKED;
    -- Fetch the first one.  The (FOR UPDATE SKIP LOCKED) will ensure that
    -- the one we fetch is not locked by another user and, after fetching,
    -- will be locked by the current session.
    FETCH c INTO l_key;
    -- Do what you need with the locked row.  In this example, we'll
    -- just print some debug messages.
    IF l_key IS NULL THEN
      DBMS_OUTPUT.PUT_LINE('No free locks!');
    ELSE
      DBMS_OUTPUT.PUT_LINE('Locked key ' || l_key);
    END IF;
    -- Close the cursor
    CLOSE c;
END;

..。在提交之前一定要使用UPDATE coupon_details SET status = 'LOCKED' WHERE p_key = l_key

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57461992

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档