2012-03-07 47 views
6

是否有可能從一個進程連接到Oracle(通過OCI),然後從另一個進程連接到同一個數據庫會話?我可以從兩個oci客戶端維護一個Oracle會話嗎?

在我當前的應用程序中,有兩種訪問數據庫的方式:同步和異步(通過使用單獨的進程,通過套接字進行通信)。 問題是兩種方法實現不同的會話。

如果我嘗試在一個會話上進行更新,然後嘗試從另一個會話更新同一個表而不進行提交,我得到了OCI調用的掛起。

更糟糕的是,如果會話變量是從一個會話設置的 - 其他會話沒有看到它(這正是名稱所說的......)。

回答

6

如果您使用的是11g數據庫,則可以使用DBMS_XA package來允許一個會話加入第一個會話啓動的事務。正如Tim Hall deomonstrates所說,您可以在一個會話中開始一個事務,從另一個會話中加入該事務,並讀取在事務中進行的未提交的更改。然而不幸的是,這不會對會話變量有幫助(假設「會話變量」意味着具有會話範圍的包變量)。

創建包和表:

CREATE TABLE foo(col1 NUMBER); 

create or replace package pkg_foo 
as 
    g_var number; 
    procedure set_var(p_in number); 
end; 

create or replace package body pkg_foo 
as 
    procedure set_var(p_in number) 
    as 
    begin 
    g_var := p_in; 
    end; 
end; 

在第一節,我們啓動一個全局事務,設置包變量,並暫停全局事務前行插入表(允許另一個會話以恢復它)

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 l_xid dbms_xa_xid := dbms_xa_xid(1); 
    3 l_ret integer; 
    4 begin 
    5 l_ret := dbms_xa.xa_start(l_xid, dbms_xa.tmnoflags); 
    6 pkg_foo.set_var(42); 
    7 dbms_output.put_line('Set pkg_foo.g_var to ' || pkg_foo.g_var); 
    8 insert into foo values(42); 
    9 l_ret := dbms_xa.xa_end(l_xid, dbms_xa.tmsuspend); 
10* end; 
SQL>/
Set pkg_foo.g_var to 42 

PL/SQL procedure successfully completed. 

在會話2中,我們恢復全局事務,從表中讀取數據,讀取會話變量並結束全局事務。請注意,針對表的查詢會看到我們插入的行,但包變量更改不可見。

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 l_xid dbms_xa_xid := dbms_xa_xid(1); 
    3 l_ret integer; 
    4 l_col1 integer; 
    5 begin 
    6 l_ret := dbms_xa.xa_start(l_xid, dbms_xa.tmresume); 
    7 dbms_output.put_line('Read pkg_foo.g_var as ' || pkg_foo.g_var); 
    8 select col1 into l_col1 from foo; 
    9 dbms_output.put_line('Read COL1 from FOO as ' || l_col1); 
10 l_ret := dbms_xa.xa_end(l_xid, dbms_xa.tmsuccess); 
11* end; 
SQL>/
Read pkg_foo.g_var as 
Read COL1 from FOO as 42 

PL/SQL procedure successfully completed. 

要共享會話狀態的會話之間,將有可能使用global application context而不是使用包變量?如果要讀取數據庫表和會話狀態,可以將它與DBMS_XA包結合使用。

創建上下文和包getter和setter

CREATE CONTEXT my_context 
    USING pkg_foo 
    ACCESSED GLOBALLY; 

create or replace package pkg_foo 
as 
    procedure set_var(p_session_id in number, 
        p_in   in number); 
    function get_var(p_session_id in number) 
    return number; 
end; 

create or replace package body pkg_foo 
as 
    procedure set_var(p_session_id in number, 
        p_in   in number) 
    as 
    begin 
    dbms_session.set_identifier(p_session_id); 
    dbms_session.set_context('MY_CONTEXT', 'G_VAR', p_in, null, p_session_id); 
    end; 
    function get_var(p_session_id in number) 
    return number 
    is 
    begin 
    dbms_session.set_identifier(p_session_id); 
    return sys_context('MY_CONTEXT', 'G_VAR'); 
    end; 
end; 

在會話1,用於會話12345

begin 
    pkg_foo.set_var(12345, 47); 
end; 

現在,會話2設定爲47上下文變量G_VAR的值可以從上下文中讀取值

1* select pkg_foo.get_var(12345) from dual 
SQL>/

PKG_FOO.GET_VAR(12345) 
---------------------- 
        47 
+0

是的,「會話變量」表示包變量可以有會話範圍......所以這種方法不是解決方案。不管怎麼說,還是要謝謝你! – user581243 2012-03-07 15:18:58

+0

@ user581243 - 你有可能使用全局上下文而不是包變量?我用這種可能性更新了我的答案。 – 2012-03-07 15:39:01

+0

再次感謝。這很有趣。不過,我需要在C++代碼層解決這個問題,而不是在pl/sql代碼層。這不是一次性的情況,而是經常發生的事情。對於我們的應用程序來說,C++代碼的修改要比pl/sql代碼少得多,這就是爲什麼我不想將複雜性轉移到pl/sql代碼的原因。 – user581243 2012-03-08 07:54:08

相關問題