W3docs

Java JDBC CallableStatement

Stored Procedures aus Java mit CallableStatement aufrufen – IN, OUT und INOUT Parameter.

Ein CallableStatement ruft eine gespeicherte Prozedur oder Funktion auf, die in der Datenbank liegt. Es erweitert PreparedStatement, bietet also dieselbe ?-Platzhalter-Bindung – plus die Möglichkeit, OUT-Parameter zu registrieren, in die die Prozedur Werte zurückschreibt. Verwenden Sie es, wenn Geschäftslogik in der Datenbank statt in Java implementiert ist.

Dieses Kapitel behandelt die JDBC-Escape-Syntax für Aufrufe, die drei Parameterrichtungen (IN, OUT, INOUT), warum OUT-Parameter einen registrierten Typ benötigen und die strikte Reihenfolge, in der die Methoden aufgerufen werden müssen.

Die JDBC-Escape-Syntax

Der Aufruf wird mit portabler Klammern-Syntax geschrieben, die jeder Treiber in den jeweiligen Hersteller-Dialekt übersetzt:

// procedure with two IN parameters
CallableStatement cs = conn.prepareCall("{call add_customer(?, ?)}");

// function returning a value, with one IN parameter
CallableStatement fn = conn.prepareCall("{? = call total_orders(?)}");

Die geschweiften Klammern bedeuten, dass Sie nicht wissen müssen, ob der Hersteller CALL, EXEC oder BEGIN ... END verwendet.

IN-, OUT- und INOUT-Parameter

Ein Prozedurparameter hat eine Richtung:

  • IN — Sie liefern ihn: cs.setInt(1, customerId), genau wie bei einem PreparedStatement.
  • OUT — die Prozedur füllt ihn; Sie müssen seinen Typ zunächst registrieren und ihn nach der Ausführung lesen.
  • INOUT — beides: setzen, registrieren und anschließend lesen.
CallableStatement cs = conn.prepareCall("{call get_balance(?, ?)}");
cs.setInt(1, accountId);                              // IN
cs.registerOutParameter(2, java.sql.Types.DECIMAL);   // OUT — declare its type
cs.execute();
BigDecimal balance = cs.getBigDecimal(2);             // read it back

Wenn eine Prozedur anstatt eines einzelnen Werts eine vollständige Tabelle liefert, gibt sie ein ResultSet zurück: Rufen Sie cs.executeQuery() auf (oder verwenden Sie den boolean von cs.execute() zusammen mit cs.getResultSet()) und iterieren Sie es genau wie ein ResultSet aus einem gewöhnlichen Statement.

Warum registerOutParameter einen Typ benötigt

JDBC muss wissen, wie die von der Datenbank zurückgesendeten Bytes zu interpretieren sind, bevor der Aufruf ausgeführt wird – daher geben Sie den SQL-Typ mit einer java.sql.Types-Konstante an. Wenn dieser Typ falsch ist, schlägt das anschließende getXxx fehl oder konvertiert fehlerhaft. Die Reihenfolge ist fest: OUT registrieren → IN setzen → ausführen → getXxx.

Ein Praxisbeispiel: Aufruf aufbauen und OUT registrieren

Dieses Programm erstellt beide Escape-Syntax-Aufruf-Strings und geht die OUT-Parameter-Registrierung mit den benötigten java.sql.Types-Codes durch – das vollständige Aufrufprotokoll, ohne eine echte Datenbankverbindung.

java— editable, runs on the server

Was der Programmauslauf zeigt:

  • Die geschweiften Klammern {call proc(?, ?)} sind die portable Escape-Syntax. Sie schreiben denselben String unabhängig vom Hersteller, und der Treiber schreibt ihn um – so bleiben Stored-Procedure-Aufrufe datenbankagnostisch.
  • Die Form {? = call fn(?)} ist für Funktionen, die einen Wert zurückgeben: das führende ? ist der Rückgabeplatz, als OUT-Parameter an Index 1 registriert, mit den eigentlichen Argumenten dahinter.
  • registerOutParameter nimmt eine java.sql.Types-Konstante (INTEGER ist 4, DECIMAL ist 3). Das ist dasselbe Typ-Vokabular aus früheren Kapiteln – JDBC verwendet es überall, wo ein SQL-Typ ohne einen Java-Wert benannt werden muss.
  • Der registrierte Typ muss mit dem übereinstimmen, was die Prozedur tatsächlich zurückgibt; andernfalls liest getInt/getBigDecimal die Bytes falsch. Die Registrierung ist ein Versprechen über die Form des Ergebnisses.
  • Die Protokollreihenfolge ist strikt und es lohnt sich, sie auswendig zu lernen: OUT-Parameter registrieren, IN-Parameter setzen, execute(), dann OUT-Werte mit getXxx(index) lesen. Das Beispiel verdeutlicht diese Abfolge, weil eine falsche Reihenfolge die häufigste Ursache für „parameter not registered"-Fehler ist.

Übungen

Übung
Was müssen Sie tun, bevor Sie ein CallableStatement mit einem OUT-Parameter ausführen?
Was müssen Sie tun, bevor Sie ein CallableStatement mit einem OUT-Parameter ausführen?
Was this page helpful?