Logo Море(!) аналитической информации!
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware
Обучение от Mail.Ru Group.
Онлайн-университет
для программистов с
гарантией трудоустройства.
Набор открыт!
2010 г.

Редакции объектов БД в Oracle как средство внесения изменений в приложение

Владимир Пржиялковский, prz@yandex.ru
Преподаватель технологий Oracle
Июль 2010 г.

Да разве б не цвела земля афинская,
Когда бы так же рассуждали граждане
И постоянно не искали нового?

Аристофан, Женщины в народном собрании

Реферат

В версии Oracle 11.2 для некоторых видов объектов хранения была введена возможность заводить одновременно несколько «редакций» (editions). Она была придумана для совершенствования процесса внесения изменений в схему данных, позволяя в некоторых случаях отлаживать новый вариант приложения впараллель с работой текущего. Техника использования редакций объектов рассматривается в статье на примерах.

Содержание

Введение
Подготовка схемы для редакций объектов
Создание редакций для объектов и управление ими
Настройка на работу с нужной редакцией
Пример создания и использования разных редакций представления данных (view)
Пример редакций процедур
Пример редакций триггерных процедур
Перекрестные триггерные процедуры для разных редакций
Подготовка таблиц
Создание перекрестных межредакционных триггерных процедур
Дополнительные замечания по технологии

Введение

С версии 11.2 для некоторых видов хранимых объектов в Oracle можно заводить разные «редакции» (editions) и переключаться между ними в работе, моделируя тем самым несколько версий прикладного программного обеспечения на этапе его разработки или переделки. Речь не идет о редакциях данных, и на таблицы эта техника не распространяется. Она применима к объектам следующих видов:

  • VIEW
  • SYNONYM
  • PROCEDURE
  • FUNCTION
  • TRIGGER
  • PACKAGE/PACKAGE BODY
  • TYPE/TYPE BODY
  • LIBRARY.

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

Хотя техника редакций объектов хранения не распространяется на данные в исходных таблицах БД, версии представлений иногда помогают подготовить приложение в том числе к переходу на новые структуры таблиц.

В версии Oracle 11.2 техника редакций объектов воплощена в своем начальном варианте, вероятно не окончательном.

Далее рассматривается несколько примеров создания и использования версий объектов в Oracle.

Подготовка схемы для редакций объектов

Ниже приводятся команды заведения в SQL*Plus схемы для объектов разных редакций и выполнения необходимых сопутствующих действий.

CONNECT / AS SYSDBA
CREATE USER yard IDENTIFIED BY pass;

GRANT CONNECT, RESOURCE, CREATE VIEW TO yard;

CREATE TABLE yard.emp AS SELECT * FROM scott.emp;

В схеме YARD появилась таблица EMP с той же структурой, что и одноименная в схеме SCOTT и с теми же данными (но без ограничений целостности).

Создание редакций для объектов и управление ими

Управление редакциями регулируется привилегиями CREATE/ALTER/DROP ANY EDITION. Слово ANY в названиях напоминает о внесхемном характере редакций, распространяющемся на уровень всей БД целиком (формально они все приписаны пользователю SYS).

Если правом создавать редакции объектов и управлять ими требуется доверить пользователю YARD, администратору БД следует продолжить:

GRANT CREATE ANY EDITION, DROP ANY EDITION TO yard;

Узнать действующую в данный момент редакцию можно из контекста сеанса USERENV (встроенного в СУБД):

SQL> CONNECT yard/pass
Connected.
SQL> SELECT SYS_CONTEXT ( 'USERENV', 'CURRENT_EDITION_NAME' ) FROM dual;

SYS_CONTEXT('USERENV','CURRENT_EDITION_NAME')
--------------------------------------------------------------------
ORA$BASE

ORA$BASE – это встроенная в БД умолчательно действующая редакция, на основе которой администратор может создавать последовательность редакций (а в будущих версиях Oracle возможно дерево) на свое усмотрение. Имя умолчательной для БД редакции можно выяснить запросом:

SELECT property_value
FROM  database_properties
WHERE property_name = 'DEFAULT_EDITION'
;

Примеры создания редакций:

CREATE EDITION app_release_1;
CREATE EDITION app_release_2 AS CHILD OF app_release_1;

В первом случае редакция APP_RELEASE_1 была создана на основе умолчательно действующей редакции ORA$BASE, во втором – как следует из текста команды.

