如何在SQL过程中管理并发访问

时间:2019-04-17 10:15:37

标签: sql oracle plsql oracle11g

我已经在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;

当两个用户同时调用此过程时,他们将获得不同的行集,该怎么办?

谢谢。

2 个答案:

答案 0 :(得分:2)

  

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

这听起来像一个队列。通常的管理方式是使用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子句的列将防止同一记录被多次处理。

答案 1 :(得分:1)

  

当两个用户在   同时,他们获得了不同的行集。

您可以修改查询并使用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