Ако използвате 11g база данни, можете да използвате DBMS_XAкод> пакет
за да позволи на една сесия да се присъедини към транзакция, започната от първата сесия. Както демонстрира Тим Хол, можете да стартирате транзакция в една сесия, да се присъедините към тази транзакция от друга сесия и да прочетете неизвършените промени, направени в транзакцията. За съжаление обаче това няма да помогне с променливите на сесията (ако приемем, че „променлива на сесията“ означава променлива на пакета, която има обхват на сесията).
Създайте пакета и таблицата:
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.
За да споделите състоянието на сесията между сесиите, възможно ли е да използвате контекст на глобалното приложение
вместо да използвате пакетни променливи? Можете да комбинирате това с 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 задайте стойността на контекстната променлива G_VAR
до 47 за сесия 12345
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