【问题标题】:can I maintain one Oracle session from two oci clients?我可以从两个 oci 客户端维护一个 Oracle 会话吗?
【发布时间】:2012-03-25 01:24:53
【问题描述】:

是否有可能从一个进程连接到 Oracle(通过 OCI),然后从另一个进程连接到同一个数据库会话?

在我当前的应用程序中,有两种方式可以访问数据库:一种同步方式和一种异步方式(通过使用单独的进程,通过套接字进行通信)。 问题是这两种方法实现了不同的会话。

如果我尝试例如一个会话的更新,然后尝试从另一个会话更新同一个表而不提交,我在 OCI 调用上挂起。

更糟糕的是,如果一个会话变量是从一个会话设置的 - 另一个会话看不到它(这正是名称所说的......)。

【问题讨论】:

    标签: c++ oracle oracle-call-interface


    【解决方案1】:

    如果您使用的是 11g 数据库,您可以使用DBMS_XA package 允许一个会话加入由第一个会话启动的事务。正如 Tim Hall 演示的那样,您可以在一个会话中启动事务,从另一个会话加入该事务,并读取在事务中所做的未提交更改。然而不幸的是,这对会话变量没有帮助(假设“会话变量”是指具有会话范围的包变量)。

    创建包和表:

    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;
    

    在会话 1 中,我们启动一个全局事务,设置包变量,并在暂停全局事务之前向表中插入一行(这允许另一个会话恢复它)

    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 的上下文变量 G_VAR 的值设置为 47

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

    现在,会话 2 可以从上下文中读取值

      1* select pkg_foo.get_var( 12345 ) from dual
    SQL> /
    
    PKG_FOO.GET_VAR(12345)
    ----------------------
                        47
    

    【讨论】:

    • 是的,“会话变量”是指具有会话范围的包变量......所以这种方法不是解决方案。还是谢谢!
    • @user581243 - 你有没有机会使用全局上下文而不是包变量?我用这种可能性更新了我的答案。
    • 再次感谢。这很有趣。但是我需要在 c++ 代码层解决这个问题,而不是在 pl/sql 代码层。这不是一次性的情况,而是经常发生的事情。对于我们的应用程序,c++ 代码的修改比 pl/sql 代码要少得多,这就是为什么我不想将复杂性转移到 pl/sql 代码。
    • 当每个会话使用不同的用户名连接时,有没有办法让 DBMS_XA 工作?
    猜你喜欢
    • 1970-01-01
    • 2013-01-19
    • 2020-07-29
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 2018-09-06
    • 1970-01-01
    • 2022-11-18
    相关资源
    最近更新 更多