Programmupdate mithilfe von Oracle Editions (Edition-Based Redefinition)

Ziel

Heute möchte ich euch zeigen, wie man mithilfe des Oracle Editions Feature ein Update einer auf PL/SQL basierenden Datenbankanwenduing mit minimaler Ausfallzeit für die Benutzer durchführen kann. 

 

Oracle Editions

Mit der Version 11g Release 2 führte Oracle das Edition-based Redefintion Feature ein. Ziel dieses Features war eine Möglichkeit zu schaffen, eine Anwendung im laufenen Betrieb zu aktualisieren, ohne das der Benutzer in seiner Arbeit gestört wird. Mit Oracle 11g Release 2 ist es nun möglich, mehrere Versionen (Editions) eines Objektes vorzuhalten. Ein Objekt wird nun anhand seines Namens, Schemas und der Edition identifiziert. Oracle unterscheidet bei den Objekten zwischen “edtionable” und “non-editionable” Objekten. Bei den “non-editionable” Objekten kann nur eine Version in der Datenbank existieren, dies ist zum Beispiel bei Tabellen der Fall.

 

Editionable Objekte

  • Function
  • Trigger
  • Synonym
  • Procedure
  • Package + Package Body
  • Type + Type Body
  • View
  • Library

Non-Editionable Objekte

  • Tables
  • Puiblic Synonym

Jedes Schema kann nur eine Edition zur gleichen Zeit aktiv haben. Welche Version zurzeit in Benutzung ist, kann man wie folgt heraus finden.

SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') EDITION FROM DUAL;

Die Edition ora$base ist die Standardedition der Datenbank.

 

Testanwendung

Um dieses Tutorial verwenden zu können, muss eine Oracle 11g Release 2 Datenbank vorhanden sein.

BANNER -------------------------------------------------------------------------------- Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production PL/SQL Release 11.2.0.1.0 - Production CORE    11.2.0.1.0      Production TNS for Linux: Version 11.2.0.1.0 - Production NLSRTL Version 11.2.0.1.0 - Production

Zur Veranschaulichung habe ich eine einfache Buchanwendung erstellt. Für die Buchanwendung verwende ich einen eigenständigen Benutzer.

CREATE USER buchliste_adm IDENTIFIED BY password; GRANT connect, resource TO buchliste_adm; GRANT create view TO buchliste_adm;

Der folgende Code soll nur das Edition-based Redefinition Feature demonstrieren und wurde deshalb einfach gehalten.

-- Sequenz fuer Primaerschluessel CREATE SEQUENCE BUCHLISTE_PK_SEQ START WITH 1;  -- Tabelle mit den Buchinformationen CREATE TABLE BUCHLISTE (     id        NUMBER,     name    VARCHAR2(30) NOT NULL,     autor    VARCHAR2(30) NOT NULL,     CONSTRAINT BUCHLISTE_PK PRIMARY KEY (id),     CONSTRAINT BUCHLUSTE_BUCH_UQ UNIQUE (name, autor) );  -- Anwendungslogik CREATE OR REPLACE PACKAGE BUCHLISTE_VERWALTUNG IS     PROCEDURE HINZUFUEGEN (p_name IN VARCHAR2, p_autor IN VARCHAR2);     PROCEDURE ALLE_ANZEIGEN; END; /  CREATE OR REPLACE PACKAGE BODY BUCHLISTE_VERWALTUNG IS     PROCEDURE HINZUFUEGEN (p_name IN VARCHAR2, p_autor IN VARCHAR2)     IS         v_id        NUMBER;     BEGIN         -- Naechste ID abrufen         SELECT buchliste_pk_seq.NEXTVAL INTO v_id FROM dual;                  -- Buch hinzufuegen         INSERT INTO buchliste VALUES (v_id, p_name, p_autor);              -- Festschreiben         COMMIT;     END HINZUFUEGEN;          PROCEDURE ALLE_ANZEIGEN     IS     BEGIN         -- Ueberschrift         DBMS_OUTPUT.PUT_LINE(RPAD('ID', 8, ' ') || ' '  || RPAD('NAME', 30, ' ') || ' '  || RPAD('AUTOR', 30, ' '));         DBMS_OUTPUT.PUT_LINE(RPAD('-', 8, '-') || ' '  || RPAD('-', 30, '-') || ' '  || RPAD('-', 30, '-'));         -- Komplette Buchluste durchlaufen         FOR v_buch IN (SELECT * FROM buchliste)         LOOP             -- Ausgabe der Buchinformationen             DBMS_OUTPUT.PUT_LINE(RPAD(v_buch.ID, 8, ' ') || ' '  || RPAD(v_buch.NAME, 30, ' ') || ' '  || RPAD(v_buch.AUTOR, 30, ' '));         END LOOP;     END ALLE_ANZEIGEN; END; /

