Java, XML und Oracle Database 10g – What's new? Carsten Czarski Oracle Deutschland GmbH München Schlüsselworte Java, JDBC, Anwendungsentwicklung, Web Services, XML, XML Schema Evolution, XML Zeichensatz Zusammenfassung Oracle 10g steht im Zeichen des Grid Computing. Daher liegen die Entwicklungsschwerpunkte bei der Optimierung der Cluster-Fähigkeiten und der Vereinfachung der Administration. Im Gegensatz zu Oracle8, Oracle8i und Oracle9i wird mit Oracle10g kein neues Paradigma für die Anwendungsentwicklung eingeführt. Entwickler, die sich mit Oracle10g beschäftigen, finden jedoch viele Einzelverbesserungen und Erweiterungen zu bereits vorhandener Funktionalität vor. Dieser Artikel beschäftigt sich mit den Neuerungen im Java- und XML-Umfeld. Der erste Abschnitt widmet sich dem JDBC Treiber, der für den Java-Entwickler von besonderem Interesse ist. Die Laufzeitumgebung für Java (JVM), die seit Oracle8i in die Datenbank integriert ist, steht im Mittelpunkt des zweiten Abschnittes. Insbesondere die neue Möglichkeit, externe Web Services aus der Datenbank heraus ansprechen zu können, wird hier ausführlich dargestellt. Der letzte Abschnitt beschäftigt sich mit den Neuerungen hinsichtlich der nativen Unterstützung von XML-Dokumenten in der Oracle-Datenbank JDBC Die JDBC Spezifikation trägt derzeit die Versionsnummer 3.01. JDBC 3.0 ist Bestandteil von Java 1.4 und wird auch Bestandteil von J2EE 1.4 sein. Einige Anforderungen von JDBC 3.0 wurden bereits in die Oracle9i JDBC-Treiber (9.2.0) implementiert. Dazu gehören die Unterstützung für Savepoints oder das Umschalten zwischen lokalen und globalen Transaktionen im XA-Umfeld. Diese Unterstützung wird mit Oracle10g weiter vervollständigt. Im folgenden sind die wichtigsten Neuerungen beschrieben. Named Parameter Bislang erlaubte der JDBC-Standard beim Aufruf von gespeicherten Prozeduren, Funktionen oder SQL-Kommandos nur positional binding. Dies entspricht den Konventionen von Java oder auch C bzw. C++ und bedeutet, dass die übergebenen Parameter nach Ihrer Position zugeordnet werden. Statement.setString(1, “Max Mustermann”); Named binding bedeutet, dass Parameter anhand Ihres Namens übergeben werden können, bei einem INSERT Befehl also anhand des Namens der Tabellenspalte. Statement.setString(“NAME”, “Max Mustermann”); Diese Art der Parameterübergabe ist PL/SQL-Entwicklern bekannt. begin anyFunction( name_parameter => ‘Max Mustermann’, alter_parameter=> 50 ); end; Named Binding ist insbesondere dann von Vorteil, wenn sich die Spalten einer Tabelle oder die Parameter einer gespeicherten Prozedur ändern. Die Aufrufe dieser Prozeduren oder Funktionen müssen dann meist nicht angepasst werden. JDBC Connection Cache Im J2EE-Umfeld ist es üblich, Connection-Pooling zu nutzen. Eine J2EE-Komponente entnimmt Datenbankverbindungen nur für kurze Zeit aus dem Pool und gibt sie nach Gebrauch sofort wieder zurück. 1 Ausführliche Informationen zu JDBC 3.0 können auf der Internet Seite von Sun http://java.sun.com/products/jdbc/download.html#corespec30 gefunden werden. unter Bislang mussten alle Datenbankverbindungen in einem JDBC Connection-Pool unter dem gleichen Benutzerkonto an der gleichen Datenbank angemeldet sein. Der Connection Cache in Oracle10g erlaubt es, Datenbankverbindungen in ein- und demselben Connection-Pool sowohl unter verschiedenen Benutzerkonten als auch zu verschiedenen Datenbanken herzustellen. Dies ist insbesondere beim Betrieb von Oracle Real Application Cluster (RAC) wichtig. Der Connection-Pool kann Verbindungen zu allen Knoten im Cluster enthalten und die Last automatisch auf alle Knoten verteilen. Wenn der Connection-Pool nicht auf den zwischenzeitlichen Absturz eines Knotens reagieren würde, würde das zur Auslieferung ungültiger Datenbankverbindungen an die Anwendung führen. Fast Connection Failover verhindert dies. Beim Absturz eines Clusterknotens wird mittels Oracle Process Monitoring and Notification (opmn) eine Nachricht an den Connection-Pool gesendet. Daraufhin werden die Verbindungen zu diesem Clusterknoten ungültig; der Connection-Pool verteilt die Last auf die verbleibenden Knoten. Der Connection-Pool reagiert auch auf das Wiederanlaufen des abgestürzten Knotens. In diesem Fall werden die Datenbankverbindungen und damit die Last automatisch neu über alle Knoten verteilt. Fast Connection Failover bezieht sich jedoch nur auf Datenbankverbindungen im ConnectionPool, die gerade nicht in Benutzung sind. Wird die Datenbankverbindung gerade verwendet, während der Knoten abstützt, führt dies zu einer Fehlermeldung (SQLException). Die Anwendung sollte in diesem Fall eine neue Datenbankverbindung aus dem Connection-Pool holen. Fast Connection Failover basiert auf der bereits beschriebenen Tatsache, dass Datenbankverbindungen im J2EE-Umfeld nur für kurze Zeit aus dem Pool entnommen werden. Homeless OCI Install Die Nutzung des JDBC OCI Treibers hat sich mit Oracle10g stark vereinfacht. Da der OCI Treiber auf den Bibliotheken des Oracle Call Interface (OCI) aufsetzt, war bislang zumindest die Installation der Oracle Client-Software erforderlich. Im Unterverzeichnis ezclient im ORACLE_HOME der Oracle10g-Software befindet sich das Oracle Call Interface vollständig und ohne weitere Abhängigkeiten. Wenn diese Dateien sich in den Umgebungsvariablen LD_LIBRARY_PATH bzw. PATH wiederfinden, kann das OCI oder der JDBC OCI Treiber ohne weitere Abhängigkeiten genutzt werden. Ein einfaches Kopieren der Bibliotheksdateien reicht daher zur Installation des OCI aus. JDBC Web RowSet JDBC Web RowSet ist eine Implementierung des JSR-1142. Es stellt eine API zur Verfügung, die aus der Ergebnismenge eines SELECT-Kommandos (ResultSet) oder einer anderen Datenquelle ein XML-Dokument erstellt. Das folgende Codebeispiel zeigt, wie – ausgehend von einem JDBC ResultSet – mit dem JDBC Web RowSet ein XML Dokument erzeugt und ausgegeben wird. import oracle.jdbc.rowset.OracleWebRowSet; : : ResultSet rs = statement.executeQuery(“select ... from ...”); OracleWebRowSet west = new OracleWebRowSet(); wset.populate(rset); wset.writeXml(new PrintWriter(System.out)); : Diese Funktionalität ist noch nicht Bestandteil des JDBC-Standards. Daher befindet sie sich in einer eigenen Java-Bibliothek. Nach Installation der Datenbank ist diese unter $ORACLE_HOME/jdbc/lib/ocrs12.jar zu finden. Datenbankinterne JVM Die Java-Laufzeitumgebung in der Datenbank wurde weiterentwickelt und unterstützt nun den aktuellen Stand 1.4. Damit werden Funktionalitäten wie bspw. die Java Logging-API auch in der Datenbank nutzbar. Ein großer Vorteil der Java stored Procedures in der Oracle-Datenbank ist, dass sie mit einem PL/SQL-Wrapper versehen werden können. Nach außen hin erscheinen so alle gespeicherten Prozeduren unabhängig von ihrer tatsächlichen Implementierung als PL/SQL. Wenn Java für bestimmte Aufgaben besser geeignet ist als PL/SQL (z.B. XML-Parsing), kann diese JavaImplementierung problemlos mit PL/SQL integriert werden. Sollen in Java implementierte Prozeduren jedoch von außen aufgerufen werden, ist dieses Verfahren sehr umständlich. Wie in Abb. 1 erkennbar ist, finden gleich zwei Context Switches statt, wobei die übergebenen Parameter zwischen Java und PL/SQL konvertiert werden müssen. Die erste Datenkonvertierung findet beim Aufruf des PL/SQL Wrappers durch JDBC statt. Die Parameter werden von der Java- in die PL/SQL Repräsentation konvertiert. Gleich darauf wird die eigentliche Java-Implementierung aufgerufen, was zu einer Rückkonvertierung in die JavaRepräsentation führt. 2 JSR steht für Java Specification Request. Eine JSR ist somit eine im Standardisierungsprozeß befindliche Java Funktionalität. Details zu JSP-114 können unter http://www.jcp.org/en/jsr/detail?id=114 gefunden werden. Abb. 1: Zugriff auf gespeicherte Prozeduren in Java außen mit Oracle9i In Oracle10g kann dieser Umweg vermieden werden. Abb. 2 zeigt, wie das Java native Interface genutzt wird. Abb. 2: Zugriff auf gespeicherte Prozeduren in Java von außen mit Oracle10g Die Verwendung des native Interface erfordert keinen hohen Aufwand. Das jpub-Werkzeug kann genutzt werden, um die notwendigen Client-Stubs zu erstellen. Der Aufruf ist im folgenden dargestellt. jpub –java=oracle.sqlj.checker.JdbcVersion Das Werkzeug generiert den Quellcode für die Client-Stubs und legt ihn in der Datei JdbcVersion.java ab. Bei Verwendung dieser Stub-Klasse muss dem Konstruktor ein Objekt vom Typ eines SQLJ DefaultContext oder einer JDBC Connection übergeben werden. Alle Methoden der serverseitigen Java-Klasse stehen dann zur Verfügung und können transparent verwendet werden. Database Web Services Die Bedeutung von Web Services nimmt auch im kommerziellen Umfeld immer mehr zu. Prozeduren und Funktionen, die als Web Service implementiert sind, stehen für Aufrufe mit SOAP3 über HTTP zur Verfügung. Da die Kommunikation mit Web Services mittels SOAP standardisiert ist, ist die eigentliche Implementierung des Web Service für den Aufruf nicht wichtig. Ein in der J2EE Architektur implementierter Web Service kann durchaus aus einer .NET-Umgebung aufgerufen werden und umgekehrt. Abb. 3: Aufruf externer Web Services aus der Datenbank. Jeder Web Service wird durch ein standardisiertes XML-Dokument beschrieben. Dieses Dokument wird als WSDL-Dokument4 bezeichnet. Ein Beispiel dafür zeigt Abb. 4. Das WSDLDokument enthält zum Aufruf des Web Service nötigen Angaben. Die Clients selbst können in zwei Varianten implementiert werden. Der Code für Statische Clients wird vollständig anhand des WSDL-Dokumentes generiert. Da die Eigenschaften bereits zur Compile-Zeit festgelegt sind, kann der Client schneller entwickelt werden und ist weniger anfällig für Fehler. Es kann jedoch nur der Web Service, für den der Client generiert wurde, aufgerufen werden. Dynamische Clients sind in der Lage, in einem UDDI5 Repository nach Web Services zu suchen, das WSDL Dokument herunterzuladen um anschließend den Web Service aufzurufen. Der hohen 3 Soap steht für Simple Object Access Protocol3. Stark vereinfacht ausgedrückt ist SOAP RPC mit XMLDokumenten über das HTTP-Protokoll. Die Standardisierung wird vom World Wide Web Consortium (W3C) vorangetrieben („http://www.w3.org/2000/xp/Group/“) 4 WSDL steht für Web Services Description Language. Die Spezifikation wird vom W3C gepflegt und ist unter http://www.w3.org/TR/wsdl zu finden. 5 UDDI steht für Universal Discovery and Description Interface. Ein UDDI Repository dient als Verzeichnis für Web Services. Anhand von Anforderungen kann das UDDI Repository nach Web Services durchsucht werden. Wurde ein Flexibilität stehen hier mehr Entwicklungsaufwand und höhere Anfälligkeit für Fehler gegenüber. Dieser Artikel beschränkt sich auf statische Clients. Oracle10g kann Web Services auch dynamisch aufrufen, der Entwicklungsaufwand ist jedoch – wie bereits beschrieben – höher. Auch hier sei auf die einschlägige Literatur zum Umgang mit UDDI Repositories und WSDLDokumenten verwiesen. Abb. 4: WSDL-Dokument eines Web Service (Devisenkurse) Der Code für den statischen Client kann vollständig mit dem jpub-Werkzeug generiert werden. Der Aufruf ist im folgenden dargestellt. jpub -proxywsdl=http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl –user=scott/tiger -package=webservices.currencyexchange -plsqlpackage=WS_CURRENCY Web Service gefunden, kann das ihn beschreibende WSDL-Dokument vom UDDI Repository heruntergeladen werden. Die Spezifikation wird von OASIS gepflegt und kann unter http://www.oasisopen.org/committees/uddi-spec/tcspecs.shtml gefunden werden. Der Parameter proxywsdl gibt dabei an, wo das WSDLDokument zu finden ist. Eine Position im lokalen Dateisystem kann ebenso angegeben werden, wie eine URL im Internet. Der Parameter package legt fest, welchen Namen das Java-Package für den generierten Java-Code erhalten soll. Mit diesen Angaben erzeugt das jpub-Werkzeug die rechts dargestellte Datei- und Verzeichnisstruktur. Darüber hinaus werden die Java-Klassen automatisch in die Datenbank geladen. Wenn dies unterdrückt werden soll, sollte die folgende Variante des Aufrufs verwendet werden. jpub -proxywsdl=http://www.xmethods.net/sd/2001/CurrencyExchangeService.wsdl –proxyopts=noload -package=webservices.currencyexchange -plsqlpackage=WS_CURRENCY -user=scott/tiger Bei der Code-Generierung wird der JAX-RPC6 Standard verwendet. Die Klassen unterhalb Verzeichnis JPubWSDLGenerated liegen nicht als Quellcode vor. Änderungen sind hier auch nicht erforderlich. Die Datei CurrencyExchangeService.java dient als Einstiegspunkt von außen. Da sie im Quellcode vorliegt, können hier Anpassungen oder zusätzliche Einstellungen vorgenommen werden. Nach außen steht nun die Methode getRate zur Verfügung. Sie kann von anderen Java-Klassen in der Datenbank transparent verwendet werden. Wenn sie aufgerufen wird, reicht sie den Aufruf an die generierten Client-Stubs weiter. Die SOAP-Kommunikation über HTTP wird komplett von diesen Klassen abgewickelt. Die Java-Laufzeitumgebung ist eng mit dem Sicherheitskonzept der Datenbank verknüpft. Dies ist auch für den Aufruf eines Web Service relevant, da hier Netzwerkverbindungen geöffnet werden. Normalerweise hat ein Datenbank-User hierzu nicht das Recht. Der folgende Aufruf erteilt dem User SCOTT das Recht, durch die Java-Laufzeitumgebung beliebige Netzwerkverbindungen zu öffnen. 6 JAX-RPC steht für Java API for XML Remote Procedure Calls. Dies ist ein Standard für eine Java API zum Aufruf von Web Services. JAX-RPC wird Bestandteil von J2EE 1.4 sein. Weitere Informationen sind unter http://java.sun.com/xml/jaxrpc/index.html zu finden. begin dbms_java.grant_permission( 'SCOTT', 'SYS:java.net.SocketPermission', '*', '*' ); end; Die Datei plsql_grant.sql wurde für diesen Zweck bereits von jpub erzeugt. Es muss als SYS oder SYSTEM gestartet werden. Im nächsten Schritt wird der Web Service zusätzlich für SQL und PL/SQL verfügbar gemacht. Dazu dient das ebenfalls erzeugte Skript plsql_wrapper.sql. Es legt ein PL/SQL Package mit Namen WS_CURRENCY an. Das Paket enthält die Funktion getRate. Diese Funktion kann nun in jedem SQL-Kommando verwendet werden. SELECT WS_CURRENCY.GETRATE(‘EUR’,’USD’) as EXCHANGE_RATE from dual; EXCHANGE_RATE ------------.8458 Für die weitere Verwendung sind der Phantasie keine Grenzen gesetzt. Informationen, die von Web Services geliefert werden, können in die Definition von Views ebenso aufgenommen werden wie in komplexe ETL-Prozesse eines Data-Warehouse. XML Im Bereich XML stand vor allem die Optimierung der Performance im Vordergrund. Die XML DB wurde in Teilbereichen erweitert. Die folgenden Abschnitte beschreiben die wichtigsten Neuerungen. Zeichensatz Oracle10g erlaubt auch für Zugriffe mit FTP oder WebDAV die Festlegung eines bestimmten Zeichensatzes. Dies war in Oracle9i nur für Zugriffe mit SQL*Plus möglich (NLS_LANG). Oracle10g richtet sich für WebDAV oder HTTP-Anfragen nach dem Inhalt des Feldes AcceptCharset im HTTP-Header. Für FTP-Zugriffe wurde ein neues Kommando eingeführt. Es kann als sog. Quote-Command wie folgt gesetzt werden. ftp> quote set_charset iso-8859-1 Schema Evolution Mitunter besteht die Notwendigkeit, die Strukturen der in der Datenbank gespeicherten XMLDokumente zu ändern. Da diese Strukturen nach dem W3C-Standard mit einem XML Schema7 beschrieben werden, wird der Vorgang als Schema Evolution bezeichnet. Darunter fällt jede denkbare Strukturänderung. Das Entfernen von Elementen oder Attributen muss ebenso möglich sein wie das Hinzufügen. Wenn die XML-Dokumente dokumentorientiert als CLOB abgelegt werden, verursacht die Änderung der Strukturen keinen zusätzlichen Aufwand. Die neuen Dokumente werden einfach zu den alten in die gleiche oder in eine neue Tabelle hinzugefügt. 7 Die Spezifikation für XML Schema wird http://www.w3.org/XML/Schema gefunden werden. vom W3C gepflegt und kann unter Die objektrelationale Speicherung der XML-Dokumente erfordert bei Strukturänderungen etwas mehr Aufwand, denn hier werden die XML-Strukturen als Objektmodell in der Datenbank nachgebildet. Bei einer Änderung gibt es zwei Optionen: • Die alte Struktur soll neben der neuen weiterhin existieren. • Die neue Struktur soll die alte ersetzen. Dies bedeutet jedoch, dass die bestehenden XMLDokumente zur neuen Struktur migriert werden müssen. Wird bspw. ein Element hinzugefügt, so müssen auch alle alten Dokumente dieses Element erhalten. Wenn die alte Struktur weiter existieren soll, empfiehlt es sich, das neue XML Schema zusätzlich zum alten zu registrieren. Anschließend existieren in der Datenbank zwei Tabellen, eine enthält die XML-Dokumente mit der alten Struktur, die andere nimmt die mit der neuen Struktur auf. Wenn die alte Struktur ersetzt werden soll, so müssen die Dokumente entladen, transformiert und wieder neu geladen werden. In Oracle9i waren dazu folgende manuelle Schritte erforderlich: 1. Alle objektrelational XML-Dokumente werden in eine andere Tabelle ausgelagert. Der Datentyp dieser Tabelle ist wiederum XMLTYPE, die Speicherungsform sollte jedoch CLOB-basiert sein. 2. Die ausgelagerten Dokumente werden auf die neue Struktur transformiert. Diese Aufgabe kann ein XSL-Stylesheet in Verbindung mit der SQL-Funktion XMLTransform() übernehmen. Dieser Schritt kann auch in einem Schnitt mit der Auslagerung erfolgen. 3. Das registrierte XML Schema wird gelöscht. Alle objektrelational gespeicherten Dokumente werden damit ebenfalls gelöscht. 4. Das neue XML Schema wird registriert. 5. Die transformierten Dokumente werden in die objektrelationale XML-Tabelle übernommen. 6. Die Auslagerungstabelle wird gelöscht. Da diese manuelle Vorgehensweise sehr fehleranfällig ist, wurde sie in Oracle10g automatisiert. Das Paket DBMS_XMLSCHEMA enthält die Funktion COPYEVOLVE. PROCEDURE COPYEVOLVE Argument Name -----------------------------SCHEMAURLS NEWSCHEMAS TRANSFORMS PRESERVEOLDDOCS Type ----------------------XDB$STRING_LIST_T XMLSEQUENCETYPE XMLSEQUENCETYPE BOOLEAN In/Out -----IN IN IN IN Default? -------- DEFAULT DEFAULT MAPTABNAME GENERATETABLES FORCE SCHEMAOWNERS VARCHAR2 BOOLEAN BOOLEAN XDB$STRING_LIST_T IN IN IN IN DEFAULT DEFAULT DEFAULT DEFAULT Die wichtigsten Eingabeparameter dieser neuen Prozedur sind einerseits das neue XML Schema und andererseits das XSL-Stylesheet zur Transformation der bestehenden Dokumente. Die übrigen Parameter steuern das Verhalten der Prozedur. So legt bspw. der Parameter MAPTABNAME die Namen der temporären Tabellen zur Aufnahme der XML-Dokumente während des Transformationsvorgangs explizit fest. Die oben beschriebenen Schritte werden von der Prozedur automatisch durchgeführt. Damit die Funktion arbeiten kann, muss genügend Plattenplatz zur Auslagerung der bestehenden Dokumente vorhanden sein. Zusammenfassung und Ausblick Oracle10g führt für Anwendungsentwickler kein neues Paradigma ein. Vielmehr wird bestehende Funktionalität erweitert und verbessert. Die wichtigsten Änderungen im Java-Umfeld betreffen die Unterstützung von Industriestandards. Mit der weitgehenden Unterstützung von JDBC 3.0 und Java 1.4 befindet sich Oracle hier auf aktuellem Stand. Die Unterstützung für den Aufruf von externen Web Services aus der Datenbank trägt der wachsenden Bedeutung dieser Technologie Rechnung. Bezüglich der XML DB ist die Unterstützung für Schema Evolution wohl die wichtigste Neuerung. Vor Anwendung dieser Funktion sollte jedoch in jedem Fall eine genaue Analyse der Anforderungen stehen. Insbesondere die Frage, ob die bestehenden XML-Dokumente beibehalten oder migriert werden sollen, spielt eine zentrale Rolle. Auch die Auswirkungen auf bestehende Anwendungen, deren Abfragen auf der alten Dokumentstruktur beruhen, müssen berücksichtigt werden. Kontaktadresse: Carsten Czarski Business Unit Database Oracle Deutschland GmbH Riesstr. 25 D-80992 München Telefon: Fax: +49(0)89-14302116 +49(0)89-14302977 E-Mail [email protected] Internet: http://www.oracle.com/de