Вы находитесь на страницах старой версии сайта.
Переходите на новую версию Interface.Ru

предыдущая статья

Контекст сеанса в Oracle, часть 2: создание собственных контекстов

© Владимир Пржиялковский,
координатор Евро-Азиатской Группы Пользователей Oracle,
преподаватель УЦ Interface Ltd.

Аннотация

В каждом сеансе работы с СУБД можно использовать так называемые контексты, формально представляющие собой именованный набор пар "параметр/значение". Контексты сеансов обладают рядом интересных свойств, существенно повышающих "внутренние" возможности Oracle по созданию приложений. В статье рассматриваются возможности проектирования локальных и глобальных контекстов сеанса и некоторые их свойства.

Создаваемый контекст сеанса

Для самостоятельного создания контекста служит специальная команда CREATE CONTEXT. Выдать ее (то есть создать контекст) может сеанс, имеющий полномочие CREATE ANY CONTEXT. Слово ANY в названии полномочия (привилегии) свидетельствует о том, что контекст – внесхемный объект в БД Oracle, такой, например, как роль, и отличный, например, от таблицы.

Для каждого контекста требуется указать специальную "доверительную" программную единицу: процедуру, функцию или пакет. Именно из тела этой программной единицы Oracle разрешит обращаться к процедуре DBMS_SESSION.SET_CONTEXT. Принято такое неочевидное решение во имя безопасности, так как доступ к хранимым программным единицам регулируется уже готовым механизмом привилегий.

Пример создания контекста

Положим, доверительной программной единицей должна быть процедура SET_MYCONTEXT_VALUE:

CONNECT / as sysdba 

CREATE OR REPLACE CONTEXT mycontext USING set_mycontext_value;

Обратите внимание, что процедура не обязана существовать в момент создания контекста. Но в конце концов ее-таки потребуется создать:

CREATE OR REPLACE PROCEDURE set_mycontext_value (
  par IN VARCHAR2
, val IN VARCHAR2 
) 
AS
BEGIN DBMS_SESSION.SET_CONTEXT ( 'mycontext', par, val );
END;
/

GRANT EXECUTE ON set_mycontext_value TO scott;

Проверка:

SQL> CONNECT scott/tiger
Connected.
SQL> SELECT SYS_CONTEXT ( 'mycontext', 'sesame' ) FROM dual;

SYS_CONTEXT('MYCONTEXT','SESAME')
------------------------------------------------------------
                                                                              

SQL> EXECUTE sys.set_mycontext_value ( 'sesame', '123' )

PL/SQL procedure successfully completed.

SQL> SELECT SYS_CONTEXT ( 'mycontext', 'sesame' ) FROM dual;

SYS_CONTEXT('MYCONTEXT','SESAME')
------------------------------------------------------------
123

Выше серым фоном выделена пустая строка.

С помощью контекста MYCONTEXT и доступной ему процедуры пользователь SCOTT завел значение, которое сможет читать и переустанавливать в собственном сеансе вплоть до завершения. Другой сеанс пользователя SCOTT создаст и будет использовать с помощью этого же контекста свои значения, то есть значения контекста являются собственностью сеанса.

Значения атрибутов контекста живут не долее пределов сеанса и защищены от доступа из других сеансов. В течение сеанса значения переменных пакета могут пропасть ("сброс" пакета, хотя пользователи и нечасто прибегают к нему), и значения атрибутов контекста тоже (с помощью пакета DBMS_SESSION). Этим атрибуты схожи с переменными пакета. Но есть и отличия:

Вот еще пример использования нашего контекста:

SQL> EXECUTE set_mycontext_value -
> ( 'start work', TO_CHAR ( SYSDATE, 'hh24:mi:ss' ) )

PL/SQL procedure successfully completed.

SQL> REMARK выполняем работу, после чего смотрим когда начинали ...
SQL> SELECT SYS_CONTEXT ( 'mycontext', 'start work' ) FROM dual;

