Einsatz der Oracle-Datenbank-internen Java Virtual Machine

Java in der Datenbank existiert seit vielen Jahren. Der am häufigsten genannte Kritikpunkt war die Performance der in der Datenbank laufenden Java-Anwendungen. Doch Oracle hat hier im Laufe der letzten Jahre und Datenbankversionen einiges verbessert.

vorlesen Druckansicht
Lesezeit: 17 Min.
Von
  • Rudolf Jansen
  • Alexander Neumann
Inhaltsverzeichnis

Java in der Datenbank existiert seit vielen Jahren, konkret seit Oracle 8i. Der am häufigsten genannte Kritikpunkt war und ist die Performance der in der Datenbank laufenden Java-Anwendungen. Während das in den ersten Versionen noch vollkommen berechtigt war, hat Oracle hier im Laufe der letzten Jahre und Datenbankversionen einiges verbessert.

Nahezu jede Java-Anwendung benötigt einen Zugriff auf Datenbankinhalte. Die Default-Architektur sieht dazu eine strikte Trennung zwischen Java-Anwendung und Datenbank auf getrennten Rechnern vor. Dies kann bei datenintensiven Anwendungen zu einem Performance-Engpass durch häufige Netzzugriffe zwischen den Servern führen. Ein Lösungsansatz besteht im Einsatz einer eingebetteten Java-Datenbank. Eine solche ist komplett in Java geschrieben und lässt sich daher als JAR-Datei in die Java-Anwendung integrieren.

Eine andere Lösung des Problems kann durch Verlagerung der Anwendungslogik in die Datenbank erfolgen. Eine solche datenbankinterne Programmierung bieten mehrere Hersteller an. Wer eine Oracle-Datenbank einsetzt, braucht dabei sogar auf Java als Programmiersprache nicht zu verzichten. Durch zahlreiche Verbesserungen vor allem im Performance-Bereich hat die Oracle-interne JVM in den neuesten Datenbankversionen eine Reife erlangt, die sie zu einer prüfenswerten Alternative für bestimmte Anwendungen macht.

Neben dem stetigen Upgrade der verwendeten Java-Version ist vor allem die Möglichkeit der nativen Kompilierung des Java-Codes über das mitgelieferte ncomp-Tool zu nennen. Wer die neue Oracle-Version 11g einsetzt, kann sogar den in dieser Release neu hinzugekommenen Just-In-Time-Compiler einsetzen.

Systemarchitekturen der meisten (Java-)Anwendungen sind aus Datenbanksicht dadurch gekennzeichnet, dass die Datenbank in einem getrennten (Server-)Bereich läuft und somit jeder Zugriff mit einem Netzzugriff gleichzusetzen ist. Während das aus Administrationssicht und dadurch, dass Datenbanken in der Regel von vielen Applikationen gleichzeitig genutzt werden, sinnvoll erscheint, führt diese Architektur in einigen Fällen zu Performance-Problemen, bei denen der häufige Netztransfer der Daten von der Datenbank zur Java-Anwendung und zurück zu einem Bottleneck führen kann.

In solchen Fällen besteht eine Alternative darin, Teile der Anwendungslogik in die Datenbank zu integrieren und so nur noch einmal die Input-Daten beim Aufruf der datenbankinternen Prozedur zur Datenbank und analog die Ergebnisse auf dem Rückweg über das Netz zur Java-Applikation zu transferieren.

Wer eine Oracle-Datenbank einsetzt, denkt für diese Architektur automatisch an PL/SQL. In dieser datenbankinternen Sprache sind Algorithmen seit Oracles Anfängen zu realisieren. Daher existieren neben vielen von Oracle mitgelieferten PL/SQL- auch einige externe PL/SQL-Bibliotheken sowie ausreichend PL/SQL-Know-how bei den meisten Oracle-Entwicklern.

Seit Oracle 8.1.5 steht Java als Alternative zu PL/SQL zur Verfügung, und zwar um eine in den Datenbankkern integrierte Java Virtual Machine (JVM). Die Datenbank kann – innerhalb einer Session – dadurch Java-Anwendungen ausführen. Die unterstützte Version der Java Standard Edition (Java SE) ist seitdem mit den Oracle-Versionen gewachsen: Java 1.3 gab es in Oracle 9.2, Java 1.4 in Oracle 10.2, und die aktuelle Release 11.1 enthält eine vollständige Java 5 VM.

Bevor der Artikel an einem einfachen (HelloWorld-)Beispiel die Vorgehensweise beim Implementieren und Aufrufen von datenbankinternen Java-Anwendungen illustriert, stellt sich zunächst die Frage, warum man eine solche auf den ersten Blick "exotische" Konstruktion überhaupt einsetzen sollte. Wie erwähnt, ist der häufige Netztransfer von umfangreichen Datenbankinhalten ein Grund für Performance-Probleme beim Zugriff. Über den linken Teil der Abbildung 1 ist zu erkennen, dass in Abhängigkeit der Anwendungslogik eine Vielzahl von JDBC-Aufrufen erforderlich sein kann. Bei jedem sind die übertragenen Daten in die passenden Datentypen umzuwandeln: Beim Aufruf einer SQL- oder PL/SQL-Funktion erfolgt die Umwandlung von Java- in SQL-Datentypen und bei der Rückgabe der Ergebnisse an die Java-Anwendung entsprechend umgekehrt. Dazu kommt noch die Verzögerung durch den eigentlichen Netztransport.

Standard-Java-Architektur versus Java in der Datenbank (Abb. 1)

Neben diesen Performance-Vorteilen hat eine Realisierung eines Algorithmus in datenbankinternem Java-Code im Gegensatz zu einer externen Java-Anwendung den Vorteil, dass diese Realisierung auch aus anderen Programmiersprachen heraus aufzurufen und somit wiederzuverwenden ist. Wie das folgende Beispiel zeigt, liegt das daran, dass nicht der Java-Code direkt aufgerufen wird, sondern ein sogenannter PL/SQL-Wrapper. Das ist eine PL/SQL-Funktion, die wiederum den Java-Code aufruft und wie "normale" PL/SQL-Funktionen beispielsweise von einer C++-Anwendung heraus anzustoĂźen ist.