Откомментировать редакцию в словаре-справочнике БД можно командой COMMENT:

COMMENT ON EDITION app_release_1
  IS 'The first release of application'
;

Снять комментарий можно, указав пустую строку ''. Наблюдаются комментарии через таблицу ALL_EDITION_COMMENTS.

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

SQL> SELECT * FROM all_editions;

EDITION_NAME                   PARENT_EDITION_NAME            USA
------------------------------ ------------------------------ ---
ORA$BASE                                                      YES
APP_RELEASE_1                  ORA$BASE                       YES
APP_RELEASE_2                  APP_RELEASE_1                  YES

Удалить можно только лист из дерева (пока – ветки), свободный от подчиненных редакций:

DROP EDITION app_release_2;

Для того, чтобы пользователь Oracle мог не просто обращаться с редакциями объектов, но и формировать их, ему следует сообщить особое качество:

CONNECT / AS SYSDBA
ALTER USER yard ENABLE EDITIONS;

Качество ENABLE EDITIONS не изначальное и неотъемлемое; буде оно раз выдано, отменить его нельзя. В результате все пользователи Oracle оказываются разделены на две категории: тех, кому разрешено формировать редакции, и тех, кому не разрешено. При том возможен перевод пользователя из второй категории в первую, но никак не обратно. Удостовериться в наличие свойства ENABLE EDITIONS у пользователя можно по значению поля EDITIONS_ENABLED (нового в версии 11.2) в таблице DBA_USERS (владелец ее SYS, и обычным пользователям сама по себе она не видна).

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

Настройка на работу с нужной редакцией

Чтобы пользователь Oracle имел право в конкретном сеансе работать с конкретной редакцией:

  • он должен иметь привилегию на работу с редакцией, выданную лично ему или, вместо этого, псевдопользователю PUBLIC (то есть всем вообще);
  • сеанс должен быть переключен на работу с этой редакцией.

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

GRANT USE ON EDITION app_release_1 TO scott;

USE – это привилегия на объекты вида EDITION, передаваемая к тому же через PUBLIC и через роли. Если редакцию, объявить в БД умолчательной, она автоматически полагается выданной для PUBLIC, то есть общедоступной, и не требует личных (или же ролевых) разрешений. По этой причине изначально частных разрешений на работу с ORA$BASE не требуется – оно есть у всех. То же самое произойдет с редакцией APP_RELEASE_1, если в какой-то момент выдать:

ALTER DATABASE DEFAULT EDITION = app_release_1;

На последнюю команду способен обладатель привилегии ALTER DATABASE (а ею обладают SYS и SYSTEM, но пока что не YARD). Как только такая команда будет выдана, команды GRANT USE, как выше, для придания нужных полномочий пользователю SCOTT, не потребуется. Выдачей подобной команды может венчаться отладка новых редакций объектов («перевод приложения на новую редакцию»).

Когда пользователь Oracle получил разрешение (то есть привилегию) на работу с объектами конкретной редакции, он получает право в рамках отдельных сеансов настраиваться на нее:

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

SYS_CONTEXT('USERENV','CURRENT_EDITION_NAME')
--------------------------------------------------------------------
ORA$BASE

SQL> ALTER SESSION SET EDITION = app_release_1;

Session altered.

SQL> SELECT SYS_CONTEXT ( 'USERENV', 'CURRENT_EDITION_NAME' ) FROM dual;

SYS_CONTEXT('USERENV','CURRENT_EDITION_NAME')
--------------------------------------------------------------------
APP_RELEASE_1

Код выше подтверждает то, что по умолчанию при открытии сеанса действует редакция, объявленая ранее умолчательной в БД.

Пример создания и использования разных редакций представления данных (view)

К настоящему моменту в БД имеется две редакции. Будем формировать их содержание редакциями объектов в схеме YARD. Создадим в ней две несложные редакции одного и того же представления данных – с выдачей сведений об отделе сотрудника, и без:

CONNECT yard/pass
ALTER SESSION SET EDITION = ora$base;
CREATE OR REPLACE EDITIONING VIEW emp_view
  AS
  SELECT empno, ename, deptno FROM emp
;
ALTER SESSION SET EDITION = app_release_1;
CREATE OR REPLACE EDITIONING VIEW emp_view
  AS
  SELECT empno, ename FROM emp
;

