我可以从两个oci客户端维护一个Oracle会话吗?
有可能从一个进程连接到Oracle(通过OCI),然后从另一进程连接到同一个数据库会话。
Is there a possibility to connect to Oracle (via OCI) from one process, then connect on the same database session from another process?
在我当前的应用程序中,有两种方法来访问数据库:同步和异步(通过使用单独的进程,通过套接字进行通信)。
问题是两种方法实现不同的会话。
In my current app, there are two ways to access the database: a synchronous one and an asynchronous one (by using a separate process, communicating via sockets). The problem is the two methods implement distinct sessions.
如果我尝试在一个会话上更新,然后尝试从其他会话更新相同的表,而不提交,我在OCI调用上挂起。
If I attempt e.g. an update on one session, then try to update the same table from the other session without committing, I get a hang on the OCI call.
更糟糕的是,如果会话变量
Worse, if a session variable is set from one session - the other session does not see it (which is exactly what the name says...).
如果您使用的是11g数据库,则可以使用 DBMS_XA
package 允许一个会话加入由第一个会话启动的事务。正如Tim Hall演示,您可以在一个会话中启动事务,从另一个会话加入该事务,并读取事务中提交的未提交的更改。不幸的是,这不会帮助会话变量(假设会话变量是指具有会话范围的包变量)。
If you are using an 11g database, you could use the DBMS_XA
package to allow one session to to join a transaction started by the first session. As Tim Hall deomonstrates, you can start a transaction in one session, join that transaction from another session, and read the uncommitted changes made in the transaction. Unfortunately, however, that is not going to help with session variables (assuming that "session variable" means package variable that have session scope).
创建包和表:
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中,我们启动一个全局事务,设置包变量,
In Session 1, we start a global transaction, set the package variable, and insert a row into the table before suspending the global transaction (which allows another session to resume it)
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中,我们恢复全局事务,从表中读取,读取会话变量,结束全局事务。请注意,对表的查询会看到我们插入的行,但是包变量更改不可见。
In session 2, we resume the global transaction, read from the table, read the session variable, and end the global transaction. Note that the query against the table sees the row we inserted but the package variable change is not visible.
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.
要在会话之间共享会话状态,可以使用全局应用程序上下文而不是使用程序包变量?如果您想读取数据库表和会话状态,您可以将它与 DBMS_XA
包结合使用。
To share session state between the sessions, would it be possible to use a global application context rather than using package variables? You could combine that with the DBMS_XA
packages if you want to read both database tables and session state.
创建上下文和包含getter和setter的包
Create the context and the package with the getter and 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;
to 47 for session 12345
In session 1, set the value of the context variable G_VAR
to 47 for session 12345
begin
pkg_foo.set_var( 12345, 47 );
end;
现在,会话2可以从上下文中读取值
Now, session 2 can read the value from the context
1* select pkg_foo.get_var( 12345 ) from dual
SQL> /
PKG_FOO.GET_VAR(12345)
----------------------
47