2012-03-22 25 views
12

Załóżmy, że mam procedure o nazwie myproc. Jest to złożony proces i nie mogę pozwolić, aby dwie instancje wykonywały w tym samym czasie proces.Czy istnieje najlepszy sposób uniknięcia wykonywania procesu więcej niż jeden raz w Oracle?

Właściwie to zrobić za pomocą dbms_application_info.set_module:

procedure start_process is 
begin 
    dbms_application_info.set_module('myproc', 'running'); 
end; 

i zweryfikować przed uruchomieniem procesu:

select 'S' 
    from v$session v 
where v.module = 'myproc' 
    and v.action = 'running'; 

Na poziomie bazy danych, czy istnieje lepszy sposób to sprawdzić?

+1

+1 dobre pytanie, ale 'v $ sesja' nie jest unikalna na module, akcja więc łatwo byłoby się pomylić. – Ben

+0

Zobacz także http://stackoverflow.com/questions/1053484/block-procedure-pl-sql-with-oracle – gavenkoa

Odpowiedz

9

Zastosowanie dbms_lock.allocate_unique wraz z dbms_lock.request. W Uwagi dotyczące wykorzystania mówi:

Pierwsza sesja zadzwonić ALLOCATE_UNIQUE z nową nazwą zamka powoduje unikatowy identyfikator blokady być generowane i przechowywane w dbms_lock_allocated tabeli. Kolejne wywołania (zwykle przez inne sesje) zwracają poprzednio wygenerowany identyfikator blokady.

Myślę, że to może być to, o co prosisz.

+0

+1, jest to o wiele lepszy pomysł niż mój ...Jestem zbyt przyzwyczajony do zbierania mnóstwa metadanych w tym samym czasie, co inne rzeczy. – Ben

+0

Naprawdę interesująca funkcja. Dzięki! –

1

Możesz utworzyć tabelę processes. Zapewniasz również, że każdy proces ma jakiś unikalny identyfikator - na przykład skrót nazwy owner, object_name z dba_objects, aby można było go utworzyć dynamicznie w pakiecie.

Następnie należy utworzyć funkcję do lock each row individually w trakcie procesu.

Jak zaznaczył @ Sergio w komentarzach, to nie zadziała, jeśli z jakiegoś powodu musiałbyś popełnić błąd w trakcie procesu - chyba że, oczywiście, został ponownie wybrany po każdym zatwierdzeniu.

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; 

Ma to tę zaletę, że blokowanie wiersz processes dla was aż sesja, która jest obecnie prowadzenie postępowanie zostało zakończone.

Następnie owinąć to w procedurze:

-- 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; 

Dopóki każda procedura ma unikatowy identyfikator - ważną bit - Twój procedura wyjdzie czysty.


To nie może zastosować w danej sytuacji, ale mój normalny sposób to zrobić jest użycie mod. Chociaż nie zatrzymuje 2 tego samego procesu, zapewnia, że ​​gdy masz więcej niż 1, uruchamiasz je tylko na różnych danych. Coś takiego, co następuje:

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

To zepsuło się, jeśli potrzebujesz z jakiegoś powodu zatwierdzić w trakcie procesu, prawda? –

+0

@ SérgioMichels, dobry punkt! Dodam to do odpowiedzi. – Ben

Powiązane problemy