假设我有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';
在数据库级别,是否有更好的方法来检查它?
答案 0 :(得分:10)
使用dbms_lock.allocate_unique和dbms_lock.request。 使用说明说:
使用新锁名称调用ALLOCATE_UNIQUE的第一个会话导致 要生成并存储在dbms_lock_allocated表中的唯一锁ID。 后续调用(通常由其他会话)返回先前生成的锁ID。
我认为这可能就是你所追求的目标。
答案 1 :(得分:1)
您可以创建表格processes
。您还要确保每个进程都有某种唯一标识符 - 例如来自dba_objects
的owner, object_name
的哈希值,以便您可以在包中动态创建它。
然后在运行流程时创建一个lock each row individually函数。
正如@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;
只要每个程序都有一个唯一的ID - 重要的一点 - 您的程序就会彻底退出。
它可能不适用于您的情况但是,我这样做的正常方法是使用mod
。虽然它不会停止运行相同进程的2个,但确保当您有多个进程时,只能在不同的数据上运行它们。如下所示:
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;