я могу поддерживать один сеанс Oracle от двух клиентов OCI? - PullRequest
6 голосов
/ 07 марта 2012

Есть ли возможность подключиться к Oracle (через OCI) из одного процесса, а затем подключиться к той же сессии базы данных из другого процесса?

В моем текущем приложении есть два способа доступа к базе данных: синхронный и асинхронный (используя отдельный процесс, общаясь через сокеты). Проблема в том, что два метода реализуют разные сессии.

Если я попытаюсь, например, обновление для одного сеанса, затем попытайтесь обновить ту же таблицу из другого сеанса без фиксации, я получаю зависание при вызове OCI.

Хуже, если переменная сеанса установлена ​​из одного сеанса - другой сеанс не видит его (что в точности соответствует названию ...).

1 Ответ

6 голосов
/ 07 марта 2012

Если вы используете базу данных 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, если хотите прочитать таблицы базы данных и состояние сеанса.

Создать контекст и пакет с помощью метода получения и установки

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...