Die Anwendung wird wie folgt verwendet. Mithilfe der Prozedur HINZUFUEGEN kann ein neues Buch zur Verwaltung hinzugefügt werden. Die Prozedur ALLE_ANZEIGEN zeigt die komplette Buchliste an.

SET serveroutput ON SET linesize 120 BEGIN     BUCHLISTE_VERWALTUNG.HINZUFUEGEN(p_name => 'Tore der Welt', p_autor => 'Ken Follett');     BUCHLISTE_VERWALTUNG.ALLE_ANZEIGEN; END; /

Das Ergebnis sollte wie folgt aussehen.

ID       NAME                           AUTOR -------- ------------------------------ ------------------------------ 1        Tore der Welt                  Ken Follett

Vorbereitung des Benutzers

Damit ein Benutzer neue Editions anlegen kann, müssen die entsprechenden Rechte vergeben werden und das Editons Feature muss aktiviert werden.

GRANT create any edition, drop any edition TO buchliste_adm; ALTER USER buchliste_adm ENABLE EDITIONS;

Die Spalte EDITIONS_ENABLED in der Tabelle DBA_USERS gibt Aufschluss, ob ein Benutzer das Editions Feature verwenden kann.

 

Vorbereitung der Testanwendung

Wie ich oben aufgeführt habe, ist eine Tabelle ein non-editionable Objekt. Aus diesem Grund sollte die Anwendung nicht direkt auf die Tabellen zugreifen, sondern über eine EDITIONING VIEW, da es sonst zum Beispiel zu einem Problem mit der folgenden Zeile kommen würde.

INSERT INTO buchliste VALUES (v_id, p_name, p_autor);

Würde nun die Tabelle BUCHLISTE um eine weitere Spalte, die keinen Standardwert besitzt, erweitert werden, würde beim nächsten INSERT eine Ora-Fehlermeldung auftreten.

 

Damit dies nicht passiert, sollte der Zugriff in jeder Edition nur über Views stattfinden. Es gibt nun zwei Möglichkeiten die Anwendung entsprechen anzupassen.

  1. Umbenennen der Tabelle und Erstellung einer EDITIONING VIEW mit dem Namen BUCHLISTE
  2. Erstellung einer EDITIONING VIEW mit neuem Namen und Anpassung des Package BUCHLISTE_VERWALTUNG

Ich werde in diesem Fall Möglichkeit 1 verwenden. Dafür werde ich die Tabelle BUCHLISTE in BUCHLISTE_BASIS umbenenen und eine neue View anlegen.

ALTER TABLE buchliste RENAME TO buchliste_basis;  CREATE OR REPLACE EDITIONING VIEW buchliste AS  SELECT id, name, autor FROM buchliste_basis;

Hinweis: Für das Anlegen einer EDITIONING VIEW wird das CREATE VIEW Recht benötigt.

 

Zum Abschluss ein Test, ob die Anwendung wieder korrekt funktioniert.

SET serveroutput ON SET linesize 120 BEGIN     BUCHLISTE_VERWALTUNG.HINZUFUEGEN(p_name => 'Der Hobbit', p_autor => 'John R Tolkien');     BUCHLISTE_VERWALTUNG.ALLE_ANZEIGEN; END; /  ID       NAME                           AUTOR -------- ------------------------------ ------------------------------ 1        Tore der Welt                  Ken Follett 2        Der Hobbit                     John R Tolkien

Die Ausführung war erfolgreich. Unsere Anwendung arbeitet nun nicht mehr direkt mit der Tabelle, sondern stattdessen über die EDITIONING VIEW.

 

Neue Edition erstellen

Damit das Update der Anwendung nicht die aktuelle Programmversion beeinträchtigt, wird als nächstes eine neue Edition erstellt. Erst nachdem das Programmupdate erfolgreich war, wird diese neue Edition aktiviert. Dies hat zudem den Vorteil, dass bei einem Fehler die Verfügbarkeit der Anwendung nicht gefährdet ist.

CREATE edition buchliste_v2 AS CHILD OF ora$base;

Anschließend muss diese Edition auf Session Ebene aktiviert werden.

ALTER SESSION SET EDITION = buchliste_v2;

Hinweis: Alle bestehenden und neuen Sessions arbeiten weiterhin mit der alten Version.

 

Programmupdate einspielen

Nun werden die Änderungen an der Anwendung eingespielt. Die Anwendung wird um eine Verleihfunktion erweitert. Dafür wird zunächst die Basis Tabelle um zwei Spalten erweitert.

ALTER TABLE buchliste_basis ADD (verliehen_an VARCHAR2(30), verliehen_am DATE);

Hinweis: Die neuen Spalten dürfen keine NOT NULL Spalten sein oder müssen zumindest über einen Standardwert verfügen. Ansonsten gibt es Probleme mit der bestehenden Programmversion.

 

