Is there a best way to avoid execution of process more than once in Oracle?

后端 未结 2 1025
无人及你
无人及你 2020-12-15 21:55

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.

相关标签:
2条回答
  • 2020-12-15 22:34

    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.

    0 讨论(0)
  • 2020-12-15 22:44

    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;
    
    0 讨论(0)
提交回复
热议问题