Wenn Sie eine 11g-Datenbank verwenden, können Sie den DBMS_XA
um einer Sitzung zu erlauben, an einer Transaktion teilzunehmen, die von der ersten Sitzung gestartet wurde. Wie Tim Hall demonstriert, können Sie eine Transaktion in einer Sitzung starten, dieser Transaktion aus einer anderen Sitzung beitreten und die nicht festgeschriebenen Änderungen lesen, die in der Transaktion vorgenommen wurden. Leider hilft das jedoch nicht bei Sitzungsvariablen (vorausgesetzt, dass "Sitzungsvariable" Paketvariablen bedeutet, die einen Sitzungsbereich haben).
Erstellen Sie das Paket und die Tabelle:
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;
In Sitzung 1 starten wir eine globale Transaktion, setzen die Paketvariable und fügen eine Zeile in die Tabelle ein, bevor wir die globale Transaktion unterbrechen (was einer anderen Sitzung erlaubt, sie fortzusetzen)
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.
In Sitzung 2 nehmen wir die globale Transaktion wieder auf, lesen aus der Tabelle, lesen die Sitzungsvariable und beenden die globale Transaktion. Beachten Sie, dass die Abfrage der Tabelle die von uns eingefügte Zeile sieht, aber die Änderung der Paketvariablen nicht sichtbar ist.
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.
Um den Sitzungsstatus zwischen den Sitzungen auszutauschen, wäre es möglich, einen globaler Anwendungskontext
anstatt Paketvariablen zu verwenden? Sie könnten das mit dem DBMS_XA
kombinieren Pakete, wenn Sie sowohl Datenbanktabellen als auch Sitzungsstatus lesen möchten.
Erstellen Sie den Kontext und das Paket mit Getter und 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;
Setzen Sie in Sitzung 1 den Wert der Kontextvariablen G_VAR
bis 47 für Sitzung 12345
begin
pkg_foo.set_var( 12345, 47 );
end;
Jetzt kann Sitzung 2 den Wert aus dem Kontext lesen
1* select pkg_foo.get_var( 12345 ) from dual
SQL> /
PKG_FOO.GET_VAR(12345)
----------------------
47