2012-03-22 22 views
12

Giả sử tôi có một số procedure được gọi là myproc. Đây là một quá trình phức tạp và tôi không thể cho phép hai trường hợp thực thi cùng lúc với proc.Có cách nào tốt nhất để tránh thực hiện quá trình nhiều hơn một lần trong Oracle không?

Thật sự tôi làm điều này bằng cách sử dụng dbms_application_info.set_module:

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

và xác minh trước khi chạy quá trình:

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

Ở cấp độ cơ sở dữ liệu, là có một cách tốt hơn để kiểm tra điều này?

+1

+1 câu hỏi hay, nhưng 'v $ session' không phải là duy nhất trên mô-đun, hành động để dễ bị sai. – Ben

+0

Xem thêm http://stackoverflow.com/questions/1053484/block-procedure-pl-sql-with-oracle – gavenkoa

Trả lời

9

Sử dụng dbms_lock.allocate_unique cùng với dbms_lock.request. Các ghi chú sử dụng nói:

Phiên họp đầu tiên để gọi ALLOCATE_UNIQUE với một tên khóa mới gây một khóa ID duy nhất được tạo ra và lưu trữ trong bảng dbms_lock_allocated. Cuộc gọi tiếp theo (thường là bởi các phiên khác) trả về ID khóa đã được tạo trước đó.

Tôi nghĩ rằng đây có thể là những gì bạn đang theo dõi.

+0

+1, đây là một ý tưởng tốt hơn nhiều so với tôi ...Tôi quá quen với việc thu thập tải siêu dữ liệu cùng một lúc như làm những việc khác. – Ben

+0

Tính năng thực sự thú vị. Cảm ơn! –

1

Bạn có thể tạo bảng processes. Bạn cũng đảm bảo rằng mỗi quy trình có một số loại số nhận dạng duy nhất - ví dụ: mã băm của owner, object_name từ dba_objects để bạn có thể tạo mã này theo cách động trong gói của mình.

Sau đó, bạn tạo một hàm thành lock each row individually khi quy trình được chạy.

Vì @Sergio đã chỉ ra trong các nhận xét, điều này sẽ không hoạt động nếu vì một lý do nào đó bạn cần thực hiện ở giữa quá trình - trừ khi, tất nhiên, bạn được chọn lại sau mỗi lần 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; 

Điều này có lợi cho việc khóa hàng đó trong processes cho bạn cho đến khi phiên hiện đang chạy thủ tục của bạn kết thúc.

Sau đó, bạn quấn này trong thủ tục của bạn:

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

Chừng nào mỗi thủ tục có một id duy nhất - bit quan trọng - thủ tục của bạn sẽ thoát sạch.


Điều này có thể không áp dụng trong trường hợp của bạn nhưng cách thông thường của tôi là sử dụng mod. Mặc dù nó không dừng lại 2 của cùng một tiến trình đang chạy nó đảm bảo rằng khi bạn có nhiều hơn 1 bạn chỉ chạy chúng trên các dữ liệu khác nhau. Một cái gì đó như sau:

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

Điều này đã xảy ra nếu bạn cần một số lý do cam kết ở giữa quá trình, phải không? –

+0

@ SérgioMichels, điểm tốt! Tôi sẽ thêm nó vào câu trả lời. – Ben

Các vấn đề liên quan