2012-03-07 69 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