【问题标题】:How to manage concurrent access in an sql procedure如何在 sql 过程中管理并发访问
【发布时间】:2019-04-17 10:15:36
【问题描述】:

我在我的 oracle 数据库中创建了一个 sql 过程,稍后我将在我的 c# 代码中调用它,

此过程的主要目标是遍历条目并在每个条目只应处理一次的条件下进行一些处理。

过程的主体看起来像这样。

FOR item IN
       ( SELECT * FROM
             (SELECT tab1.item1,tab1.item2,tab1.item3... 
               FROM tab1
               INNER JOIN tab2 ON ...condition...
               INNER JOIN TAB3 ON ...condition...

               WHERE ....main_condition=true;

               ORDER BY  tab1.item1
              )
          WHERE ROWNUM < in_param
        )
    LOOP

        .
        .
        .
        dbms_lock.sleep(4);
        .
        .
        .
        "set main_condition=false;" 
        commit;

    END LOOP;

当两个用户同时调用此过程时,我可以做什么,他们会得到一组不同的行。

谢谢。

【问题讨论】:

    标签: sql oracle plsql oracle11g


    【解决方案1】:

    “每个条目只应处理一次的条件。”

    这听起来像一个队列。通常的管理方法是使用 SELECT ... FOR UPDATE SKIP LOCKED 游标来实现队列。这里有一个非常重要的警告:您在问题中提到的 治疗 包括影响初始标准的内容,例如通过更新状态值或删除识别记录(或其他任何方式 - 不幸的是,问题对其细节含糊不清只能吸引同样含糊的答案)。

    所以它可能会锁定这样的东西(显然是指示性代码):

      cursor c_whatever is
         SELECT tab1.item1,tab1.item2,tab1.item3... 
               FROM tab1
               INNER JOIN tab2 ON ...condition...
               INNER JOIN TAB3 ON ...condition...
               WHERE tab1.main_condition = true     
               FOR UPDATE OF tab1.main_condition SKIP LOCKED ;
    
       begin
           open c_whatever;
    
           ….
           update tab1
           set tab1.main_condition = false
           where tab1.item1 = ….
    
           commit;
    

    悲观锁定将防止两个会话抓取同一行。更新提供 WHERE 子句的列将防止同一记录被多次处理。

    【讨论】:

    • 对 OP 要求的猜测不是很疯狂吗?他也可能选择在他的 proc 中删除或插入行。从任何地方我都可以关联这个问题以更新任何内容
    • @xing - 是的,这是一个猜测,但我奉承自己见多识广而不是狂野。如果“每个条目只应被处理一次”,那么必须有某种方法来跟踪哪些条目已被处理。我同意这可能不是更新,可能意味着删除或(不太可能)插入,但关键是 “处理” 必须影响驱动查询中使用的标准。我已经调整了这句话以使其更清晰 - 通过使其更模糊:-/
    【解决方案2】:

    当两个用户在 同时,它们得到一组不同的行。

    您可以修改查询并使用ORDER BY DBMS_RANDOM.VALUE 获取随机行。因此,您可以将查询修改为

    SELECT * FROM
                 (SELECT tab1.item1,tab1.item2,tab1.item3... 
                   FROM tab1
                   INNER JOIN tab2 ON ...condition...
                   INNER JOIN TAB3 ON ...condition...
    
                   WHERE ....main_condition=true;
    
                   ORDER BY  DBMS_RANDOM.VALUE
    

    【讨论】:

    • 不过,这并不能阻止两个用户获得同一行。
    • 它会在某种程度上..!!如果两个用户同时查询,出现同一行的可能性就很小了。可能低于 1%。不是吗?
    • 两个用户不会获得同一行的可能性较低,但不是 0。大概 OP 想要保证不会有多个用户选择任何行。
    • 那么在这种情况下,两个用户同时调用同一个过程的可能性也非常小,除此之外dbms_random.value 使情况更加紧张。当然这是其中一种方式,我想对此没有明确的解决方案
    • 感谢您的回答。但是条目应该按照给定的顺序处理,而不是随机的。
    猜你喜欢
    • 2022-10-01
    • 2019-06-23
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 2016-09-01
    • 1970-01-01
    相关资源
    最近更新 更多