Verlagerung von JavaAnwendungen in die Datenbank (Teil II) Autor: Markus Fiegler, ORDIX AG DOAGNews Q3_2005 Dieses Werk ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesondere die der Übersetzung, des Nachdrucks, des Vortrags, der Entnahme von Abbildungen und Tabellen, der Funksendung, der Mikroverfilmung oder der Vervielfältigung auf anderen Wegen und der Speicherung in Datenverarbeitungsanlagen, bleiben, bei auch nur auszugsweiser Verwertung, vorbehalten. Eine Vervielfältigung dieses Werkes oder von Teilen dieses Werkes ist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des Urheberrechtes der Bundesrepublik Deutschland vom 9. September 1965 in der jeweils geltenden Fassung zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen unterliegen den Strafbestimmungen des Urheberrechtsgesetzes. ©2005 Dieser Beitrag richtet sich an Datenbank-Anwendungsentwickler, die sich zusätzlich zum PL/SQL auch für Java als serverseitige Datenbank-Programmiersprache entscheiden können. Im ersten Teil dieser Reihe wurden Java Stored Procedures vorgestellt und die Besonderheiten bei der Entwicklung von Java-Anwendungen für die OracleJVM erläutert. In diesem Teil stellen wir das Resolving-Konzept zum Auffinden aller von einer Klasse benötigten Klassen innerhalb der Datenbank sowie einige Anwendungsmöglichkeiten von Java Stored Procedures vor. Resolving Bei einer herkömmlichen JVM-Umgebung werden alle abhängigen Java-Klassen in Verzeichnissen ermittelt, die sich in der Umgebungsvariable CLASSPATH befinden. In der OracleJVM-Umgebung werden dagegen alle Klassen, die mit dem loadjava-Kommando in die Datenbank geladen wurden, als Datenbank-Objekte innerhalb eines Datenbank-Schemas abgelegt. Aus diesem Grund verfügt die OracleJVM-Umgebung über ein so genanntes Resolving-Konzept. Resolving kann als eine Alternative zum CLASSPATH-Konzept verstanden werden und dient dem Auffinden aller von einer Klasse benötigten Klassen innerhalb der Datenbank. Standardmäßig wird bei dem Resolving-Konzept im Schema des Datenbankbenutzers nach den abhängigen Klassen gesucht. War die Recherche erfolglos, so wird zusätzlich das Schema SYS durchsucht. Resolving-Liste Soll das oben beschriebene Verhalten geändert werden, so kann eine sogenannte ResolvingListe beim Laden der Klassen in die Datenbank festgelegt werden. Eine Resolving-Liste kann beim loadjava-Kommando mithilfe der Option –resolver bestimmt werden. Mit der folgenden Syntax wird festgelegt, dass zuerst im Schema BK, danach im Schema MF und schließlich im Schema PUBLIC nach abhängigen Java-Klassen gesucht werden soll: ((Beginn Programmcode)) loadjava -resolver ((*BK)(*MF)(*PUBLIC)) ... ((Ende Programmcode)) Eine Resolving-Liste kann auch beim direkten Erstellen einer Java-Klasse in der Datenbank mit dem Kommando CREATE JAVA festgelegt werden. Auch wird die Resolving-Liste mit der RESOLVER-Option bestimmt. Das Beispiel in Abbildung 1 legt eine StartProg-Klasse im Datenbank-Schema MF an. Diese StartProg-Klasse referenziert auf eine MitarbeiterKlasse, die sich im Schema BK befindet. ((Beginn Programmcode)) CREATE AND COMPILE JAVA SOURCE NAMED mf.StartProg RESOLVER ((*BK)(*MF)(*PUBLIC)) AS public class StartProg { public static void setGehalt(int ma_nr, int gehalt) { Mitarbeiter.setGehalt(ma_nr, gehalt); } } / ((Ende Programmcode)) Abb. 1: Beispiel mit CREATE JAVA Kommando ©2005 Damit der Datenbank-Benutzer MF auf die Klasse Mitarbeiter im Schema BK zugreifen kann, muss der Datenbank-Benutzer BK dem Datenbank-Benutzer MF folgendes Recht erteilen: ((Beginn Programmcode)) GRANT EXECUTE ON "Mitarbeiter" to mf; ((Ende Programmcode)) Soll eine Resolving-Liste zu einer Klasse geändert werden, so muss die Klasse entweder mit dem loadjava-Kommando neugeladen werden oder mit dem Kommando CREATE JAVA neu erstellt werden. Eine Übersicht über die vorhandenen Resolving-Listen kann über den DBA_JAVA_RESOLVERS-View ermittelt werden. Wichtigster Punkt dabei ist, dass sich eine Resolving-Liste im Gegensatz zum CLASSPATH-Konzept immer nur auf eine JavaKlasse bezieht. Beim CLASSPATH-Konzept wird die Such-Reihenfolge der Klassen für den gesamten Rechner und somit für alle Java-Anwendungen, die auf dem Rechner ablaufen, festgelegt. Veröffentlichung von Java-Klassen in der Datenbank Nachdem die Java-Klassen in die Datenbank geladen wurden, müssen die Signaturen der Java-Klassen im Data Dictionary veröffentlicht werden. Für die Veröffentlichung von JavaKlassen werden die sogenannten PL/SQL-Wrapper verwendet. Mit Hilfe von PL/SQLWrappern werden die Java-Methoden und Parameter-Typen auf die Prozeduren und Parameter-Typen in der Datenbank-Programmiersprache PL/SQL abgebildet. Die PL/SQL-Wrapper werden auch als Aufruf-Spezifikationen, Call Specs oder Java Stored Procedures bezeichnet. Aufruf-Spezifikationen können wie folgt definiert werden: • Aufruf-Spezifikation auf höchster Ebene, das heißt, auf derselben hierarchischen Ebene wie andere Objekte (z. B. Tabellen oder Sichten) • Aufruf-Spezifikation als PL/SQL-Package-Prozedur • Aufruf-Spezifikation als Methode eines Objekt-Typs Das in Abbildung 2 dargestellte Beispiel zeigt eine Aufruf-Spezifikation (Java-StoredProcedure) rechne_java, die auf der höchsten Ebene deklariert wird. Die rechne_java-AufrufSpezifikation startet eine statische Methode rechne aus der Klasse Test und gibt den Parameter bis an die Java-Methode rechne weiter. ((Beginn Programmcode)) CREATE OR REPLACE PROCEDURE rechne_java("bis" IN NUMBER) AS LANGUAGE JAVA NAME 'Test.rechne(int)'; / ((Ende Programmcode)) Abb. 2: Beispiel einer Aufruf-Spezifikation (Java Stored Procedures) Parameterübergabe zwischen PL/SQL und Java In der Datenbank-Programmiersprache PL/SQL können die Parameter einer Prozedur mit folgenden Modi definiert werden: ©2005 • IN (nur lesen) • OUT (nur schreiben) • IN OUT (lesen und schreiben) Bei der Programmiersprache Java hingegen werden die einfachen, primitiven Datentypen wie int oder char als Wert an eine Methode übergeben. Eine Übergabe als Wert bedeutet, dass bei einem Methoden-Aufruf der Parameterwert übergeben beziehungsweise kopiert wird. Änderungen eines derartigen Parameters innerhalb einer Methode haben somit keine Auswirkungen in einer aufrufenden Methode. Die primitiven Java-Datentypen können dadurch als IN-Parameter in der Datenbank-Programmiersprache PL/SQL abgebildet werden. Java-Objekte werden dagegen als Referenz an eine Methode übergeben. Wird eine derartige Objektreferenz innerhalb einer Methode verändert, so hat dies Auswirkungen in einer aufrufenden Methode. Demzufolge können Java-Objekte als IN OUT-Parameter in PL/SQL abgebildet werden. Aufruf von Java Stored Procedures Java Stored Procedures können ähnlich wie eine PL/SQL-Stored-Procedure sowohl aus SQL als auch aus PL/SQL aufgerufen werden. Abbildung 3 zeigt, wie Java Stored Procedures in einer Oracle-Datenbank von externen Client-Anwendungen aufgerufen werden können. Abb. 3: Verwendung von Java Stored Procedures Die Ausgabe von Java Stored Procedures wird standardmäßig in eine Trace-Datei unter dem USER_DUMP_DEST-Verzeichnis auf dem Datenbank-Server geschrieben. Damit die Ausgabe im SQL*Plus auf dem Bildschirm erscheint, müssen folgende Kommandos abgesetzt werden: ((Ende Programmcode)) set serveroutput on exec dbms_java.set_output(10000) ((Ende Programmcode)) Die erste Anweisung legt fest, dass die Ausgaben von PL/SQL-Programmen ausgegeben werden sollen. Mit dem zweiten Kommando wird die Java-Ausgabe aktiviert. Die dbms_java.set_outputProzedur erwartet als Parameter die Größe des Ausgabe-Buffers in Bytes. Der Ausgabe-Buffer kann auf eine Größe zwischen 2000 und 1.000.000 Bytes gesetzt werden. ©2005 Anwendungsmöglichkeiten von Java Stored Procedures - Zugriff auf Dateien In der Datenbank-Programmiersprache PL/SQL besteht die Möglichkeit mittels UTL_FILEPackage auf Dateien zuzugreifen, die sich auf dem Datenbank-Rechner befinden. Das UTL_FILE-Package stellt allerdings nur eine sehr begrenzte Funktionalität zur Verfügung. Java dagegen verfügt über eine weitaus umfangreichere Schnittstelle (API) wie z. B. das java.io-Paket, um auf Dateien des Datenbank-Rechners zuzugreifen. Mit der Java-Schnittstelle ist es unter anderem möglich, Verzeichnisse auf dem Datenbank-Rechner anzulegen und diese zu entfernen. - Dateikomprimierung Eine weitere praktische Anwendungsmöglichkeit von Java Stored Procedures in einer Datenbank ist die Verwendung des java.util.zip-Paketes. Mit dessen Hilfe können Dateien im ZIP-Format komprimiert werden. Sollen Dateien komprimiert in der Datenbank abgelegt werden, so kann das java.util.zip-Paket in einer Java-Stored-Procedure verwendet werden, die wiederum von einem INSERT-Trigger aufgerufen wird. - Integration verschiedener EDV-Systeme Weiterhin können Java Stored Procedures für die Integration verschiedener EDV-Systeme untereinander verwendet werden. Dabei können die verschiedenen EDV-Systeme mit Hilfe der Java Stored Procedures beispielsweise eine gemeinsame Geschäftslogik nutzen oder untereinander Daten austauschen. Abbildung 4 zeigt, wie Java Stored Procedures und externe EDV-Systeme miteinander kommunizieren können. Abb. 4: Integration verschiedener EDV-Systeme mit Java Stored Procedures - Rechenintensive Operationen Sollen in einer Programmeinheit viele rechenintensive Operationen ohne Datenbank-Zugriff durchgeführt werden, so ist die Programmiersprache Java mit Java Stored Procedures der Datenbank-Programmiersprache PL/SQL vorzuziehen. Der Grund hierfür liegt in der Eigenschaft der Programmiersprache Java, die für derartige rechenintensive Operationen optimiert ist. Erfolgen in einer Programmeinheit dagegen viele Datenbank-Zugriffe, so ist die dafür Datenbank-Programmiersprache PL/SQL zu empfehlen. ©2005 Resümee Es wurde aufgezeigt, wie Java-Programme in eine Oracle-Datenbank geladen und in einer OracleJVM ausgeführt werden können. Dabei wurde dargelegt, wie Java-Klassen für die Ausführung im OracleJVM angepasst werden müssen. Es ist deutlich geworden, dass mit Java Stored Procedures die Funktionalität einer Datenbank deutlich erweitert werden kann. JavaFunktionsbibliotheken können in die Datenbank-Programmiersprache PL/SQL mit Hilfe der Java Stored Procedures ohne großen Aufwand integriert und verwendet werden. Damit sinkt der Programmieraufwand, da viele vorhandene Java-Funktionsbibliotheken wie Logging-Mechanismen oder Assertions eingebunden werden können, ohne diese in PL/SQL neu entwickeln zu müssen. Ein weiterer Vorteil von Java Stored Procedures ist die Datenbank-Unabhängigkeit. Die Java Stored Procedures werden in der Programmiersprache Java erstellt und können auf jedem Rechnersystem mit Hilfe einer Java-Virtual-Machine interpretiert und ausgeführt werden. Zudem wird der Datenbank-Zugriff einer Java-Stored-Procedure mit einem JDBCDatenbanktreiber sichergestellt. Dieser ist für alle herkömmlichen Datenbank-Systeme verfügbar. Im Verhältnis zu einer herkömmlichen Java-Web-Anwendung sinkt bei der Verwendung von Java Stored Procedures die Programm-Ausführungszeit. Denn die Java Stored Procedures sind in der Datenbank abgelegt und es ist ein direkter Daten-Zugriff innerhalb der Datenbank möglich. Damit wird die Netzlast minimiert und demzufolge eine gute Performance erzielt. Abschließend lässt sich feststellen, dass die Programmiersprache Java zusätzlich zu der traditionellen und anerkannten Datenbank-Programmiersprache PL/SQL für die serverseitige Datenbank-Programmierung genutzt werden kann. Diese beiden Programmiersprachen schließen sich für die serverseitige Datenbank-Programmierung nicht aus, sondern können sich ergänzen. Literaturhinweis [ORAOJ2002] Oracle und Java, Datenbankentwicklung für E-Commerce-Anwendungen, Elion Bonazzi, Glenn Stokol, Markt+Technik Verlag, 2002 [ORAUP2002] Unleash the Power of Java Stored Procedures, Oracle Corporation, http://otn.oracle.com/, 2002 [ORASJ2004] Simplify with Java Stored Procedures, Oracle Corporation, http://otn.oracle.com/, 2004 [ORADG2004] Oracle10g, Java Developer's Guide Release 1 (10.1), Oracle Corporation, 2004 Kontakt: Markus Fiegler [email protected] ©2005