[目次] [前の項目] [次の項目]

CallableStatement

注: この章の内容は、Addison Wesley 社より Java シリーズの 1 巻として出版された『JDBCTM API Tutorial and Reference, Second Edition: Universal Data Access for the JavaTM 2 Platform』(ISBN 0-201-43328-1) に基づいて作成したものです。

7.1 CallableStatement の概要

CallableStatement オブジェクトは、すべての RDBMS について標準的な方法でストアドプロシージャを呼び出す方法を提供します。ストアドプロシージャはデータベース内に格納されます。CallableStatement オブジェクトに格納されるのは、このストアドプロシージャに対する「呼び出し」です。この呼び出しは、エスケープ構文で書かれます。この構文には、結果パラメータを伴う書式と、伴わない書式の 2 つの書式があります。結果パラメータは OUT パラメータの一種で、ストアドプロシージャの戻り値です。どちらの書式も、入力 (IN パラメータ)、出力 (OUT パラメータ)、またはその両方 (INOUT パラメータ) として使用されるパラメータを持つ場合があります。パラメータの数は可変です。疑問符はパラメータのプレースホルダとして働きます。

JDBC API を使用してストアドプロシージャを呼び出す構文は、次のとおりです。角括弧は、それに囲まれた部分がオプションであることを示します。 これらのかっこは、それ自体構文の一部ではありません。

{call procedure_name[(?, ?, ...)]}

以下は、結果パラメータを返すプロシージャの構文です。

{? = call procedure_name[(?, ?, ...)]}

パラメータが付かないストアドプロシージャの構文は、以下のようになります。

{call procedure_name}

通常、CallableStatement オブジェクトの作成者は、使用している DBMS がストアドプロシージャをサポートしていること、およびそれらのプロシージャが何かということを知っています。しかし、確認が必要な場合は、さまざまな DatabaseMetaData メソッドがこのような情報を提供します。たとえば、メソッド supportsStoredProcedures は、DBMS がストアドプロシージャ呼び出しをサポートしている場合に true を返し、メソッド getProcedures は、使用可能なストアドプロシージャの説明を返します。

CallableStatement は、Statement のメソッド (Statement のメソッドは一般的に SQL 文を扱います) を継承し、また IN パラメータを処理する PreparedStatement のメソッドを継承します。CallableStatement に定義されているすべてのメソッドは、OUT パラメータまたは INOUT パラメータの OUT 部分の処理 (OUT パラメータの JDBC の型の登録、それらの値の取り出し、または戻り値が JDBC NULL であったかどうかの確認) を行います。ResultSet に定義された getXXX メソッドが結果セットからの値を取り出すのに対して、CallableStatement に定義された getXXX メソッドは OUT パラメータから値を取り出すか、ストアドプロシージャの値を返すか、あるいはその両方を行います。

7.1.1 CallableStatement オブジェクトの生成

CallableStatement オブジェクトは、Connection メソッドの prepareCall によって生成されます。次の例では、CallableStatement のインスタンスが生成されます。 con はアクティブな JDBC の Connection オブジェクトです。

CallableStatement cstmt = con.prepareCall(
	"{call getTestData(?, ?)}");

変数 cstmt には、ストアドプロシージャ getTestData の呼び出しが含まれています。 このストアドプロシージャには、2 つの入力パラメータが指定され、結果パラメータは指定されていません。? プレースホルダが、IN、OUT、INOUT のいずれのパラメータになるかは、ストアドプロシージャ getTestData に依存します。CallableStatement オブジェクトのこのインスタンスは、JDBC 1.0 API を使用して生成されているため、cstmt によって呼び出されるストアドプロシージャ内のクエリーは、すべてデフォルトの ResultSet オブジェクト (スクロールおよび更新を行うことができないオブジェクト) を生成します。

JDBC 2.0 API では、CallableStatement オブジェクトを生成し、そのオブジェクトから、スクロールおよび更新を行うことができる ResultSet オブジェクトを生成できます。 次のコードを参照してください。

