7.2 コール仕様の定義
コール仕様とそのコール仕様によって公開されるJavaメソッドは、JavaメソッドにPUBLIC
シノニムがないかぎり、同一スキーマに常駐している必要があります。コール仕様の宣言方法は次のとおりです。
-
スタンドアロンPL/SQLファンクションまたはプロシージャ
-
パッケージ化されたPL/SQLファンクションまたはプロシージャ
-
SQLオブジェクト型のメンバー・メソッド
コール仕様によって、Javaメソッドのトップレベルのエントリ・ポイントがOracle Databaseに公開されます。このため、公開できるのはpublic
static
メソッドのみです。ただし、例外が1つあります。インスタンス・メソッドは、SQLオブジェクト型のメンバー・メソッドとして公開できます。
パッケージ化されたコール仕様はトップレベルのコール仕様と同様に機能します。このため、メンテナンスを容易にするために、コール仕様をパッケージ本体に配置することもできます。この方法では、他のスキーマ・オブジェクトを無効にせずにコール仕様を変更できます。また、コール仕様をオーバーロードすることもできます。
この項の内容は次のとおりです。
7.2.1 パラメータ・モードの設定について
Javaや他のオブジェクト指向言語では、メソッドは引数として渡されたオブジェクトに値を割り当てることはできません。SQLまたはPL/SQLからメソッドをコールするときに引数の値を変更するには、コール仕様でOUT
パラメータまたはIN OUT
パラメータとして宣言する必要があります。対応するJavaパラメータは、要素の数が1つのみの配列であることが必要です。
要素の値を適切な型の別のJavaオブジェクトに置き換えるか、またはJavaの型によっては値を変更できます。いずれの方法でも、新しい値がコール元に戻されます。たとえば、コール仕様のNUMBER
型のOUT
パラメータを、float[]
p
として宣言されたJavaパラメータにマッピングし、p[0]
に新しい値を割り当てます。
注意:
OUT
パラメータまたはIN
OUT
パラメータを宣言するファンクションは、SQLのデータ操作言語(DML)文からはコールできません。
7.2.2 データ型のマッピングについて
コール仕様では、対応するSQLパラメータとJavaパラメータ、およびファンクションの結果には互換性のあるデータ型を設定する必要があります。
表7-1に、有効なデータ型マッピングが示されています。Oracle Databaseでは、SQL型とJavaクラス間で自動的に変換が行われます。
表7-1 有効なデータ型マッピング
SQL型 | Javaクラス |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ref cursor |
|
ユーザー定義の名前付き型、ADT |
|
opaque名前付き型 |
|
NESTED TABLEおよびVARRAY名前付き型 |
|
名前付き型の参照 |
|
次の点を考慮する必要もあります。
-
最後の4つのSQL型は、まとめて名前付き型と呼ばれています。
-
BLOB
、CLOB
、BFILE
、REF
CURSOR
および名前付き型を除くすべてのSQL型は、Javaのバイト配列であるJava型byte[]
にマップできます。この場合、引数の変換は、SQL値のRAWバイナリ表現をJavaのバイト配列にコピーする(あるいはその逆へのコピーを行う)ことを意味します。 -
ORAData
インタフェースおよび関連メソッドを実装するJavaクラス、または表でoracle.sql
クラスのサブクラスとして示されたJavaクラスは、BINARY_INTEGER
およびREF
CURSOR
以外のSQL型からマップできます。 -
UROWID
型およびNUMBER
のサブタイプ(INTEGER
、REAL
など)はサポートされていません。 -
LONG
またはLONG RAW
の列から、32KBを超える値をJavaストアド・プロシージャに取り出すことはできません。
7.2.3 サーバー側JDBC内部ドライバの使用
Java Database Connectivity(JDBC)では、JDBCドライバのセットを管理するDriverManager
クラスを使用して、データベースとの接続を確立します。JDBCドライバがロードされた後、getConnection()
メソッドを使用できます。正しいドライバが検出されると、getConnection()
メソッドによって、データベース・セッションを表すConnection
オブジェクトが戻されます。SQL文はすべて、そのセッションのコンテキスト内で実行されます。
ただし、サーバー側JDBC内部ドライバは、デフォルトのセッションおよびトランザクション・コンテキスト内で動作します。そのため、すでにデータベースに接続された状態であり、SQL操作はすべてデフォルトのトランザクションの一部です。ドライバは事前に登録されているため、登録する必要はありません。Connection
オブジェクトを取得するには、次のコード行を実行します。
Connection conn = DriverManager.getConnection("jdbc:default:connection:");
IN
パラメータを取らず、かつ1回のみ実行されるSQL文に対しては、Statement
クラスを使用します。Connection
オブジェクト上でcreateStatement()
メソッドがコールされると、新しいStatement
オブジェクトが戻されます。次に例を示します。
String sql = "DROP " + object_type + " " + object_name; Statement stmt = conn.createStatement(); stmt.executeUpdate(sql);
IN
パラメータを取るか、または複数回実行されるSQL文に対しては、PreparedStatement
クラスを使用します。1つ以上のパラメータ・プレースホルダを含むことができるSQL文は、プリコンパイルされます。疑問符(?)がプレースホルダとして機能します。Connection
オブジェクト上でprepareStatement()
メソッドがコールされると、プリコンパイルされたSQL文が含まれる新しいPreparedStatement
オブジェクトが戻されます。次に例を示します。
String sql = "DELETE FROM dept WHERE deptno = ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setInt(1, deptID); pstmt.executeUpdate();
ResultSet
オブジェクトには、SQLの問合せ結果、つまり検索条件を満たす行が含まれます。next()
メソッドを使用すると次の行に移動し、その行がカレント行になります。現在の行から列の値を取り出すには、get
XXX
()
メソッドを使用します。次に例を示します。
String sql = "SELECT COUNT(*) FROM " + tabName; int rows = 0; Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery(sql); while (rset.next()) { rows = rset.getInt(1); }
CallableStatement
オブジェクトを使用すると、ストアド・プロシージャをコールできます。これには、1つの戻りパラメータと任意の数のIN
、OUT
およびIN OUT
のパラメータを含めることができる、コール・テキストが含まれています。コールは、中カッコ({}
)で区切られるエスケープ句を使用して記述されます。次の例に示すように、エスケープ構文には3つの形式があります。
// parameterless stored procedure CallableStatement cstmt = conn.prepareCall("{CALL proc}"); // stored procedure CallableStatement cstmt = conn.prepareCall("{CALL proc(?,?)}"); // stored function CallableStatement cstmt = conn.prepareCall("{? = CALL func(?,?)}");
重要な点
ストアド・プロシージャにアクセスするJDBCアプリケーションを開発するときは、次の点を考慮する必要があります。
-
各Oracle JVMセッションには、存在するデータベース・セッションに対して1つの暗黙的なネイティブ接続があります。この接続は概念的で、Javaオブジェクトではありません。これはこのセッションに固有な側面であり、JVM内でオープンまたはクローズできません。
-
サーバー側JDBC内部ドライバは、デフォルトのトランザクション・コンテキスト内で動作します。データベースにすでに接続された状態であり、SQL操作はすべてデフォルトのトランザクションの一部です。このトランザクションはローカル・トランザクションで、Java Transaction API(JTA)またはJava Transaction Service(JTS)によって実装されるようなグローバル・トランザクションの一部ではありません。
-
文および結果セットは複数のコールにわたって存続するため、ファイナライザはデータベース・カーソルを解放しません。カーソルが不足しないように、処理が終了した後にすべての文および結果セットをクローズしてください。または、DBAに依頼して、初期化パラメータの
OPEN_CURSORS
で設定されている制限値を増やすこともできます。 -
サーバー側JDBC内部ドライバは、自動コミットをサポートしていません。そのため、アプリケーションで、データベースの変更を明示的にコミットまたはロールバックする必要があります。
-
サーバー側JDBC内部ドライバを使用して、リモート・データベースには接続できません。Javaプログラムを実行しているサーバーにのみ接続できます。サーバー/サーバー接続の場合は、サーバー側JDBC Thinドライバを使用します。クライアント/サーバー接続の場合は、クライアント側JDBC ThinドライバまたはJDBC Oracle Call Interface(OCI)ドライバを使用します。
-
通常、デフォルトの接続インスタンスはクローズしないでください。このインスタンスは複数の場所に格納される可能性がある単一インスタンスであり、クローズするとそれぞれの場所が使用できなくなります。クローズすると、それ以降に
OracleDriver.defaultConnection
メソッドをコールしたときに、新しいオープン・インスタンスが作成されます。OracleDataSource.getConnection
メソッドはコールするたびに新規オブジェクトを戻しますが、毎回、新しいデータベース接続を作成するわけではありません。同じ暗黙的なネイティブ接続を使用し、同じセッション状態(特にローカル・トランザクション)を共有します。