Настройку на редакцию ORA$BASE можно было выше не выполнять, потому что эта редакция умолчательная (это проверялось ранее), и автоматически действует в начале каждого сеанса.

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

SQL> SELECT view_name, edition_name FROM user_editioning_views_ae;
VIEW_NAME                      EDITION_NAME		      
------------------------------ ------------------------------
EMP_VIEW		       ORA$BASE		      
EMP_VIEW		       APP_RELEASE_1

Редактируемые представления данных (editioning views) отличаются от обычных не только формальным словом EDITIONING при создании, но и некоторыми техническими свойствами. Они могут строиться на основе единственной таблицы, без фильтрации строк фразой WHERE и с отсутствием преобразований столбцов (в то же время воспроизведение всех столбцов не обязательно). Есть и другие отличия, не востребованными в этом тексте.

Чтобы пользователь SCOTT имел доступ к данным, для каждой редакции требуется выдать отдельное разрешение:

ALTER SESSION SET EDITION = ora$base;
GRANT SELECT ON emp_view TO scott;
ALTER SESSION SET EDITION = app_release_1;
GRANT SELECT ON emp_view TO scott;

Вот как этими разрешениями может воспользоваться SCOTT:

SQL> CONNECT scott/tiger
Connected.
SQL> ALTER SESSION SET EDITION = ora$base;

Session altered.

SQL> SELECT * FROM yard.emp_view WHERE ROWNUM = 1;

     EMPNO ENAME          DEPTNO
---------- ---------- ----------
      7369 SMITH              20

SQL> ALTER SESSION SET EDITION = app_release_1;

Session altered.

SQL> SELECT * FROM yard.emp_view WHERE ROWNUM = 1;

     EMPNO ENAME
---------- ----------
      7369 SMITH

Теперь без отмены прежнего представления данных (которым может пользоваться текущее приложение) открылась возможность отлаживать приложение применительно к новому.

Упражнение. Отобрать у пользователя SCOTT привилегию на выборку данных из YARD.EMP_VIEW в редакции APP_RELEASE_1 и наблюдать результат попытки обращения.

Пример редакций процедур

Заведение разных редакций одной и той же процедуры в схеме со свойством EDITIONS_ENABLED = TRUE выглядит достаточно прозрачно. Так, для добавления данных о сотрудниках можно завести две редакции процедуры INSERT_EMPLOYEE следующим образом:

CONNECT yard/pass
ALTER SESSION SET EDITION = ora$base;
CREATE OR REPLACE PROCEDURE insert_employee (
  eno   NUMBER
, ename VARCHAR2
, dno   NUMBER
)
AS
BEGIN
INSERT INTO yard.emp_view ( empno, ename, deptno ) VALUES ( eno, ename, dno )
;
END;
/
GRANT EXECUTE ON insert_employee TO scott;

ALTER SESSION SET EDITION = app_release_1;
CREATE OR REPLACE PROCEDURE insert_employee (
  eno   NUMBER
, ename VARCHAR2
)
AS
BEGIN
INSERT INTO yard.emp_view ( empno, ename ) VALUES ( eno, ename )
;
END;
/
GRANT EXECUTE ON insert_employee TO scott;

Проверка:

SQL> CONNECT scott/tiger
Connected.
SQL> ALTER SESSION SET EDITION = ora$base;

Session altered.

SQL> EXECUTE yard.insert_employee ( 1111, 'OBAMA', 10 )

PL/SQL procedure successfully completed.

SQL> ROLLBACK;

Rollback complete.

SQL> ALTER SESSION SET EDITION = app_release_1;

Session altered.

SQL> EXECUTE yard.insert_employee ( 1111, 'OBAMA' )

PL/SQL procedure successfully completed.

SQL> ROLLBACK;

Rollback complete.

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

Пример редакций триггерных процедур

Теперь для добавления в БД данных о сотрудниках создадим две редакцмм триггерных процедур. Это делается аналогично обычным процедурам. Прикладной смысл триггерных процедур в данном случае состоит в нормализации имен сотрудников перед помещением в базу.

CONNECT yard/pass
ALTER SESSION SET EDITION = ora$base;

CREATE OR REPLACE TRIGGER empl_insert
BEFORE INSERT ON emp_view
FOR EACH ROW
BEGIN
   :new.ename := INITCAP ( :new.ename );
END;
/
GRANT INSERT ON emp_view TO scott;

