PL/SQL 过程的同步。如何保证一次只执行一个程序? [复制]

Posted

技术标签:

【中文标题】PL/SQL 过程的同步。如何保证一次只执行一个程序? [复制]【英文标题】:Synchronisation of PL/SQL procedure. How to guaranty execution of procedure only one at time? [duplicate] 【发布时间】:2013-06-26 13:40:27 【问题描述】:

某些 PL/SQL 过程需要花费大量时间进行评估(因为重新计算和更新大量数据)。

我想将评估此过程的执行上下文的数量限制为单个。

如果其他上下文执行它,则什么也不做......

但我不知道在 PL/SQL 代码中使用哪些原子操作。

注意:如果服务器在过程评估中间停止,我担心使用表行进行同步会导致数据库中的状态不一致...

【问题讨论】:

还有***.com/questions/1053484/… 看看 DBMS_LOCK。您可以创建您拥有的名称锁,然后在您的 PL/SQL 包中获取该锁。如果包执行的另一个实例运行,锁调用将失败。与锁定表或表中的行相比,这更有效且更简洁。 【参考方案1】:

您可以使用DBMS_LOCK.request 生成唯一的锁句柄。只有一个会话可以同时持有此锁。如果会话的数据库重启意外结束,锁会自动释放。

您在请求锁时决定是否在提交期间保持锁。

这是一个例子:

SQL> CREATE OR REPLACE PROCEDURE serial IS
  2     l_lock_handle  VARCHAR2(128 BYTE);
  3     l_lock_request INTEGER;
  4  BEGIN
  5     dbms_lock.allocate_unique(lockname => 'MY_SERIAL_PROC',
  6                               lockhandle => l_lock_handle);
  7     l_lock_request := dbms_lock.request(lockhandle => l_lock_handle,
  8                                         timeout => 5,
  9                                         release_on_commit => FALSE);
 10     CASE l_lock_request
 11        WHEN 0 THEN
 12           NULL; -- success
 13        WHEN 1 THEN
 14           raise_application_error(-20002, 'lock already reserved');
 15        ELSE
 16           raise_application_error(-20001, 'Lock error: ' || l_lock_request);
 17     END CASE;
 18     BEGIN
 19        ---------- serialized block of code           ----------
 20        ---------- (lock will be kept accross commit) ----------
 21        dbms_lock.sleep(30);
 22        ---------- End of serialized code             ----------
 23     EXCEPTION
 24        WHEN OTHERS THEN -- release lock in case of uncatched error
 25           l_lock_request := dbms_lock.release(lockhandle => l_lock_handle);
 26           RAISE;
 27     END;
 28     l_lock_request := dbms_lock.release(lockhandle => l_lock_handle);
 29  END;
 30  /

Procedure created

我将同时运行两个会话:

Session A> exec serial;                

                                       Session B> -- Before session A ends
                                       Session B> exec serial;

                                       ERROR at line 1:
                                       ORA-20002: lock already reserved
                                       ORA-06512: at "APPS.SERIAL", line 13
                                       ORA-06512: at line 1


PL/SQL procedure successfully completed

                                       Session B> -- After session A ends
                                       Session B> exec serial;

                                       PL/SQL procedure successfully completed.

【讨论】:

+1 不错!不知道那个。我猜如果块失败,事务会自动回滚并释放锁? @haki:不会,事务不会回滚,锁也不会释放!我可能应该在“finally”块中添加一个版本,因为这将是您正确的预期行为。 谢谢 - 学到了一些东西。也许编辑带有exception when others 子句的帖子以释放锁定。

以上是关于PL/SQL 过程的同步。如何保证一次只执行一个程序? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

PL / SQL中的当前状态

PL_sql如何执行oracle存储过程

如何在pl / sql中同时在不同会话中执行存储过程

PL/SQL Developer 中执行过程的问题

如何确定通用 PL/SQL 过程的参数(执行 group by 子句)?

如何执行pl/sql过程