Einsatz der Oracle-Datenbank-internen Java Virtual Machine
Seite 2: Beispielanwendung
Hallo Welt, hallo Java
Grundsätzlich kann jede Java-Anwendung auch innerhalb der Datenbank laufen, vorausgesetzt, die Oracle-Version unterstützt das entsprechende Java. Das folgende HelloWorld-Beispiel zeigt, wie man bei der Entwicklung und beim Deployment von Java-Anwendungen in der Oracle-Datenbank vorgehen sollte. Anschließend liefert der Artikel noch Hinweise zu Besonderheiten, die in dieser Ablaufumgebung zu beachten sind.
Die folgende Java-Klasse mit ihren beiden Methoden liegt auĂźerhalb der Datenbank als normale Textdatei mit Namen HelloWorld_Test.java vor:
public class HelloWorld
{ public static void hello() {
System.out.println("Hello World");
}
public static String helloWithName(String pName) {
return "Hello " + pName;
}
}
Das loadjava-Tool, das die Oracle-Datenbank bei einer Installation mitliefert, transferiert die Datei wie folgt in die Datenbank und kompiliert sie direkt:
loadjava -u <user>/<passwd>[@database] -r
HelloWorld_Test.java
Über das loadjava-Tool kann man neben Sourcecode-Dateien auch außerhalb der Datenbank kompilierte Class-Dateien sowie komplette .jar-Archive in die Datenbank spielen. Sie liegen dort als Datenbankobjekte vor. Für das Löschen solcher (Java-)Datenbankobjekte existiert das Tool dropjava. Alternativ wäre die Klasse direkt auf Datenbankebene zu erstellen und zu kompilieren. In diesem Fall würde der Aufruf – zum Beispiel aus sqlplus heraus – wie folgt aussehen:
create or replace java source named "HelloWorld_Test" as
public class HelloWorld {
public static void hello() {
System.out.println("Hello World");
}
public static String helloWithName(String pName) {
return "Hello " + pName;
}
}
/
alter java source "HelloWorld_Test" compile
Der Java-Sourcecode und die kompilierte Java-Klasse liegen nun in der Datenbank, was ĂĽber den folgenden Befehl zu ĂĽberprĂĽfen ist:
SQL> select name, source from user_java_classes
NAME SOURCE ----------- --------------------------
HelloWorld HelloWorld_Test
Wie kann man die Methoden dieser datenbankinternen Java-Klassen nun aufrufen, in unserem Beispiel die beiden Methoden hello und helloWithName? An dieser Stelle kommen die bereits erwähnten PL/SQL-Wrapper ins Spiel. Es handelt sich um "normale" PL/SQL-Funktionen, die in allen aus der PL/SQL-Welt bekannten Arten aufzurufen sind. Zu erkennen ist die Delegation an die zugrunde liegenden Java-Klassen am Zusatz
is language java
Die Aufruf-Funktionen fĂĽr die obigen beiden Methoden aus der HelloWorld-Klasse lauten beispielsweise:
create or replace procedure print_hello
is
language java name
'HelloWorld.hello()';
/ create or
replace function get_helloWithName( p_name in varchar2)
return varchar2 is language java name
'HelloWorld.helloWithName(java.lang.String) return
java.lang.String';
/
Vor Aufruf der ersten Methode ist noch zu beachten, dass fĂĽr die Ausgabe der System.out.println-Methode die STDOUT-Ausgabe auf die aktuelle Konsole umzuleiten ist:
set serveroutput.on size 10000
call dbms_java.set_output(10000)
AnschlieĂźend ergibt der Aufruf der PL/SQL-Wrapper-Funktion die gewĂĽnschte Ausgabe:
execute print_hello;
Hello World
Reale Anwendungen arbeiten natĂĽrlich mit Datenbankinhalten und nicht mit HelloWorld-Strings. Wie erfolgt nun der Zugriff auf Datenbankinhalte aus der datenbankinternen Java-Anwendung heraus? Genau wie bei externen Java-Anwendungen ĂĽber JDBC (Java Database Connectivity), das heiĂźt, JDBC-Sourcecode, den man auĂźerhalb der Datenbank erstellt beziehungsweise schon genutzt hat, ist wiederzuverwenden.
Eine zu beachtende Besonderheit ist der Verbindungsaufbau aus JDBC heraus. Eine datenbankinterne Java-Funktion wird ja bereits innerhalb einer Datenbank-Session aufgerufen, das heißt, eine Verbindung zur Datenbank mit User und Passwort ist schon erfolgt. Die Java-Funktion läuft innerhalb der Session mit den Rechten des Users, der sie aufgerufen hat. Für den JDBC-Sourcecode bedeutet dies, dass keine gesonderte Anmeldung mehr nötig ist. Stattdessen erfolgt die Anmeldung über einen speziellen "Server Side Internal"-JDBC-Treiber und die folgende getConnection-Methode:
Connection con = DriverManager.getConnection("jdbc:default:connection:");
Eine weitere Besonderheit ist beim Thema Threading zu betrachten. Wer die Java Thread API für die Erstellung von Multithreading-Applikationen nutzen will, der kann das zwar tun, sollte aber beachten, dass alle Datenbank- innerhalb eines Betriebssystem-Threads ablaufen. Wer tatsächliches Multithreading erreichen will, sollte daher mehrere Datenbank-Sessions mit einzelnen Java-Aufrufen – beispielsweise über DBMS_SCHEDULER-Jobs – erzeugen. Ob man dabei dann aber aufgrund der zusätzlichen Latenzzeiten tatsächlich einen nennenswerten Performancegewinn erzielen kann, muss anhand einer konkreten Anwendung überprüft werden.