Обратите внимание, что для редактируемых представлений (EDITIONING VIEW) в триггерных процедурах не действует привязка к событию INSTEAD OF, как для обычных представлений, а вместо этого BEFORE и AFTER, как для основных таблиц. Это одно из проявлений особости редактируемых представлений от обычных.

Вторая редакция:

ALTER SESSION SET EDITION = app_release_1;
CREATE OR REPLACE TRIGGER empl_insert
BEFORE INSERT ON emp_view
FOR EACH ROW
BEGIN
   :new.ename := LOWER ( :new.ename );
END;
/
GRANT INSERT ON emp_view TO scott;

Проверку можно выполнить следующей последовательностию команд в SQL*Plus:

CONNECT scott/tiger
ALTER SESSION SET EDITION = ora$base;
INSERT INTO yard.emp_view VALUES ( 1111, 'OBAMA', 10 );
SELECT * FROM yard.emp_view WHERE empno = 1111;
ROLLBACK;

ALTER SESSION SET EDITION = app_release_1;
INSERT INTO yard.emp_view VALUES ( 1111, 'OBAMA' );
SELECT * FROM yard.emp_view WHERE empno = 1111;
ROLLBACK;

Перекрестные триггерные процедуры для разных редакций

Когда отлаживается работа приложения с новой редакцией объектов БД, какое-то время обе редакции объектов (старая и новая) сосуществуют. Сложность в том, что работа с новой редакцией не должна портить данные, с которыми продолжает иметь дело старый вариант приложения. Если планируемые изменения в схеме однозначно взаимообратимы с исходным состоянием, помочь в этом способны перекрестные триггерные процедуры для разных редакций (межредакционные триггерные процедуры; crossedition triggers, CET).

Рассмотрим пример подготовки к изменению структуры таблицы EMP в схеме YARD. Предположим, требуется хранить в БД самостоятельно сведения о должностях, как например максимальную зарплату и тому подобное. Ради этого придется завести отдельную новую таблицу с данными о должностях, а в таблице EMP изъять столбец с названием должности сотрудника, и добавить заместо ссылку на сведения о должностях. Пока новая редакция приложения не будет объявлена основной, старый столбец придется какое-то время сохранять.

Подобное разбиение одной таблицы сотрудников на две – сотрудников и должностей – очевидно обратимо, так что на время отладки будет удобно воспользоваться межредакционными триггерными процедурами. Они будут отвечать при работе со старой редакцией за дублированное внесение изменений в новые структуры, а при работе с новой редакцией – в старые, обеспечивая в данных БД возможность предоставления «взгляда» на них как по-старому, так и по-новому.

Подготовка таблиц

Создадим таблицу должностей, добавим в таблицу сотрудников ссылку, при том что столбец с названием должности оставим до будущего перехода на новую редакцию приложения. Выполним в SQL*Plus:

CONNECT yard/pass
CREATE TABLE job (
  jobid  NUMBER   ( 2 ) PRIMARY KEY
, jname  VARCHAR2 ( 9 )
, maxsal NUMBER   ( 7, 2 )
);
INSERT INTO job ( jobid, jname, maxsal ) VALUES ( 1,   'ANALYST', 3500 );
INSERT INTO job ( jobid, jname,	maxsal ) VALUES	( 2,     'CLERK', 2000 );
INSERT INTO job ( jobid, jname,	maxsal ) VALUES	( 3,   'MANAGER', 3000 );
INSERT INTO job ( jobid, jname,	maxsal ) VALUES	( 4, 'PRESIDENT', 6000 );
INSERT INTO job ( jobid, jname,	maxsal ) VALUES	( 5,  'SALESMAN', 2000 );

ALTER TABLE emp ADD ( jobno NUMBER ( 2 ) REFERENCES job ( jobid ) );

UPDATE emp SET jobno = ( SELECT jobid FROM job WHERE jname = emp.job );

Переименуем таблицу сотрудников, и отдадим ее старое имя двум редакциям представлений:

ALTER TABLE emp RENAME TO emp_tab;

ALTER SESSION SET EDITION = ora$base;
CREATE OR REPLACE EDITIONING VIEW emp
  AS
  SELECT empno, ename, job, mgr, hiredate, sal, comm, deptno FROM emp_tab
;
GRANT INSERT, UPDATE, DELETE, SELECT ON emp TO scott;

