Подтвердить что ты не робот

Есть ли лучший способ избежать выполнения процесса более одного раза в 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';

На уровне базы данных есть лучший способ проверить это?

4b9b3361

Ответ 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;