Есть ли лучший способ избежать выполнения процесса более одного раза в Oracle?
Скажем, что у меня есть procedure
, называемый myproc
. Это сложный процесс, и я не могу позволить двум экземплярам одновременно выполнять proc.
На самом деле я делаю это с помощью dbms_application_info.set_module
:
procedure start_process is
begin
dbms_application_info.set_module('myproc', 'running');
end;
и проверьте перед запуском процесс:
select 'S'
from v$session v
where v.module = 'myproc'
and v.action = 'running';
На уровне базы данных есть лучший способ проверить это?
Ответы
Ответ 1
Используйте dbms_lock.allocate_unique вместе с dbms_lock.request, В примечаниях говорится:
Первый сеанс для вызова ALLOCATE_UNIQUE с новым именем блокировки вызывает уникальный идентификатор блокировки, который должен быть сгенерирован и сохранен в таблице dbms_lock_allocated. Последующие вызовы (обычно с помощью других сеансов) возвращают ранее созданный идентификатор блокировки.
Я думаю, что это может быть то, что вам нужно.
Ответ 2
Вы можете создать таблицу 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;