Вы можете создать таблицу processes
. Вы также гарантируете, что каждый процесс имеет своего рода уникальный идентификатор - например, хэш owner, object_name
из dba_objects
, чтобы вы могли динамически создавать его в своем пакете.
Затем вы создаете функцию для индивидуальной блокировки каждой строки при запуске процесса.
Как отметил @Sergio в комментариях, это не сработает, если по какой-то причине вам понадобится совершить коммит в середине процесса - если, конечно, вы не переизбрали после каждого коммита.
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;
Это имеет преимущество, заключающееся в том, что вы блокируете эту строку в processes
до тех пор, пока не завершится сеанс, в котором в данный момент выполняется ваша процедура.
Затем оберните это в своей процедуре:
-- 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;
Пока каждая процедура имеет уникальный идентификатор - важный бит - ваша процедура будет завершена корректно.
Это может не применяться в вашей ситуации, но мой обычный способ сделать это - использовать mod
. Хотя он не останавливает 2 запущенных процесса, он гарантирует, что при наличии более 1 вы будете запускать их только на разных данных. Примерно так:
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;