在我的表格中有5个优惠券代码,这些优惠券代码是相同的。如果10个客户的将同时申请优惠券代码FIRST5,那么我只需要更新优惠券为“锁定”和CUST_ID分别为5个客户。对于这种情况,我尝试了下面的SQL来锁定行,并让P_KEY在客户申请优惠券时更新状态和客户id。但是我无法为各自的客户更新最新的P_KEY。请指点正确的做法。
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
发布于 2019-08-12 22:52:13
如果10个客户将同时应用优惠券代码FIRST5,那么我只需要为5个客户分别更新优惠券为“锁定”和CUST_ID。
我不知道有什么好的纯SQL方法可以做到这一点,因为FOR UPDATE
子句不会影响查询的结果集。它只影响提取行的方式。
因此,您可能会考虑尝试以下操作:
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。下面是一个示例:
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
。
https://stackoverflow.com/questions/57461992
复制相似问题