Let\'s say that I have a procedure
called myproc
. This is a complex process and i cannot allow two instances executing at the same time the proc.
Use dbms_lock.allocate_unique along with dbms_lock.request. The usage notes says:
The first session to call ALLOCATE_UNIQUE with a new lock name causes a unique lock ID to be generated and stored in the dbms_lock_allocated table. Subsequent calls (usually by other sessions) return the lock ID previously generated.
I think this could be what you're after.
You can create a table processes
. You also ensure that each process has some sort of unique identifier - for instance a hash of the owner, object_name
from dba_objects so you could create this dynamically in your package.
You then create a function to lock each row individually as a process is run.
As @Sergio pointed out in the comments this would not work if for some reason you needed to commit in the middle of the process - unless, of course, you re-selected after each 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;
This has the benefit of locking that row in processes
for you until the session that's currently running your procedure has finished.
You then wrap this in your procedure:
-- 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;
As long as each procedure has a unique id - the important bit - your procedure will exit cleanly.
It might not apply in your situation but, my normal way of doing this is to use mod. Though it doesn't stop 2 of the same process running it does ensure that when you have more than 1 you only run them on different data. Something like as follows:
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;