如何确保过程中只有一个副本在Oracle中运行?


10

我们需要确保特定过程的一个副本仅在Oracle中运行。如果它已经在运行,并且用户尝试打开另一个,则应该出错。

最好的方法是什么?

Answers:


12

您可以使用DBMS_LOCK和独占锁来做到这一点。

请参阅以下过程:

CREATE OR REPLACE PROCEDURE myproc
IS
  lockhandle VARCHAR2(128);
  retcode NUMBER;
BEGIN
  DBMS_LOCK.ALLOCATE_UNIQUE('myproclock',lockhandle);

  retcode:=DBMS_LOCK.REQUEST(lockhandle,timeout=>0, lockmode=>DBMS_LOCK.x_mode);

  IF retcode<>0
  THEN
    raise_application_error(-20000,'myproc is already running');
  END IF;

  /* sleep so that we can test with a 2nd execution */
  DBMS_LOCK.sleep(1000);

  retcode:=DBMS_LOCK.RELEASE(lockhandle);

END myproc;
/

测试(会话1):

SQL> BEGIN
  2  myproc();
  3  END;
  4  /

(当DBMS_LOCK.sleep()返回时显然返回)。

测试(会话2):

SQL> BEGIN
  2  myproc();
  3  END;
  4  /
BEGIN
*
ERROR at line 1:
ORA-20000: myproc is already running
ORA-06512: at "PHIL.MYPROC", line 12
ORA-06512: at line 2


SQL>

显然你需要GRANT EXECUTE ON DBMS_LOCK TO YOURUSER;


2

使用“锁定”表。

当过程开始时,检查表中的已知值(如果存在),则继续并退出proc。如果不存在,则将值写入表,执行过程,然后删除值并正常退出。


对于许多系统来说,这是一个很好的解决方案,但是我认为在这种特殊情况下,Phil的西装更好。
dezso 2012年

1

当我的客户提出的请求具有这种独特的业务逻辑时,我会尝试解决这个问题,并询问为什么需要这样做。

确保仅运行一个副本的最佳方法是完全不让用户执行该过程。如果此过程非常特殊,则应仅限dba /开发人员使用。

另一种方法是仅将此过程作为作业运行。在该过程中添加检查以查看是否有任何正在运行的作业正在运行。如果它们停止了,则停止进一步处理并记录发生的情况。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.