SYS_CONTEXT('MYCONTEXT','STARTWORK')
--------------------------------------------------------------------
13:58:06

Вариация в технологии: использование доверительного пакета

Если запросить структуру справочной таблицы доступных контекстов, то видно, что поле для доверительной программной единицы названо PACKAGE:

SQL> SELECT * FROM all_context;

NAMESPACE              SCHEMA                 PACKAGE
---------------------- ---------------------- ----------------------
MYCONTEXT              SYS                    SET_CONTEXT_VALUE

Это не случайно: на практике часто более технологично установку контекста выполнять с помощью доверительного пакета, а не самостоятельной процедуры или функции. Ведь в состав пакета можно включить и прочие программные элементы, моделирующие логику предметной области.

Пример:

CONNECT / as sysdba 

CREATE OR REPLACE CONTEXT mycontext USING mycontext_pckg;

CREATE OR REPLACE PACKAGE mycontext_pckg IS
   PROCEDURE set_value ( par VARCHAR2, val VARCHAR2 );
   FUNCTION get_value ( par VARCHAR2 ) RETURN VARCHAR2;
END;
/

CREATE OR REPLACE PACKAGE BODY mycontext_pckg IS
   PROCEDURE set_value ( par VARCHAR2, val VARCHAR2 )
   IS
   BEGIN
      DBMS_SESSION.SET_CONTEXT ( 'mycontext', par, val );
   END;

   FUNCTION get_value ( par VARCHAR2 ) RETURN VARCHAR2
   IS
   BEGIN
      RETURN SYS_CONTEXT ( 'mycontext', par );
   END;
END;
/

GRANT EXECUTE ON mycontext_pckg TO scott;

Проверка:

SQL> CONNECT scott/tiger
Connected.
SQL> SELECT sys.mycontext_pckg.get_value ( 'sesame' ) FROM dual;

SYS.MYCONTEXT_PCKG.GET_VALUE('SESAME')
---------------------------------------------------------------------
                                                                              

SQL> EXECUTE sys.mycontext_pckg.set_value ( 'sesame', '123' )

PL/SQL procedure successfully completed.

SQL> SELECT sys.mycontext_pckg.get_value ( 'sesame' ) FROM dual;

SYS.MYCONTEXT_PCKG.GET_VALUE('SESAME')
---------------------------------------------------------------------
123

Пакет можно спроектировать и иначе, закрыв, например, для пользователя имя атрибута или даже контекста. Можно запрограммировать все, что требует логика предметной области.

Начальные значения атрибутов контекста

Выше было показано, как атрибуты контекстов выставляются в процессе сеанса связи с СУБД. Однако по подобию с CLIENTCONTEXT создаваемый контекст тоже можно обеспечить начальными значениями требуемых атрибутов из программы, открывающий сеанс. Это можно сделать:

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

CREATE CONTEXT ... INITIALIZED EXTERNALLY и

CREATE CONTEXT ... INITIALIZED EXTERNALLY

Начальные значения атрибутов контекста для сеансов – очень сильное средство, позволяющее наложить на относительно примитивный механизм внутренних пользователей БД инфраструктуру внешних пользователей, часто более проработанную и универсальную. Например, сервер приложений может поддерживать очень много пользователей web-страниц, обладающих собственными свойствами. Моделировать их отдельными локальными для Oracle пользователями может оказаться крайне неэффективно, и в этом случае возможность предварительного установления атрибутов перед обращением к БД будет давать единственный ключ к построению решения.

Глобальный контекст сеанса ("контекст приложения")

"Обычный" контекст сеанса имеет своей областью действия отдельный сеанс. Иногда этого разработчику приложения вполне достаточно, а иногда хочется большего. Можно ли, например, запретить сеансу самостоятельно выставлять значение атрибута и предоставить ему только чтение, а значение задавать из другого сеанса? Такую возможность обеспечивает глобальный контекст сеанса, называемый еще иногда контекстом приложения. Пример его использования показан ниже:

