È possibile creare una tabella processes
. Inoltre, assicurati che ogni processo abbia una sorta di identificatore univoco, ad esempio un hash dello owner, object_name
da dba_objects
in modo da poterlo creare dinamicamente nel pacchetto.
Quindi si crea una funzione su lock each row individually durante l'esecuzione di un processo.
Come ha sottolineato @Sergio nei commenti, ciò non funzionerebbe se per qualche motivo fosse necessario eseguire il commit nel bel mezzo del processo, a meno che, naturalmente, non venga selezionato nuovamente dopo ogni commit.
function locking (Pid) return number is
l_locked number := 0;
begin
select 1
into l_locked
from processes
where id = Pid
-- exit immediately if the proc is running
for update nowait
;
return l_locked;
exception when others then
return 0;
end;
Questo ha il vantaggio di bloccare quella riga nel processes
per voi fino a quando la sessione che è attualmente in esecuzione la vostra procedura è terminata.
È quindi avvolgere questo nella procedura:
-- if we failed to lock locking will have thrown an error
-- i.e. we have 0 here.
if locking(123) = 0 then
exit;
end if;
Finché ogni procedura ha un ID univoco - il bit importante - la vostra procedura uscirà in modo pulito.
Potrebbe non si applica nella vostra situazione, ma, il mio modo normale di fare questo è quello di utilizzare mod
. Sebbene non si fermi 2 dello stesso processo in esecuzione, garantisce che, quando ne hai più di 1, li esegui solo su dati diversi. Qualcosa di simile a quanto segue:
procedure my_procedure (PNumerator number, PDenominator number) is
cursor c_my_cursor (CNumerator number, CDenominator number) is
select columns
from my_table
where mod(ascii(substr(id, -1)), CDenominator) = CNumerator
;
begin
open c_my_cursor(PNumerator, PDenominator);
...
end;
+1 buona domanda, ma 'v $ session' non è univoco sul modulo, azione quindi sarebbe facile sbagliare. – Ben
Vedere anche http://stackoverflow.com/questions/1053484/block-procedure-pl-sql-with-oracle – gavenkoa