Możesz utworzyć tabelę processes
. Zapewniasz również, że każdy proces ma jakiś unikalny identyfikator - na przykład skrót nazwy owner, object_name
z dba_objects
, aby można było go utworzyć dynamicznie w pakiecie.
Następnie należy utworzyć funkcję do lock each row individually w trakcie procesu.
Jak zaznaczył @ Sergio w komentarzach, to nie zadziała, jeśli z jakiegoś powodu musiałbyś popełnić błąd w trakcie procesu - chyba że, oczywiście, został ponownie wybrany po każdym zatwierdzeniu.
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;
Ma to tę zaletę, że blokowanie wiersz processes
dla was aż sesja, która jest obecnie prowadzenie postępowanie zostało zakończone.
Następnie owinąć to w procedurze:
-- 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;
Dopóki każda procedura ma unikatowy identyfikator - ważną bit - Twój procedura wyjdzie czysty.
To nie może zastosować w danej sytuacji, ale mój normalny sposób to zrobić jest użycie mod
. Chociaż nie zatrzymuje 2 tego samego procesu, zapewnia, że gdy masz więcej niż 1, uruchamiasz je tylko na różnych danych. Coś takiego, co następuje:
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 dobre pytanie, ale 'v $ sesja' nie jest unikalna na module, akcja więc łatwo byłoby się pomylić. – Ben
Zobacz także http://stackoverflow.com/questions/1053484/block-procedure-pl-sql-with-oracle – gavenkoa