String sql = "{call getTestData(?, ?)}";
CallableStatement cstmt2 = con.prepareCall(sql,
	ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

変数 cstmt2 には、cstmt と同様に、ストアドプロシージャ TestData の呼び出しが含まれています。 ただし cstmt2 の場合、TestData によって生成された resultSet オブジェクトはどれでも、すべて更新およびスクロールを行うことができます (しかしながら、開かれている間に行われた変更は反映されません)。スクロールおよび更新を行うことができるかどうかを識別するときに使用する定数については、「ResultSet」の章を参照してください。

7.1.2 IN パラメータ

IN パラメータの値の CallableStatement オブジェクトへの引き渡しは、PreparedStatement から継承された setXXX メソッドを使用して行われます。渡される値の型は、どの setXXX (float の値を渡すためには setFloatboolean の値を渡すためには setBoolean など) を使用するかによって決まります。パラメータを使用するプログラムでは、多くの場合、IN パラメータだけが使用されます。

7.1.3 バッチ更新の実行

CallableStatement オブジェクトのバッチ更新は、PreparedStatement オブジェクトと同様に行われます。実際、CallableStatement オブジェクトの機能は、PreparedStatement オブジェクトの機能と同じ制限を受けます。つまり、バッチ更新機能を使用するときは、CallableStatement オブジェクトは、入力パラメータを指定するもしくはパラメータをまったく指定しない、ストアドプロシージャしか呼び出せません。さらに、そのストアドプロシージャは、更新カウントを返さなければなりません。ストアドプロシージャが更新カウント以外の結果を返したり、ストアドプロシージャが OUT または INPUT パラメータを取る場合は、CallableStatement.executeBatch メソッド (PreparedStatement から継承) は、BatchUpdateException をスローします。

次のコードでは、バッチ更新機能を使用して、2 つのパラメータを CallableStatement オブジェクトに関連付けています。

CallableStatement cstmt = con.prepareCall(
			"{call updatePrices(?, ?)}");
cstmt.setString(1, "Colombian");
cstmt.setFloat(2, 8.49f);
cstmt.addBatch();

cstmt.setString(1, "Colombian_Decaf");
cstmt.setFloat(2, 9.49f);
cstmt.addBatch();

int [] updateCounts = cstmt.executeBatch();

変数 cstmt には、ストアドプロシージャ updatePrices への呼び出しが含まれています。 ストアドプロシージャには、2 つのパラメータが関連付けられています。cstmt を実行すると、2 つの更新文が、バッチとしてまとめて実行されます。一方の更新文には、Colombian および 8.49f がパラメータとして指定されています。 もう一方の更新文には、Colombian_Decaf および 9.49f がパラメータとして指定されています。8.49f のように、数値のあとに f が指定されている場合は、その数値が float であることを Java コンパイラに伝えています。 f が指定されていない場合、コンパイラは 10 進数の数値を double と見なすので、float としての使用が許されません。

7.1.4 OUT パラメータ

ストアドプロシージャが OUT パラメータを返す場合、CallableStatement を使用する前に、各 OUT パラメータの JDBC の型を登録する必要があります。この登録が必要なのは、一部の DBMS では、SQL 型 (JDBC 型が表しています) が必要なためです。 JDBC が必要としているわけではありません。JDBC のデータ型、使用頻度の高い SQL のデータ型を表す汎用的な SQL の型識別子についての詳細は、「SQL と Java の型のマッピング」を参照してください。

JDBC の型の登録は、メソッド registerOutParameter によって行います。文の実行が完了してから、CallableStatementgetXXX メソッドを使用して OUT パラメータの値を取得します。使用する正しい CallableStatement.getXXX メソッドは、その OUT パラメータに登録されている JDBC の型に対応する Java プログラミング言語の型のメソッドです。(JDBC の型から Java の型への標準マッピングについては、表 8.1 を参照)。つまり、registerOutParameter は、(それがデータベースが返すデータの型に一致するように) JDBC の型を使用し、getXXX がそれを Java の型にキャストします。

例を挙げて説明すると、以下のコードは OUT パラメータを登録し、cstmt が呼び出すストアドプロシージャを実行してから、OUT パラメータに返された値を取り出します。メソッド getByte は、最初の OUT パラメータから Java の byte を取り出し、getBigDecimal は、2 番目の OUT パラメータから java.math.BigDecimal オブジェクト (小数点以下第 3 位まで) を取り出します。cstmt によって呼び出されたストアドプロシージャが結果セットを返すので、cstmt の実行には executeQuery メソッドを使用しています。

CallableStatement cstmt = con.prepareCall(
	"{call getTestData(?, ?)}");
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3);
ResultSet rs = cstmt.executeQuery();
// . . . retrieve result set values with rs.getXXX methods
byte x = cstmt.getByte(1);
java.math.BigDecimal n = cstmt.getBigDecimal(2);

ResultSet とは異なり、CallableStatement では、大きな OUT 値を少しずつ次々と取得するための特別な機構は提供されていません。つまり、getAsciiStream または getBinary-Stream などのデータストリームを取得するような getXXX メソッドを持っていません。ただし、JDBC 2.0 API の CallableStatement のメソッドでは、OUT パラメータまたは INOUT パラメータとして SQL3 のデータ型を取得することができます。CallableStatement には、getBlob メソッドおよび getClob メソッドが組み込まれており、バイナリラージオブジェクトおよびキャラクタラージオブジェクトを取得することができます。

