2011-11-02 61 views
2

我是一位使用舊版Oracle數據庫的.Net Web開發人員。在過去,我一直使用像nHibernate這樣的orm工具,但是這裏所有的數據庫通信都需要通過存儲過程完成。我們的dba要求我們將一些管理信息傳遞給我們所調用的每個過程,包括最終用戶的用戶名/域名/ IP。這些數據然後用於調用另一個存儲過程,每次調用過程時都會記錄使用情況信息。Oracle存儲過程基準測試

我不太熟悉Oracle或Pl/Sql,我試圖用乾淨的方式編寫我的.Net代碼,以儘可能地滿足最佳實踐。在我看來,這種將額外數據傳遞給每個過程的過程在.Net和Oracle兩端都是混亂和乏味的。

有沒有人知道有更好的方法來完成dba的目標而沒有所有的開銷?或者這是一種我應該習慣的做事的標準方式。

+0

這絕對不是標準,絕對不是一個好辦法。你需要傳遞什麼樣的「額外」數據(即用戶名等)? – Icarus

+0

是的,我們需要通過用戶名,域名,IP地址。 – zaq

回答

3

我會使用上下文而不是傳遞額外的參數到每個存儲過程調用。上下文是存儲任意會話級別狀態數據的便利場所,存儲過程可以全部引用該數據。

例如,我可以爲我的應用程序創建一個上下文MYAPP_CTX並創建一個簡單的包,讓我可以在上下文中設置任何我想要的值。

SQL> create context myapp_ctx using ctx_pkg; 

Context created. 

SQL> create package ctx_pkg 
    2 as 
    3 procedure set_value(p_key in varchar2, p_value in varchar2); 
    4 end; 
    5/

Package created. 

SQL> create package body ctx_pkg 
    2 as 
    3 procedure set_value(p_key in varchar2, p_value in varchar2) 
    4 as 
    5 begin 
    6  dbms_session.set_context('MYAPP_CTX', p_key, p_value); 
    7 end; 
    8 end; 
    9/

Package body created. 

當應用程序從連接池獲取連接時,它只需設置所有上下文信息一次。然後在同一會話

SQL> begin 
    2 ctx_pkg.set_value('USERNAME', 'JCAVE'); 
    3 ctx_pkg.set_value('IP_ADDRESS', '192.168.17.34'); 
    4 end; 
    5/

PL/SQL procedure successfully completed. 

後續調用和查詢可以只要求任何值存儲在上下文中。

SQL> select sys_context('MYAPP_CTX', 'USERNAME') 
    2 from dual; 

SYS_CONTEXT('MYAPP_CTX','USERNAME') 
-------------------------------------------------------------------------------- 
JCAVE 

實際上,你幾乎肯定要在clear_context程序添加到調用dbms_session.clear_context('MYAPP_CTX')以清除任何值已在上下文中進行了設置,當連接返回到連接池,以避免無意中允許範圍內的包來自一個會話的信息泄漏到另一個會話中。您可能還會設計包含單獨程序的程序包,以便設置和獲取至少常用密鑰(用戶名,IP地址等),而不是使用'USERNAME'對多個位置進行硬編碼。爲了簡單起見,我使用了一個通用的set_value方法。

+0

我可能會漏掉一些東西,但如果多個用戶同時訪問會話,似乎可能會有潛在的併發問題。例如,如果第二個用戶會話設置用戶名/ IP,然後第一個用戶會話調用要求輸入用戶名的存儲過程,會發生什麼情況。它會不會返回第二個會話設置的用戶名? – zaq

+1

@zaq - 上下文是(默認情況下)本地數據庫會話。一次只有一個用戶可以使用數據庫會話(儘管多箇中間層會話可能會在從連接池檢索連接時隨時分享數據庫會話)。這就是爲什麼當連接返回到連接池,從連接池中取出連接或兩者都連接時,通常需要清除上下文。兩個數據庫會話將在其各自的上下文中具有單獨的數據副本 - 一個會話將不會在其他會話的上下文中看到該信息。 –

+0

很高興知道,謝謝! – zaq