Hvis du bruger en 11g-database, kan du bruge DBMS_XA pakke
for at tillade en session at deltage i en transaktion startet af den første session. Som Tim Hall demonstrerer, kan du starte en transaktion i én session, deltage i den transaktion fra en anden session og læse de uforpligtede ændringer i transaktionen. Desværre vil det dog ikke hjælpe med sessionsvariabler (forudsat at "sessionsvariabel" betyder pakkevariabel, der har sessionsomfang).
Opret pakken og tabellen:
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;
I session 1 starter vi en global transaktion, indstiller pakkevariablen og indsætter en række i tabellen, før vi suspenderer den globale transaktion (hvilket tillader en anden session at genoptage den)
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.
I session 2 genoptager vi den globale transaktion, læser fra tabellen, læser sessionsvariablen og afslutter den globale transaktion. Bemærk, at forespørgslen mod tabellen ser den række, vi indsatte, men ændringen af pakkevariabelen er ikke synlig.
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.
For at dele sessionstilstand mellem sessionerne, ville det være muligt at bruge en global applikationskontekst
i stedet for at bruge pakkevariabler? Du kan kombinere det med DBMS_XA
pakker, hvis du vil læse både databasetabeller og sessionstilstand.
Opret konteksten og pakken med getter og 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;
I session 1 skal du indstille værdien af kontekstvariablen G_VAR
til 47 for session 12345
begin
pkg_foo.set_var( 12345, 47 );
end;
Nu kan session 2 læse værdien fra konteksten
1* select pkg_foo.get_var( 12345 ) from dual
SQL> /
PKG_FOO.GET_VAR(12345)
----------------------
47