7.1.5 パラメータの番号付け

対象パラメータを指定する int を引数に取るメソッド (setXXXgetXXX、および registerOutParameter) の場合、その int は、? プレースホルダパラメータのみを参照します。なお、番号は 1 から始まります。このパラメータの番号は、ストアドプロシージャ呼び出しに指定されるリテラルパラメータを参照しません。たとえば、次のコードは、1 つのリテラルパラメータ (25) と 1 つの ? パラメータを持つストアドプロシージャ呼び出しの例です。

CallableStatement cstmt = con.prepareCall(
		"{call getTestData(25, ?)}");
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);

このコードでは、registerOutParameter の第 1 引数である int 1 は、最初の ? パラメータ (ここでは ? パラメータは 1 つしかありません) を参照しています。この int 1 は、ストアドプロシージャの第 1 パラメータであるリテラルの 25 を参照しているわけではありません。

7.1.6 INOUT パラメータ

入力を渡し、出力を受け取るパラメータ (INOUT パラメータ) は、(PreparedStatement から継承された) 適切な setXXX を呼び出す必要があります。 さらに registerOutParameter メソッドも呼び出す必要があります。setXXX メソッドは、パラメータの値を入力パラメータとして設定し、registerOutParameter メソッドはその JDBC の型を出力パラメータとして登録します。setXXX メソッドは、Java の値を提供します。ドライバはその値をデータベースへ送信する前に JDBC の値に変換します。この IN の値の JDBC の型と、メソッド registerOutParameter に供給する JDBC の型は同一でなければなりません。そして、出力値を取り出すためには、対応する getXXX メソッドを使用します。たとえば、パラメータの Java の型が byte の場合は、setByte メソッドを使用して入力値を代入し、TINYINT を JDBC の型として registerOutParameter に渡し、getByte を使用して出力値を取り出す必要があります (型のマッピングの一覧については、「SQL と Java の型のマッピング」を参照)。

以下の例では、ストアドプロシージャ reviseTotal があり、その唯一のパラメータが 1 つの INOUT パラメータである場合を想定しています。メソッド setByte はこのパラメータを 25 に設定し、ドライバはこれを JDBC の TINYINT としてデータベースへ送信します。次の registerOutParameter は、このパラメータを JDBC の TINYINT として登録します。ストアドプロシージャが実行されると、新しい JDBC TINYINT の値が返され、メソッド getByte がこの新しい値を Java の byte として取り出します。この例で呼び出されているストアドプロシージャは更新カウントを返すため、executeUpdate メソッドが使用されています。

CallableStatement cstmt = con.prepareCall(
		"{call reviseTotal(?)}");
cstmt.setByte(1, (byte)25);
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.executeUpdate();
byte x = cstmt.getByte(1);

7.1.7 結果セットのあとに OUT パラメータを取り出す

一部の DBMS に課せられている制限のため、移植性を大きくするために以下を推奨します。 OUT パラメータを取り出す前に、CallableStatement オブジェクトの実行によって生成された ResultSet オブジェクトのすべての結果を取り出してください。結果セットの値がすべて取り出されると、ResultSet.next メソッドは false を返します。

CallableStatement オブジェクトが複数の ResultSet オブジェクトを返す場合 (execute メソッドの呼び出しによって実行された場合のみ起り得る)、OUT パラメータを取り出す前に、すべての結果セットにアクセスする必要があります。この場合、すべての結果に確実にアクセスするように、結果がなくなるまで Statement のメソッド getResultSetgetUpdateCount、および getMoreResults を呼び出す必要があります。すべての結果がなくなったあとで、getMoreResults メソッドを呼び出すと false が返され、getUpdateCount メソッドを呼び出すと -1 が返されます。

ResultSet.getXXX メソッドを使用して ResultSet オブジェクトからすべての値が取り出され、更新カウントが返されなくなったら、CallableStatement.getXXX メソッドを使用して OUT パラメータの値を取り出すことができます。

7.1.8 NULL 値を OUT パラメータとして取り出す

OUT パラメータに返される値は JDBC NULL である場合があります。JDBC NULL 値は、getXXX メソッドが返す値が getXXX メソッドの型によって null0false のどれかになるように変換されます。ResultSet オブジェクトについて、0 または false の値がもともと JDBC NULL であったかどうかを知る唯一の方法は、wasNull メソッドを使用して確認する方法です。 wasNull は、getXXX メソッドが読み取った最後の値が JDBC NULL の場合 true を返し、そうでない場合 false を返します。



[目次] [前の項目] [次の項目]

Copyright © 1999, Sun Microsystems, Inc. All rights reserved.