Oracle
 sql >> Database >  >> RDS >> Oracle

posso mantenere una sessione Oracle da due client oci?

Se stai utilizzando un database 11g, puoi utilizzare il DBMS_XA pacchetto per consentire a una sessione di partecipare a una transazione avviata dalla prima sessione. Come dimostra Tim Hall, puoi avviare una transazione in una sessione, unirti a quella transazione da un'altra sessione e leggere le modifiche non vincolate apportate alla transazione. Sfortunatamente, tuttavia, ciò non aiuterà con le variabili di sessione (supponendo che "variabile di sessione" significhi variabile di pacchetto con ambito di sessione).

Crea il pacchetto e la tabella:

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;

Nella sessione 1, avviamo una transazione globale, impostiamo la variabile del pacchetto e inseriamo una riga nella tabella prima di sospendere la transazione globale (che consente a un'altra sessione di riprenderla)

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.

Nella sessione 2, riprendiamo la transazione globale, leggiamo dalla tabella, leggiamo la variabile di sessione e terminiamo la transazione globale. Nota che la query sulla tabella vede la riga che abbiamo inserito ma la modifica della variabile del pacchetto non è visibile.

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.

Per condividere lo stato della sessione tra le sessioni, sarebbe possibile utilizzare un contesto dell'applicazione globale piuttosto che usare le variabili del pacchetto? Potresti combinarlo con il DBMS_XA pacchetti se vuoi leggere sia le tabelle del database che lo stato della sessione.

Crea il contesto e il pacchetto con getter e 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;

Nella sessione 1, imposta il valore della variabile di contesto G_VAR a 47 per la sessione 12345

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

Ora, la sessione 2 può leggere il valore dal contesto

  1* select pkg_foo.get_var( 12345 ) from dual
SQL> /

PKG_FOO.GET_VAR(12345)
----------------------
                    47