ALTER SESSION SET EDITION = app_release_1;
CREATE OR REPLACE EDITIONING VIEW emp
  AS
  SELECT empno, ename, jobno, mgr, hiredate, sal, comm, deptno FROM emp_tab
;
GRANT INSERT, UPDATE, DELETE, SELECT ON emp TO scott;
Создание перекрестных межредакционных триггерных процедур

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

ALTER SESSION SET EDITION = app_release_1;

CREATE OR REPLACE TRIGGER cross_forward_job
BEFORE INSERT OR UPDATE ON emp_tab
FOR EACH ROW
FORWARD CROSSEDITION
BEGIN
  SELECT jobid INTO :new.jobno FROM job WHERE :new.job = jname;
END;
/

CREATE OR REPLACE TRIGGER cross_reversed_job
BEFORE INSERT OR UPDATE ON emp_tab
FOR EACH ROW
REVERSE CROSSEDITION
BEGIN
  SELECT jname INTO :new.job FROM job j WHERE :new.jobno = jobid;
END;
/

Проверку способен организовать следующий код:

CONNECT scott/tiger
ALTER SESSION SET EDITION = ora$base;
INSERT INTO yard.emp ( empno, ename, job ) VALUES ( 1111, 'OBAMA', 'CLERK' );
COMMIT;
ALTER SESSION SET EDITION = app_release_1;
INSERT INTO yard.emp ( empno, ename, jobno ) VALUES ( 2222, 'LADEN', 2 );
COMMIT;

Как и раньше, если транзакция успела изменить какие-нибудь данные в БД, для настройки на новую редакцию ее потребуется сначала закрыть. В результате получим:

SQL> SELECT * FROM yard.emp WHERE empno IN ( 1111, 2222 );

     EMPNO ENAME        JOBNO      MGR HIREDATE      SAL    COMM   DEPTNO
---------- ------- ---------- -------- --------- ------- ------- --------
      1111 OBAMA            2
      2222 LADEN            2

SQL> ALTER SESSION SET EDITION = ora$base;

Session altered.

SQL> SELECT * FROM yard.emp WHERE empno IN ( 1111, 2222 );

     EMPNO ENAME   JOB            MGR HIREDATE      SAL    COMM   DEPTNO
---------- ------- --------- -------- --------- ------- ------- --------
      1111 OBAMA   CLERK
      2222 LADEN   CLERK

При работе со старой редакцией воспроизводится поведение старой таблицы EMP, а при работе с новой – с тою же таблицей, но в новом варианте.

Дополнительные замечания по технологии

Приведенные примеры перекрестных триггерных процедур были намерено упрощены. В жизни в них следовало бы предусмотреть реакцию на указание в качестве нового значения отсутствующей должности. Предположим, что в старом приложении подобная обработка не программировалась, то есть в БД добавлялась ровно то название должности, которае было указано в INSERT/UPDATE. Тогда для сохранения поведения старой реакции приложения следовало бы на возникающую в SELECT ... INTO ... FROM job ошибку NO_DATA_FOUND среагировать добавлением новой записи в таблицу JOB. Придется решить технический вопрос о поставке значений в JOBID; это может потребовать употребления генератора последовательности (sequence) и других усложнений.

При решении перейти на новую редакцию приложения перекрестные триггерные процедуры и редакционные представления данных следует удалить, а освободившееся имя EMP вернуть основной таблице:

CONNECT yard/pass
ALTER SESSION SET EDITION = ora$base;
DROP VIEW emp;

ALTER SESSION SET EDITION = app_release_1;
DROP VIEW emp;
DROP TRIGGER cross_reversed_job;
DROP TRIGGER cross_forward_job;

ALTER TABLE emp_tab RENAME TO emp;
ALTER TABLE emp DROP COLUMN job;

CONNECT / AS SYSDBA
ALTER DATABASE DEFAULT EDITION = app_release_1;

Новости мира IT:

Архив новостей

Последние комментарии:

Релиз ядра Linux 4.14  (9)
Среда 22.11, 19:04
Loading

IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

Информация для рекламодателей PR-акции, размещение рекламы — adv@citforum.ru,
тел. +7 985 1945361
Пресс-релизы — pr@citforum.ru
Обратная связь
Информация для авторов
Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
Copyright © 1997-2000 CIT, © 2001-2015 CIT Forum
Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...