Anschließend wird die EDITIONING VIEW ersetzt.

CREATE OR REPLACE EDITIONING VIEW buchliste AS  SELECT id, name, autor, verliehen_an, verliehen_am FROM buchliste_basis;

Zum Abschluss wird das Package aktualisiert und erweitert.

CREATE OR REPLACE PACKAGE BUCHLISTE_VERWALTUNG IS     PROCEDURE HINZUFUEGEN (p_name IN VARCHAR2, p_autor IN VARCHAR2);     PROCEDURE VERLEIHEN (p_id IN NUMBER, p_verliehen_an IN VARCHAR2, p_verliehen_am IN DATE);     PROCEDURE ALLE_ANZEIGEN; END; /  CREATE OR REPLACE PACKAGE BODY BUCHLISTE_VERWALTUNG IS     PROCEDURE HINZUFUEGEN (p_name IN VARCHAR2, p_autor IN VARCHAR2)     IS         v_id        NUMBER;     BEGIN         -- Naechste ID abrufen         SELECT buchliste_pk_seq.NEXTVAL INTO v_id FROM dual;                  -- Buch hinzufuegen         INSERT INTO buchliste VALUES (v_id, p_name, p_autor, NULL, NULL);              -- Festschreiben         COMMIT;     END HINZUFUEGEN;          PROCEDURE VERLEIHEN (p_id IN NUMBER,p_verliehen_an IN VARCHAR2, p_verliehen_am IN DATE)     IS     BEGIN         UPDATE buchliste SET verliehen_an = p_verliehen_an, verliehen_am = p_verliehen_am WHERE id = p_id;         COMMIT;     END VERLEIHEN;          PROCEDURE ALLE_ANZEIGEN     IS     BEGIN         -- Ueberschrift         DBMS_OUTPUT.PUT_LINE(RPAD('ID', 8, ' ') || ' '  || RPAD('NAME', 30, ' ') || ' '  || RPAD('AUTOR', 30, ' ') || ' '  || RPAD('VERLIEHEN_AN', 30, ' ') || ' '  || RPAD('VERLIEHEN_AM', 30, ' '));         DBMS_OUTPUT.PUT_LINE(RPAD('-', 8, '-') || ' '  || RPAD('-', 30, '-') || ' '  || RPAD('-', 30, '-') || ' '  || RPAD('-', 30, '-') || ' '  || RPAD('-', 30, '-'));         -- Komplette Buchluste durchlaufen         FOR v_buch IN (SELECT * FROM buchliste)         LOOP             -- Ausgabe der Buchinformationen             DBMS_OUTPUT.PUT_LINE(RPAD(v_buch.ID, 8, ' ') || ' '  || RPAD(v_buch.NAME, 30, ' ') || ' '  || RPAD(v_buch.AUTOR, 30, ' ') || ' '  || RPAD(v_buch.VERLIEHEN_AN, 30, ' ') || ' '  || RPAD(v_buch.VERLIEHEN_AM, 30, ' '));         END LOOP;     END ALLE_ANZEIGEN; END; /

Bevor die neue Programmversion aktiviert wird, wird zunächst ein Test der neuen VERLEIHEN Prozedur durchgeführt.

SET serveroutput ON SET linesize 160 BEGIN     BUCHLISTE_VERWALTUNG.VERLEIHEN(p_id => 1, p_verliehen_an => 'Frodo', p_verliehen_am => SYSDATE);     BUCHLISTE_VERWALTUNG.ALLE_ANZEIGEN; END; /

Das Ergebnis sieht wie folgt aus.

ID       NAME                           AUTOR                          VERLIEHEN_AN                   VERLIEHEN_AM -------- ------------------------------ ------------------------------ ------------------------------ ------------------------------ 1        Tore der Welt                  Ken Follett                    Frodo                          15-APR-13 2        Der Hobbit                     John R Tolkien

Wie man sieht waren die Änderungen erfolgreich.

 

Aktivieren der neuen Edition

Damit nun alle Benutzer in den Genuss der neuen Programmversion kommen, muss diese Edition als Standardedition aktiviert werden.

CONNECT / as sysdba ALTER DATABASE DEFAULT EDITION = buchliste_v2;

Jeder Benutzer der sich neu anmeldet arbeitet von dort an mit der neuen Programmversion.

CONNECT buchliste_adm/password SELECT SYS_CONTEXT('USERENV', 'CURRENT_EDITION_NAME') EDITION FROM DUAL;  EDITION ------------------------ BUCHLISTE_V2

Fazit

Mit dem Editions Feature bietet Oracle eine einfache und sichere Methode um Anwendungen im laufenden Betrieb zu aktualisieren. 

Leave a Reply

Your email address will not be published.