CONNECT / AS SYSDBA

CREATE OR REPLACE CONTEXT globalcontext 
USING globalcontext_pckg
ACCESSED GLOBALLY
/

CREATE OR REPLACE PACKAGE globalcontext_pckg AS
   PROCEDURE set_value (
     par VARCHAR2
   , val VARCHAR2
   , usr VARCHAR2
   , usrid VARCHAR2
   );
END;
/

CREATE OR REPLACE PACKAGE BODY globalcontext_pckg AS
   PROCEDURE set_value (
     par VARCHAR2
   , val VARCHAR2
   , usr VARCHAR2
   , usrid VARCHAR2
   )
   AS
   BEGIN
    DBMS_SESSION.SET_CONTEXT (
     'globalcontext'
   , par
   , val
   , usr
   , usrid
   );
   END;
END;
/

EXECUTE globalcontext_pckg.set_value -
( 'sesame' , '123', 'SCOTT', 'XYZ32A6' )

Проверка:

SQL> CONNECT scott/tiger
Connected.
SQL> SELECT SYS_CONTEXT ( 'globalcontext', 'sesame' ) FROM dual;

SYS_CONTEXT('GLOBALCONTEXT','SESAME')
--------------------------------------------------------------------
                                                                              

SQL> EXECUTE DBMS_SESSION.SET_IDENTIFIER ( 'XYZ32A6' );

PL/SQL procedure successfully completed.

SQL> SELECT SYS_CONTEXT ( 'globalcontext', 'sesame' ) FROM dual;

SYS_CONTEXT('GLOBALCONTEXT','SESAME')
--------------------------------------------------------------------
123

SQL> EXECUTE DBMS_SESSION.SET_IDENTIFIER ( 'XYZ32A6ZZZ' );

PL/SQL procedure successfully completed.

SQL> SELECT SYS_CONTEXT ( 'globalcontext', 'sesame' ) FROM dual;

SYS_CONTEXT('GLOBALCONTEXT','SESAME')
----------------------------------------------------------------------
                                                                              

Тут есть сразу несколько интересных новшеств.

  1. То, что контекст глобальный, было указано словами ACCESSED GLOBALLY при его создании.
  2. В процедуре DBMS_SESSION.SET_CONTEXT именно для глобального контекста существуют два дополнительных параметра. Первый сообщает, сеансам чьего пользователя будет доступен этот контекст (для каждого такого пользователя нужно будет выполнить отдельный вызов SET_CONTEXT), а второй – условное значение, которое необходимо будет сообщить для возможности прочитать установленное другим сеансом значения атрибута, своего рода пароль.
  3. Сообщение этого условного значения выполняется специальной процедурой DBMS_SESSION.SET_IDENTIFIER.

Таким образом, мало войти в СУБД под "правильным" пользователем; для того, чтобы получить в сеансе значение желаемого атрибута (глобального контекста), нужно будет еще сообщить условную строку. Излишне напоминать, что очевидным кандидатом на такую строку является cookie сеанса общения с web. И только благодаря этому, а также механизму избирательного доступа к частям таблицы в Oracle ("виртуальные частные базы данных", VPD/FGAC) и возможности сервера приложений автоматически выдавать SET_IDENTIFIER при обращении к БД, многочисленные пользователи web, формально подключаемые к СУБД под одними и теми же именами пользователей Oracle, смогут увидеть в базе каждый собственные данные.

Дополнительная информация

За дополнительной информацией обращайтесь в компанию Interface Ltd.

Обсудить на форуме Oracle

Рекомендовать страницу

INTERFACE Ltd.
Телефон/Факс: +7 (495) 925-0049
Отправить E-Mail
http://www.interface.ru
Rambler's Top100
Ваши замечания и предложения отправляйте редактору
По техническим вопросам обращайтесь к вебмастеру
Дата публикации: 16.02.06