Respostas:
Você pode fazer isso com DBMS_LOCK
um bloqueio exclusivo.
Veja o seguinte procedimento:
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;
/
Teste (sessão 1):
SQL> BEGIN
2 myproc();
3 END;
4 /
(Obviamente retorna quando DBMS_LOCK.sleep()
retorna).
Teste (sessão 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>
Obviamente você precisa GRANT EXECUTE ON DBMS_LOCK TO YOURUSER;
.
Use uma tabela de 'bloqueio'.
Quando o procedimento iniciar, verifique se há um valor conhecido na tabela, se presente, não vá mais longe e saia de proc. Caso contrário, escreva o valor na tabela, execute o procedimento, exclua o valor e saia normalmente.
Quando meus clientes têm uma solicitação que possui uma lógica comercial única como essa, tento mudar a questão e perguntar por que isso é necessário.
A melhor maneira de garantir que apenas uma cópia esteja em execução é não permitir que os usuários executem o procedimento. Se esse procedimento é tão especial, seu uso deve ser restrito ao dba / developers.
Outra maneira é executar este procedimento apenas como um trabalho. Adicione uma verificação no procedimento para ver se algum trabalho chamando isso está em execução. Se estiverem, pare o processamento e registre a ocorrência.