Willkommen Objektorientierte PL/SQL-Programmierung für RDBMS Andriy Terletskyy Berenberg Bank Neuer Jungfernstieg 20 20354 Hamburg Berenberg stellt sich vor MDV/EDV- Erfahrung • • • • • • • Zeitraum Hardware Datenbank Pr. Sprache 1590 – ~ 1950 ~ 1960 ~ 1970 ~ 1980 ~ 1990 ~ 1995 ~ 2001 Rechenbrett Buchungsautomaten NCR Century 201 NCR 8000/9800 NCR 3600 NCR S-50 Sun 3800 Cluster Karteikarten Karteikarten MIDAS TOTAL Supra PDM Oracle 8.0 Oracle 8.1 - 9.2 Neat Cobol Cobol Cobol PL/SQL, Java Modellierung Traditionelle ODBMS Virtuelle ODBMS auf Basis RDBMS BO-TYPES OBJECT TYPES OO-ROWTYPES ODBMS RDBMS Aufbau traditionelle ODBMS Aufbau • Definition Basis Typen • Abbildung Real-Welt Objekten in BOTypen • Aufbau OO-Tabellen OBJECT TYPES Verwendung • übliche DML- Anweisungen • Datennormalisierung über OID • DEREF - zieht referenzierte Object Größter Nachteil • Änderungsunfähig, bzw. schwerfällig ( … IS DANGLING) ODBMS Aufbau virtuelle ODBMS für RDBMS BO-TYPES OO-ROWTYPES Aufbau • RDBMS (neue oder bestehende) • Aufbau OO-ROWTYPE (ROWTYPE + DML, DEFAULT, TO_STRING, DBMS_OUTPUTMethoden, PK/UK- Konstruktoren ) • Aufbau BO- Typen (Vererbung, Aggregation, Assoziation) Verwendung • Methoden statt übliche DML- Anweisungen • Datennormalisierung über RDBMS • PK/UK- Konstruktoren - ziehen referenzierte Object über relationale ID (DEREF- Analogon) Größter Nachteil • Aufwandbedürftig für OO-ROWTYPE Aufbau (Lösung : automatische Generierung oder Herstellerimplementierung) RDBMS Implementierung 1/8 1. Einführung TYPE_OBJECT – Basisklasse für alle abgeleiteten Object Types (optional) CREATE OR REPLACE TYPE SCOTT.TYPE_OBJECT AS OBJECT( -- attributes object_type_name VARCHAR2(100) -- member functions and procedures , MEMBER FUNCTION TO_STRING RETURN VARCHAR2 , MEMBER PROCEDURE DBMS_OUTPUT , MEMBER FUNCTION COMPARE(in_type1 TYPE_OBJECT, in_type2 TYPE_OBJECT) RETURN INTEGER , ORDER MEMBER FUNCTION COMPARE2(in_other TYPE_OBJECT) RETURN INTEGER ) NOT FINAL NOT INSTANTIABLE Vorteile: • Standardisiertes Interface für alle abgeleiteten Objekte (TO_STRING, DBMS_OUTPUT) • Einfache Übergabe abgeleiteter Typen als Parameter (Ursprungshierarchie) • ORDER Funktion - vergleicht Instanzen wegen überschriebener COMPARE- Methode Implementierung 2/8 2.1. Einführung OO-ROWTYPE CREATE OR REPLACE TYPE SCOTT.ROW_DEPT UNDER SCOTT.TYPE_OBJECT( -- attributes deptno NUMBER(2) , dname VARCHAR2(14) , loc VARCHAR2(13) -- constructors , CONSTRUCTOR FUNCTION ROW_DEPT RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION ROW_DEPT( in_deptno NUMBER, in_dname VARCHAR2 , in_loc VARCHAR2) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION ROW_DEPT(in_deptno NUMBER) RETURN SELF AS RESULT -- member functions , MEMBER FUNCTION ROW_EXISTS(in_deptno NUMBER) RETURN BOOLEAN , OVERRIDING MEMBER FUNCTION COMPARE( in_type1 GLOBAL.TYPE_OBJECT , in_type2 GLOBAL.TYPE_OBJECT) RETURN INTEGER -- member procedures , MEMBER PROCEDURE ROW_INSERT , MEMBER PROCEDURE ROW_UPDATE , MEMBER PROCEDURE ROW_MERGE , MEMBER PROCEDURE ROW_SAVE , MEMBER PROCEDURE ROW_DELETE , MEMBER PROCEDURE ROW_SELECT(in_deptno NUMBER) , MEMBER PROCEDURE ROW_DEFAULT ) NOT FINAL Implementierung 3/8 2.1. Einführung OO-ROWTYPE CREATE OR REPLACE TYPE SCOTT.ROW_EMP UNDER SCOTT.TYPE_OBJECT( -- attributes empno NUMBER(4) , ename VARCHAR2(10) , job VARCHAR2(9) , mgr NUMBER(4) , hiredate DATE , sal NUMBER(7,2) , comm NUMBER(7,2) , deptno NUMBER(2) -- constructors , CONSTRUCTOR FUNCTION ROW_EMP RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION ROW_EMP( in_empno NUMBER, in_ename VARCHAR2, in_job VARCHAR2, in_mgr NUMBER , in_hiredate DATE, in_sal NUMBER, in_comm NUMBER, in_deptno NUMBER ) RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION ROW_EMP(in_empno NUMBER) RETURN SELF AS RESULT -- member functions , MEMBER FUNCTION ROW_EXISTS(in_empno NUMBER) RETURN BOOLEAN , OVERRIDING MEMBER FUNCTION compare( in_type1 GLOBAL.TYPE_OBJECT, in_type2 GLOBAL.TYPE_OBJECT ) RETURN INTEGER -- member procedures , MEMBER PROCEDURE ROW_INSERT , MEMBER PROCEDURE ROW_UPDATE , MEMBER PROCEDURE ROW_MERGE , MEMBER PROCEDURE ROW_SAVE , MEMBER PROCEDURE ROW_DELETE , MEMBER PROCEDURE ROW_SELECT(in_empno NUMBER) , MEMBER PROCEDURE ROW_DEFAULT ) NOT FINAL Implementierung 4/8 2.2. Einführung OO-ROWTYPE Container Types und Data-Cartridges • Container Types CREATE OR REPLACE TYPE TABLE_EMP AS TABLE OF SCOTT.ROW_EMP; CREATE OR REPLACE TYPE TABLE_DEPT AS TABLE OF SCOTT.ROW_DEPT; • Data-Cartridge für DEPT-Tabelle CREATE OR REPLACE PACKAGE PA_DEPT IS FUNCTION FU_SELECT RETURN TABLE_DEPT; END; • Data-Cartridge für EMP-Tabelle CREATE OR REPLACE PACKAGE PA_EMP IS FUNCTION FU_SELECT RETURN TABLE_EMP; FUNCTION FS_DEPTNO(IN_DEPTNO IN EMP.DEPTNO%TYPE) RETURN TABLE_EMP; FUNCTION FS_MGR(IN_MGR IN EMP.MGR%TYPE) RETURN TABLE_EMP; END; Implementierung 5/8 2.3. Automatische Generierung OO-ROWTYPEs, Container Types und Data-Cartridges • Generator (generiert, kompiliert und bewährt Sourcen) – Java-Klasse (liest TABLE Definition und generiert PL/SQL-Source) – PL/SQL Wrapper – Prozedur (ruft Java-Klasse auf) • DDL-Trigger (empfängt CREATE / ALTER TABLE Ereignis und schickt AQ-Message) • Oracle-Job (empfängt AQ-Message und anstoßt Generator ) Implementierung 6/8 3.1. Einführung BO-Types (TYPE_ MANAGER) CREATE OR REPLACE TYPE TYPE_MANAGER UNDER ROW_EMP( -- attributes EMPLOYEES TABLE_EMP -- constructors , CONSTRUCTOR FUNCTION TYPE_MANAGER RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_MANAGER(IN_EMPNO NUMBER) RETURN SELF AS RESULT ) NOT FINAL Implementierung 7/8 3.2. Einführung BO-Types (TYPE_DEPARTMENT) CREATE OR REPLACE TYPE TYPE_DEPARTMENT UNDER ROW_DEPT( -- attributes EMPLOYEES TABLE_EMP -- constructors , CONSTRUCTOR FUNCTION TYPE_DEPARTMENT RETURN SELF AS RESULT , CONSTRUCTOR FUNCTION TYPE_DEPARTMENT(in_deptno NUMBER) RETURN SELF AS RESULT -- member functions , MEMBER FUNCTION GET_MANAGER RETURN TYPE_MANAGER ) NOT FINAL Implementierung 8/8 3.3. Einführung BO-Types (TYPE_ENTERPRISE) CREATE OR REPLACE TYPE TYPE_ENTERPRISE UNDER TYPE_OBJECT( -- attributes NAME VARCHAR2(100) , PRESIDENT TYPE_MANAGER , DEPARTMENTS TABLE_DEPT , EMPLOYEES TABLE_EMP -- constructors , CONSTRUCTOR FUNCTION TYPE_ENTERPRISE RETURN SELF AS RESULT ) NOT FINAL Programmierung 1/3 1. SQL SQL> SELECT TYPE_DEPARTMENT(20) FROM DUAL; TYPE_DEPARTMENT()(OBJECT_TYPE_NAME, DEPTNO, DNAME, LOC, NAME, TABLE_EMP(ROW_EMP()) -------------------------------------------------------------------------------TYPE_DEPARTMENT('TYPE_DEPARTMENT', 20, 'RESEARCH', 'DALLAS', TABLE_EMP( ROW_EMP('ROW_EMP', 7369, 'SMITH', 'CLERK', 7902, '17.12.80', 800, NULL, 20), ROW_EMP('ROW_EMP', 7566, 'JONES', 'MANAGER', 7839, '02.04.81', 2975, NULL, 20), ROW_EMP('ROW_EMP', 7788, 'SCOTT', 'ANALYST', 7566, '19.04.87', 3000, NULL, 20), ROW_EMP('ROW_EMP', 7876, 'ADAMS', 'CLERK', 7788, '23.05.87', 1100, NULL, 20), ROW_EMP('ROW_EMP', 7902, 'FORD', 'ANALYST', 7566, '03.12.81', 3000, NULL, 20) ) ) SQL> SELECT VALUE(e) FROM TABLE (TYPE_MANAGER(7698).EMPLOYEES) e; VALUE(E)(OBJECT_TYPE_NAME, EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO) -------------------------------------------------------------------------------ROW_EMP('ROW_EMP', 7499, 'ALLEN', 'SALESMAN', 7698, '20.02.81', 1600, 300, 30) ROW_EMP('ROW_EMP', 7521, 'WARD', 'SALESMAN', 7698, '22.02.81', 1250, 500, 30) ROW_EMP('ROW_EMP', 7654, 'MARTIN', 'SALESMAN', 7698, '28.09.81', 1250, 1400, 30) ROW_EMP('ROW_EMP', 7844, 'TURNER', 'SALESMAN', 7698, '08.09.81', 1500, 0, 30) ROW_EMP('ROW_EMP', 7900, 'JAMES', 'CLERK', 7698, '03.12.81', 950, NULL, 30) Programmierung 2/3 2.1. PL/SQL DECLARE e TYPE_ENTERPRISE := TYPE_ENTERPRISE(); BEGIN e.dbms_output; END; / DBMS Output: SCOTT.TYPE_ENTERPRISE ( OBJECT_TYPE_NAME = TYPE_ENTERPRISE NAME = King Corporation PRESIDENT = SCOTT.TYPE_MANAGER ( OBJECT_TYPE_NAME = TYPE_MANAGER EMPNO = 7839 ENAME = KING JOB = PRESIDENT MGR = HIREDATE = 17.11.1981 00:00:00 SAL = 5000 COMM = DEPTNO = 10 EMPLOYEES = < SCOTT.TABLE_EMP > ) DEPARTMENTS = < SCOTT.TABLE_DEPT > EMPLOYEES = < SCOTT.TABLE_EMP > ) Programmierung 3/6 2.2. PL/SQL DECLARE m TYPE_MANAGER; BEGIN m := TYPE_MANAGER(7839); m.sal := m.sal * 2; m.row_update; m.dbms_output; END; / DBMS Output: SCOTT.TYPE_MANAGER ( OBJECT_TYPE_NAME = TYPE_MANAGER EMPNO = 7839 ENAME = KING JOB = PRESIDENT MGR = HIREDATE = 17.11.1981 00:00:00 SAL = 10000 COMM = DEPTNO = 10 EMPLOYEES = < SCOTT.TABLE_EMP > ) Zusammenfassung (virtuelle ODBMS) • keine Funktionalitätsverluste gegenüber der bestehenden ODBMS Lösung • Das Objektmodel entspricht dem relationalen Datenmodel und kann ohne Änderung am relationalen Datenmodel erzeugt und verwendet werden • Vereinfachung der DML-Anweisungen • Zugriffe der Business Objekte (BO) sind unabhängig von der unterliegenden Datenquelle • DB-Mapping für Java (JPublisher oder selbst geschriebene Generatoren) Java DB-Mapping 1/2 1. Type-Mapping PL/SQL-TYPE Attribute 1 …. Attribute N Constructor(p1,...) Function F1(p1,..) Procedure P2(p1,…) Java-Class JDBC, SQLData Attribute 1 …. Attribute N Constructor(con,p1,...) Methode F1(con,p1,..) Methode P2(con,p1,…) Java DB-Mapping 2/2 2. Package-Mapping Class Record 1 PL/SQL-Package Cursor 1 of Record 1 …. Cursor N of Record N Java-Class JDBC OUT_F1 OUT_P2 Parameter 1 Parameter 1 Parameter N Parameter N Attribute 1 …. Attribute N Class Record N Function F1(p1,..) Procedure P2(p1,…) Constructor(con) Methode F1(con,p1,..) Methode P2(con,p1,…) Attribute 1 …. Attribute N Gewünschte Nachbesserung von Architekturnachteilen • Object-Typen unterstützen nicht ROWID, %TYPE und INDEX BY TABLE • ein Type kann nicht Container von eigenen Instanzen referenzieren • ein SUPER –Attribut fehlt • die entsprechendes Gegenstück der z.B. in Java existierenden Interfaces fehlt (deswegen beinhaltet TYPE_OBJECT das überflüssige Attribute OBJECT_TYPE_NAME) • ein Type, der von einem anderen Type vererbt ist, oder von einem Container referenziert wird, kann mittels REPLACE nicht mehr ersetzt werden (DROP TYPE FORCE und anschließende Grants) Q&A • Objektorientierte PL/SQL-Programmierung, Andriy Terletskyy, Michael Meyer, DOAG News Q3/2004, s.31-35 • Objektorientierte PL/SQL-Programmierung, Andriy Terletskyy, 17. Deutsche ORACLE- Anwenderkonferenz 10./11. November 2004, CCM Congress Center Mannheim; s.207-215 • Alternative zu J2EE Enterprise- Applicationen mit wenig Ballast, Manfred Emmelmnn, Stephan Koop, Jürgen Hoffmann, Tim Lechler, Carsten Paschilke, Andriy Terletskyy, Javamagazin 01/2005, s.49-59