11 Oracleデータへのアクセスと操作
この章では、Oracle拡張機能(oracle.sql.*形式)について説明し、標準Java形式(java.sql.*)と比較します。Oracle拡張機能を使用するには、結果セットと文を適宜OracleResultSet、OracleStatement、OraclePreparedStatementおよびOracleCallableStatementにキャストし、これらのクラスのgetOracleObject、setOracleObject、getXXXおよびsetXXXメソッド(XXXはoracle.sqlパッケージの型に対応)を使用する必要があります。
11.1 データ型マッピング
Oracle JDBCドライバは、Oracle固有のデータ型に加えて、標準JDBC型をサポートしています。この項では、標準およびOracle固有のSQL-Javaデフォルト型マッピングについて説明します。この項では、次の項目について説明します。
11.1.1 マッピングの表
次の表は、SQLデータ型、JDBC型コード、標準Java型およびOracle拡張型間のデフォルト・マッピングを示しています。
SQLデータ型の列は、Oracle Database 12cリリース1 (12.1)に存在するSQL型を示しています。JDBC型コードの列は、JDBC標準によってサポートされ、java.sql.Typesクラス、またはoracle.jdbc.OracleTypesクラスでOracleによって定義されるデータの型コードを示しています。標準の型コードの場合、コードはこの2つのクラスで同一です。
標準Java型の列は、Java言語で定義される標準型を示しています。Oracle拡張機能Java型の列は、データベース内の各SQLデータ型に対応したoracle.sql.*Java型を示しています。これらは、oracle.sql.* Java型でSQLデータすべての取出しを可能にするOracle拡張機能です。
ノート:
一般に、Oracle JDBCドライバは、標準JDBC型を使用してSQLデータを操作するように最適化されています。いくつかの特殊な例では、oracle.sqlパッケージで入手できるOracle拡張クラスを使用するのが有利な場合があります。しかし、できるかぎりOracle拡張機能ではなく標準JDBC型を使用することを強くお薦めします。
表11-1 SQL型とJava型間のデフォルト・マッピング
| SQLデータ型 | JDBC型コード | 標準Java型 | Oracle拡張機能Java型 |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ユーザー定義オブジェクト |
|
|
|
|
ユーザー定義参照 |
|
|
|
|
ユーザー定義コレクション |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(Oracle拡張機能) |
なし |
|
|
|
(Oracle拡張機能) |
|
|
|
|
(Oracle拡張機能) |
|
|
|
|
(Oracle拡張機能) |
|
|
|
|
(Oracle拡張機能) |
|
|
脚注1
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.BLOBクラスは非推奨となり、oracle.jdbc.OracleBlobインタフェースに置き換えられています。
脚注2
Oracle Database 12cリリース1以降、oracle.sql.CLOBクラスは非推奨となり、oracle.jdbc.OracleClobインタフェースに置き換えられています。
脚注3
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.STRUCTクラスは非推奨となり、oracle.jdbc.OracleStructインタフェースに置き換えられています。
脚注4
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.REFクラスは非推奨となり、oracle.jdbc.OracleRefインタフェースに置き換えられています。
脚注5
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.ARRAYクラスは非推奨となり、oracle.jdbc.OracleArrayインタフェースに置き換えられています。
ノート:
バージョン8.1.7など、TIMESTAMPデータ型をサポートしていないデータベースのバージョンの場合、TIMESTAMPはDATEにマップされます。
11.1.2 マッピングに関するノート
この項では、NUMBERおよびユーザー定義型のマッピングに関する詳細を提供します。
NUMBER型
Oracle NUMBER値が対応できる様々な型コードでは、マッピングを正しく動作させるために、データのサイズに適切なgetterルーチンをコールします。たとえば、-128 < x < 128の項目xに対してJava tinyint値を取得するには、getByteをコールします。
ユーザー定義型
オブジェクト、オブジェクト参照およびコレクションなどのユーザー定義型は、デフォルトでjava.sql.Structなどの弱いJava型にマップされますが、かわりに強い型指定のカスタムJavaクラスにもマップできます。カスタムJavaクラスは、次のいずれかのインタフェースを実装できます。
-
標準
java.sql.SQLData -
Oracle固有
oracle.jdbc.OracleData
11.2 データ変換での考慮事項
11.2.1 標準型とOracle型
oracle.sqlのOracleデータ型では、データベースで使用されているのと同じビット形式でデータが格納されます。Oracle Database 10gより前のバージョンのOracle JDBCドライバでは、通常、Oracleデータ型の方が効率的でした。Oracle Database 10g以降、JDBCドライバは大幅に更新されました。その結果、ほとんどの場合は、oracle.sqlのデータ型よりも標準Java型が優先されるようになりました。特に、java.lang.Stringは、oracle.sql.CHARよりはるかに効率的です。
一般的にはJava標準型の使用をお薦めします。例外として次のような場合があります。
-
OracleDataの機能の方がニーズに合っている場合は、java.sql.SqlDataではなく、oracle.jdbc.OracleDataを使用します。 -
浮動小数点数の値を正確に保持する必要がある場合は、
java.lang.Doubleではなくoracle.sql.NUMBERを使用します。OracleNUMBERは10進表現ですが、JavaDoubleおよびFloatは2進表現となります。ある形式から別の形式へ変換を行うと、実際の表現値が少し変化することがあります。さらに、2つの形式を使用して表現できる値の範囲が異なります。パフォーマンスが重大で、値を操作せずに、単に値の読取りや書込みを行う場合には、
java.math.BigDecimalではなく、oracle.sql.NUMBERを使用します。 -
JDK 6より前のJDKバージョンを使用している場合は、
oracle.sql.DATEまたはoracle.sql.TIMESTAMPを使用します。JDK 6以降のバージョンを使用している場合、java.sql.Dateまたはjava.sql.Timestampを使用します。ノート:
JDK 6より前のすべてのバージョンでは、不具合により
java.lang.Dateおよびjava.lang.Timestampオブジェクトの作成処理が遅くなるという問題があります(特に、マルチスレッド環境において)。この不具合は、JDK 6で修正されました。 -
Oracle文字セットによるコードで表されている外部ソースのデータがある場合にかぎり、
oracle.sql.CHARを使用します。それ以外の場合はすべて、java.lang.Stringを使用します。 -
STRUCT、ARRAY、BLOB、CLOB、REFおよびROWIDはすべて、対応するJDBC標準インタフェース型の実装クラスです。したがって、JDBC標準型と同一のOracle拡張型を使用する利点はありません。 -
BFILE、TIMESTAMPTZおよびTIMESTAMPLTZには、JDBC標準での表現がありません。これらのOracle拡張機能は使用する必要があります。 -
他のすべての場合には、Oracle拡張機能ではなく、標準JDBC型を使用する必要があります。
ノート:
oracle.sqlデータ型をJava標準データ型に変換した場合、oracle.sqlデータ型を使用する利点は失われます。
11.2.2 SQL NULLデータの変換について
Javaは、SQL NULLデータを、Javaの値nullで表現します。Javaデータ型は、プリミティブ型(byte、int、floatなど)とオブジェクト型(クラス・インスタンスなど)の2つのカテゴリに分類されます。プリミティブ型でNULLを表すことはできません。かわりに、JDBC仕様で定義されているように、nullを0(ゼロ)値として格納します。これは、結果の解釈時にあいまいさが生じる原因ともなります。
一方、Javaオブジェクト型はNULLを表現できます。Java言語は、nullを表現可能なプリミティブ型ごとに対応したオブジェクト・コンテナ型を定義します。オブジェクト・コンテナ型は、SQLデータがSQL NULLを明確に検出するためのターゲットとして使用する必要があります。
11.2.3 NULLのテストについて
関係演算子を使用してNULL値同士、または他の値との比較をすることはできません。たとえば、次のSELECT文は、COMMISSION_PCT列にNULL値が1つ以上存在する場合でも行を戻しません。
PreparedStatement pstmt = conn.prepareStatement( "SELECT * FROM EMPLOYEES WHERE COMMISSION_PCT = ?"); pstmt.setNull(1, java.sql.Types.VARCHAR);
次の例では、戻り値にNULLが含まれる可能性がある場合に値が等しいかどうかを比較する方法を示します。このコードは、COMMに値205が存在しない場合、EMPLOYEES表からFIRST_NAMEをNULLとして戻します。
PreparedStatement pstmt = conn.prepareStatement("SELECT FIRST_NAME FROM EMPLOYEES
WHERE COMMISSION_PCT =? OR ((COMM IS NULL) AND (? IS NULL))");
pstmt.setBigDecimal(1, new BigDecimal(205));
pstmt.setNull(2, java.sql.Types.VARCHAR);
11.3 結果セットと文拡張機能
Statementオブジェクトは、java.sql.ResultSetを戻します。標準JDBCメソッドのみをオブジェクトに適用する場合は、オブジェクトのResultSet型を維持してください。ただし、オブジェクト上でOracle拡張機能を使用する場合は、Oracle拡張機能をOracleResultSetにキャストする必要があります。Oracleの結果セット拡張機能は、すべてoracle.jdbc.OracleResultSetインタフェースに含まれ、Statement拡張機能は、すべてoracle.jdbc.OracleStatementインタフェースに含まれています。
たとえば、標準Statementオブジェクトstmtがあり、標準JDBC ResultSetメソッドのみを使用する場合、次のように記述します。
ResultSet rs = stmt.executeQuery("SELECT * FROM employees");
JDBCに対するOracle拡張機能を使用する場合は、結果を選択して標準ResultSet変数に入れ、次にその変数をOracleResultSetにキャストします。
結果セット・クラスおよび文クラスへの主な拡張機能には、getOracleObjectおよびsetOracleObjectメソッドがあります。これらのメソッドは、oracle.sql.*形式でデータへのアクセスおよび操作を実行するために使用します。
11.4 Oracleのgetおよびsetメソッドと標準JDBCの比較
この項では、getメソッドとsetメソッド、特にJDBC標準のgetObjectメソッドとsetObjectメソッドおよびOracle固有のgetOracleObjectメソッドとsetOracleObjectメソッドについて説明します。また、oracle.sql.*形式のデータへのアクセス方法をJava形式と比較しながら説明します。
すべてのOracle SQL型に標準のgetXXXメソッドを使用できます。
この項の内容は次のとおりです。
ノート:
表名を使用して列名を修飾し、その列名をパラメータとしてgetXXXメソッドに渡すことはできません。たとえば:
ResultSet rset = stmt.executeQuery("SELECT employees.department_id, department.department_id FROM employees, department");
rset.getInt("employees.department_id");
このコード例の場合、getIntメソッドで例外が発生します。getXXXメソッドで列を一意に識別するには、列索引を使用するか、または問合せで列別名を指定してその別名をgetXXXメソッドで使用します。
11.4.1 標準getObjectメソッド
結果セットまたはコール可能文の標準getObjectメソッドの戻り型は、java.lang.Objectです。戻されるオブジェクトのクラスは、次に示すようにSQL型に基づきます。
-
Oracle固有ではないSQLデータ型の場合、JDBC仕様のマッピングに従い、
getObjectメソッドは列のSQL型に対応するデフォルトのJava型を戻します。 -
Oracle固有のデータ型の場合、
getObjectは適切なoracle.sql.*クラス(oracle.sql.ROWIDなど)のオブジェクトを戻します。 -
Oracle Databaseオブジェクトの場合、
getObjectは、使用する型マップで指定されたクラスのJavaオブジェクトを戻します。型マップは、データベース型名からJavaクラスへのマッピングを指定します。getObject(parameter_index)メソッドでは、接続のデフォルト型マップを使用します。getObject(parameter_index,map)を使用すると、型マップを渡すことができます。型マップに特定のOracleオブジェクトに対応するマッピングがない場合、getObjectはoracle.sql.OracleStructオブジェクトを戻します。
11.4.2 Oracle getOracleObjectメソッド
結果セットまたはコール可能文からデータをoracle.sql.*オブジェクトとして取り出す場合は、特殊なプロセスに従う必要があります。OracleResultSetオブジェクトの場合、結果セットをoracle.jdbc.OracleResultSetにキャストしてから、getObjectではなく、getOracleObjectをコールする必要があります。CallableStatementおよびoracle.jdbc.OracleCallableStatementにも同じことが当てはまります。
getOracleObjectの戻り型はoracle.sql.Datumです。実際に戻されるオブジェクトは、該当するoracle.sql.*クラスのインスタンスです。メソッド・シグネチャは次のとおりです。
public oracle.sql.Datum getOracleObject(int parameter_index)
Datum変数に取り出したデータを入れると、標準Java instanceof演算子を使用して、実際にどのoracle.sql.*型であるかを確認できます。
例: 結果セットでのgetOracleObjectの使用方法
次の例では、CHARデータの列を含む表およびBFILEロケータを含む列を作成します。SELECT文では、表の内容を結果セットとして取り出します。その後、getOracleObjectで取り出したCHARデータをchar_datum変数に、BFILEロケータをbfile_datum変数に入れます。getOracleObjectはDatumオブジェクトを戻すため、戻り値をそれぞれCHARおよびBFILEにキャストする必要があります。
stmt.execute ("CREATE TABLE bfile_table (x VARCHAR2 (30), b BFILE)");
stmt.execute
("INSERT INTO bfile_table VALUES ('one', BFILENAME ('TEST_DIR', 'file1'))");
ResultSet rset = stmt.executeQuery ("SELECT * FROM bfile_table");
while (rset.next ())
{
CHAR char_datum = (CHAR) ((OracleResultSet)rset).getOracleObject (1);
BFILE bfile_datum = (BFILE) ((OracleResultSet)rset).getOracleObject (2);
...
}
例: コール可能文でのgetOracleObjectの使用方法
次の例では、文字列を日付と関連付けるプロシージャmyGetDateへのコールを作成します。このプログラムは、HRを準備済コールに渡し、DATE型を出力パラメータとして登録します。コールの実行後、getOracleObjectはHRに関連付けられている日付を取り出します。getOracleObjectはDatumオブジェクトを戻すため、結果はDATEにキャストされる点に留意してください。
OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall
("begin myGetDate (?, ?); end;");
cstmt.setString (1, "HR");
cstmt.registerOutParameter (2, Types.DATE);
cstmt.execute ();
DATE date = (DATE) ((OracleCallableStatement)cstmt).getOracleObject (2);
...
11.4.3 getObjectおよびgetOracleObject戻り型のまとめ
次の表は、各Oracle SQL型のgetObjectメソッドとgetOracleObjectメソッドの、基礎となる戻り型を示しています。
ただし、これらのメソッドを使用する際は、次のことを念頭に置いてください。
-
getObjectは、データを常にjava.lang.Objectインスタンスで戻します。 -
getOracleObjectは、データを常にoracle.sql.Datumインスタンスで戻します。
表11-2 getObjectとgetOracleObjectの戻り型
| Oracle SQL型 | getObjectの基礎となる戻り型 | getOracleObjectの基礎となる戻り型 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(未サポート) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Oracleオブジェクト |
型マップで指定されたクラス または |
|
|
Oracleオブジェクト参照 |
|
|
|
コレクション(VARRAYまたはNESTED TABLE) |
|
|
脚注6
ResultSet.getObjectは、oracle.jdbc.J2EE13Compliant接続プロパティがTRUEに設定されている場合のみjava.sql.Timestampを戻します。そうでない場合、このメソッドはoracle.sql.TIMESTAMPを戻します。
脚注7
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.BLOBクラスは非推奨となり、oracle.jdbc.OracleBlobインタフェースに置き換えられています。
脚注8
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.CLOBクラスは非推奨となり、oracle.jdbc.OracleClobインタフェースに置き換えられています。
脚注9
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.STRUCTクラスは非推奨となり、oracle.jdbc.OracleStructインタフェースに置き換えられています。
脚注10
Oracle Database 12cリリース1以降、oracle.sql.REFクラスは非推奨となり、oracle.jdbc.OracleRefインタフェースに置き換えられています。
脚注11
Oracle Database 12cリリース1以降、oracle.sql.ARRAYクラスは非推奨となり、oracle.jdbc.OracleArrayインタフェースに置き換えられています。
ノート:
ResultSet.getObjectメソッドは、接続プロパティoracle.jdbc.J2EE13CompliantがTRUEに設定されている場合のみ、TIMESTAMP SQL型のjava.sql.Timestampを戻します。このプロパティは、接続の取得時に設定する必要があります。この接続プロパティが設定されていない場合、または接続の取得後に設定した場合、ResultSet.getObjectメソッドはTIMESTAMP SQL型のoracle.sql.TIMESTAMPを戻します。
oracle.jdbc.J2EE13Compliant接続プロパティは、コードを変更せずに、次の方法で設定できます。
-
ojdbc6dms.jarファイルまたはojdbc7dms.jarファイルをCLASSPATHに含めます。これらのファイルでは、デフォルトでoracle.jdbc.J2EE13CompliantがTRUEに設定されます。これらはOracle Application Serverリリースに固有のもので、一般のJDBCリリースには含まれていません。これらのファイルは$ORACLE_HOME/jdbc/libにあります。 -
javaコマンドをフラグ-Doracle.jdbc.J2EE13Compliant=trueを指定してコールし、システム・プロパティを設定します。たとえば、java -Doracle.jdbc.J2EE13Compliant=true ...
J2EE13CompliantがTRUEに設定されると、動作はJDBC仕様の表B-3のようになります。
関連トピック
11.4.4 その他のgetXXXメソッド
標準JDBCでは、各標準Java型に対応したgetXXX(getByte、getInt、getFloatなど)が提供されます。これらの各メソッドは、そのメソッド名が意味する内容を正確に戻します。
さらに、OracleResultSetクラスとOracleCallableStatementインタフェースは、すべてのoracle.sql.*型に対応したgetXXXメソッドを補完します。各getXXXメソッドは、oracle.sql.XXXオブジェクトを戻します。たとえば、getROWIDメソッドは、oracle.sql.ROWIDオブジェクトを戻します。
特定のgetXXXメソッドを使用してもパフォーマンス上の利点はありません。ただし、戻り型は戻されるオブジェクトに固有であるため、面倒なキャストの必要がなくなります。
この項の内容は次のとおりです。
11.4.4.2 getXXXメソッドに関する特別なノート
この項では、いくつかのgetXXXメソッドについて追加の詳細情報を示します。
getBigDecimal
JDBC 2.0では、getBigDecimalメソッドのメソッド・シグネチャが単純になっています。以前の入力シグネチャは次のいずれかでした。
(int columnIndex, int scale) or (String columnName, int scale)
単純になった入力シグネチャは次のとおりです。
(int columnIndex) or (String columnName)
小数点の右にある数字の数を指定するために使用するscaleパラメータは不要になりました。Oracle JDBCドライバは、完全な精度で数値を取り出します。
getBoolean
BOOLEANデータベース型が存在しないため、getBooleanを使用すると必ずデータ型変換が実行されます。getBooleanメソッドは数値用の列に対してのみサポートされます。このような列に対してgetBooleanが適用されると、0(ゼロ)値はfalseとして、それ以外の値はtrueとして解釈されます。別の種類の列に適用された場合は、getBooleanは例外java.lang.NumberFormatExceptionを戻します。
11.4.5 getObjectおよびgetXXXから戻されるオブジェクトのデータ型
getObjectの戻り型はjava.lang.Objectです。戻り型は、java.lang.Objectのサブクラスのインスタンスです。同様に、getOracleObjectの戻り型はoracle.sql.Datumで、戻り値のクラスはoracle.sql.Datumのサブクラスです。通常、適切なクラスの特定のメソッドおよび機能を使用するには、戻されたオブジェクトをそのクラスにキャストします。
また、汎用のgetObjectメソッドやgetOracleObjectメソッドのかわりに、特定のgetXXXメソッドも使用できます。getXXXの戻り型は、戻されるオブジェクトの型に対応しているため、getXXXメソッドを使用することにより、キャストを回避できます。たとえば、getCLOBの戻り型は、java.lang.Objectではなくoracle.sql.CLOBです。
戻り値のキャストの例
この例では、NUMBERタイプのデータを結果セットの最初の列としてフェッチしていると想定しています。精度を下げずにNUMBERデータを操作する必要があるので、OracleResultSetに結果セットをキャストし、getOracleObjectを使用して、NUMBERデータをoracle.sql.*形式で戻します。結果セットをキャストしない場合は、getObjectを使用する必要があります。数値データがJava Floatに戻されるため、SQLデータの精度が多少下がります。
getOracleObjectメソッドは、出力をキャストしないかぎり、oracle.sql.NUMBERオブジェクトをoracle.sql.Datum戻り変数に戻します。NUMBER戻り変数を使用し、そのクラスの特殊機能のいずれかを使用する場合は、getOracleObjectの出力をoracle.sql.NUMBERにキャストしてください。
NUMBER x = (NUMBER)ors.getOracleObject(1);
11.4.6 setObjectメソッドとsetOracleObjectメソッド
結果セットとコール可能文に標準getObjectとOracle固有のgetOracleObjectがあるように、OraclePreparedStatementとOracleCallableStatementにも標準setObjectメソッドとOracle固有のsetOracleObjectメソッドがあります。setOracleObjectメソッドは、oracle.sql.*を入力パラメータとして取ります。
標準Java型をプリペアド文またはコール可能文にバインドするには、java.lang.Objectを入力にとるsetObjectメソッドを使用します。setObjectメソッドは、いくつかのoracle.sql.*型をサポートします。ただしこのメソッドは、JDBC標準型Blob、Clob、Struct、RefおよびArrayに対応するoracle.sql.*クラスのインスタンスを入力できるように実装されています。
oracle.sql.*型をプリペアド文またはコール可能文にバインドするには、oracle.sql.Datumのサブクラスを入力にとるsetOracleObjectメソッドを使用します。setOracleObjectを使用するには、プリペアド文またはコール可能文をOraclePreparedStatementまたはOracleCallableStatementにキャストする必要があります。
setObjectとsetOracleObjectの使用例
プリペアド文には、charVal変数により表現されたoracle.sql.CHARデータがsetOracleObjectメソッドによってバインドされます。oracle.sql.*データをバインドするには、プリペアド文をOraclePreparedStatementにキャストする必要があります。同様に、setObjectメソッドは、変数strValで表現されたJava Stringデータをバインドします。
PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
((OraclePreparedStatement)ps).setOracleObject(1,charVal);
ps.setObject(2,strVal);11.4.7 その他のsetXXXメソッド
getXXXメソッドと同様に、固有なsetXXXメソッドもいくつかあります。標準のsetXXXメソッドはJava型をバインドするために、Oracle固有のsetXXXメソッドはOracle固有の型をバインドするために提供されています。
同様に、setNullメソッドには次の2つの形式があります。
-
void setNull(intparameterIndex,intsqlType)これは、標準の
java.sql.PreparedStatementインタフェースで指定されるシグネチャです。このシグネチャは、java.sql.Typesクラスまたはoracle.jdbc.OracleTypesクラスによって定義されるパラメータ索引とSQL型コードを取ります。REF、ARRAYまたはSTRUCT以外のオブジェクトをNULLに設定する場合は、このシグネチャを使用します。 -
void setNull(intparameterIndex,intsqlType, Stringsql_type_name)JDBC 2.0の場合、このシグネチャは標準の
java.sql.PreparedStatementインタフェースにも指定されます。このメソッドは、パラメータ索引およびSQL型コードに加え、SQL型名を取ります。このメソッドは、SQL型コードがjava.sql.Types.REF、ARRAYまたはSTRUCTの場合に使用します。型コードがREF、ARRAYまたはSTRUCT以外の場合、指定されたSQL型名は無視されます。
同様に、registerOutParameterメソッドには、REF、ARRAYまたはSTRUCTデータとともに使用するためのシグネチャがあります。
void registerOutParameter
(int parameterIndex, int sqlType, String sql_type_name)
標準Java型のバインドのためのメソッドではなく、適切なsetXXXメソッドを使用してOracle固有型をバインドすると、多少パフォーマンスが向上することがあります。
この項の内容は次のとおりです。
11.4.7.1 入力データのバインド
入力用のデータのバインド方法は3つあります。
-
データ自体をバインド・バッファに格納するダイレクト・バインド
-
データをストリーム処理するストリーム・バインド
-
一時LOBを作成し、LOB APIを使用してデータをそのLOBに格納し、LOBロケータのバイトをバインド・バッファに格納するLOBバインド
3種類のバインドはパフォーマンスが異なり、バッチ処理に影響を与えます。ダイレクト・バインドは最も高速で、バッチ処理が正常に行われます。ストリーム・バインドはより低速で、複数のラウンドトリップが必要な場合があり、バッチ処理はオフになります。LOBバインドは非常に低速で、多数のラウンドトリップが必要です。バッチ処理は機能しますが、お薦めできません。これらのバインドでは、SQL文の型に応じてサイズの制限も異なります。
SQLパラメータについては、RAWやVARCHAR2など標準のパラメータ型の長さはターゲット列のサイズによって固定されます。PL/SQLパラメータについては、サイズは32766という固定バイト数に制限されます。
Oracle Database 10gリリース2では、PreparedStatementのsetString、setCharacterStream、setAsciiStream、setBytesおよびsetBinaryStreamメソッドが一部変更されています。APIの当初の動作は次のとおりでした。
-
setString: キャラクタのダイレクト・バインド -
setCharacterStream: キャラクタのストリーム・バインド -
setAsciiStream: バイトのストリーム・バインド -
setBytes: バイトのダイレクト・バインド -
setBinaryStream: バイトのストリーム・バインド
Oracle Database 10gリリース2以降、データ・サイズおよびSQL文の型に基づくバインド・モードの自動切替えがサポートされています。
setBytesおよびsetBinaryStream
SQLでは、サイズが2000以下の場合はダイレクト・バインド、2000を超える場合はストリーム・バインドが使用されます。
PL/SQLでは、サイズが32766以下の場合はダイレクト・バインド、32766を超える場合はLOBバインドが使用されます。
setString、setCharacterStreamおよびsetAsciiStream
SQLでは、Javaキャラクタが32766以下の場合はダイレクト・バインド、32766を超える場合はストリーム・バインドが使用されます。これは文字セットに依存しません。
PL/SQLでは、使用形式パラメータの設定に応じて、データベース文字セットまたは各国語文字セット内のキャラクタ・データのバイト・サイズに注意する必要があります。バイト長が32766未満のデータにはダイレクト・バインド、32766以上のデータにはLOBバインドが使用されます。
固定長文字セットについては、Javaキャラクタ・データの長さにバイト単位の固定文字サイズをかけた値を上限値と比較します。可変長文字セットについては、Javaキャラクタの長さに応じて、次の3つの場合があります。
-
文字長が32766を最大文字サイズで割った値よりも小さい場合は、ダイレクト・バインドが使用されます。
-
文字長が32766を最小文字サイズで割った値よりも大きい場合は、LOBバインドが使用されます。
-
文字長がその間であり、変換済バイトの実際の長さが32766未満の場合は、ダイレクト・バインドが使用され、それ以外の場合はLOBバインドが使用されます。
ノート:
PL/SQLプロシージャがSQL文に埋め込まれている場合、バインド処理は異なります。
サーバー側内部ドライバには、他にも次の制限事項があります。
-
データ・サイズの文字数が32767バイトを超える場合、
setString、setCharacterStreamおよびsetASCIIStreamの各APIはSQL CLOB列ではサポートされていません。 -
データ・サイズが32767バイトを超える場合、
setBytesおよびsetBinaryStreamの各APIはSQL BLOB列ではサポートされていません。
ノート:
サーバー側内部ドライバでこれらのAPIを使用する場合は、クライアント・コードのデータ・サイズを入念にチェックしてください。
関連トピック
関連項目:
詳細な説明および考えられる対応策は、JDBCのリリース・ノートを参照してください。
11.4.7.2 WHERE句にCHARデータをバインドするためのメソッドsetFixedCHAR
データベース内のCHARデータは、列幅まで埋め込まれます。このため、SELECT文のWHERE句に文字データをバインドするためのsetCHARメソッドの使用に関して、制限が生じます。WHERE句の文字データも、SELECT文で合致させるために、列幅まで埋め込む必要があります。これは特に列幅がわからない場合に問題になります。
これを修正するために、OracleはOraclePreparedStatementクラスにsetFixedCHARメソッドを追加しました。このメソッドは埋込みなしの比較を実行します。
ノート:
-
setFixedCHARメソッドを使用するには、必ずプリペアド文オブジェクトをOraclePreparedStatementにキャストしてください。 -
INSERT文で、setFixedCHARを使用する必要はありません。データベースは挿入時に、常にそのデータを列幅まで自動的に埋め込みます。
例
次の例では、setCHARメソッドとsetFixedCHARメソッドの違いを示します。
/* Schema is :
create table my_table (col1 char(10));
insert into my_table values ('JDBC');
*/
PreparedStatement pstmt = conn.prepareStatement
("select count(*) from my_table where col1 = ?");
pstmt.setString (1, "JDBC"); // Set the Bind Value
runQuery (pstmt); // This will print " No of rows are 0"
CHAR ch = new CHAR("JDBC ", null);
((OraclePreparedStatement)pstmt).setCHAR(1, ch); // Pad it to 10 bytes
runQuery (pstmt); // This will print "No of rows are 1"
((OraclePreparedStatement)pstmt).setFixedCHAR(1, "JDBC");
runQuery (pstmt); // This will print "No of rows are 1"
void runQuery (PreparedStatement ps)
{
// Run the Query
ResultSet rs = pstmt.executeQuery ();
while (rs.next())
System.out.println("No of rows are " + rs.getInt(1));
rs.close();
rs = null;
}
11.5 結果セット・メタデータ拡張機能の使用方法
oracle.jdbc.OracleResultSetMetaDataインタフェースはJDBC 2.0に準拠していますが、Oracle Databaseによってサポートされていないため、getSchemaNameメソッドとgetTableNameメソッドは実装されません。
次のコードは、OracleResultSetMetadataインタフェースのメソッドをいくつか使用して、EMPLOYEES表から列数を取り出し、各列の数値型とSQL型名を取り出します。
DatabaseMetaData dbmd = conn.getMetaData();
ResultSet rset = dbmd.getTables("", "HR", "EMPLOYEES", null);
while (rset.next())
{
OracleResultSetMetaData orsmd = ((OracleResultSet)rset).getMetaData();
int numColumns = orsmd.getColumnCount();
System.out.println("Num of columns = " + numColumns);
for (int i=0; i<numColumns; i++)
{
System.out.print ("Column Name=" + orsmd.getColumnName (i+1));
System.out.print (" Type=" + orsmd.getColumnType (i + 1) );
System.out.println (" Type Name=" + orsmd.getColumnTypeName (i + 1));
}
}
このプログラムは次の出力を戻します。
Num of columns = 5 Column Name=TABLE_CAT Type=12 Type Name=VARCHAR2 Column Name=TABLE_SCHEM Type=12 Type Name=VARCHAR2 Column Name=TABLE_NAME Type=12 Type Name=VARCHAR2 Column Name=TABLE_TYPE Type=12 Type Name=VARCHAR2 Column Name=TABLE_REMARKS Type=12 Type Name=VARCHAR2
11.6 SQL CALL文とCALL INTO文の使用について
次の2つの方法で、CALL文を使用してSQL内からルーチンを実行できます。
ノート:
ルーチンとは、スタンドアロンのプロシージャまたは関数や、型またはパッケージ内で定義されているプロシージャまたは関数です。スタンドアロンのルーチン上、またはルーチンが定義されている型やパッケージ上で、EXECUTE権限を持っている必要があります。
-
コールをルーチン自身に名前で送信するか、
routine_clauseを使用します。 -
式の型の内部で
object_access_expressionを使用します。
ルーチンが引数を取る場合は、引数を指定できます。引数には、位置表記、名前表記または混合表記を使用できます。
CALL INTO文
INTO句は関数のコールにのみ適用されます。この句には次の型の変数を使用できます。
-
ホスト変数
-
標識変数
関連項目:
詳細は、『Oracle Database SQL言語リファレンス』を参照してください
PL/SQLブロック
PL/SQLの基本単位は、ブロックです。すべてのPL/SQLプログラムはブロックで構成されており、ブロックは互いの内部にネストすることができます。PL/SQLブロックには、宣言部、実行部、例外処理部の3つの部分があります。アプリケーションでPL/SQLブロックを使用すると、次の利点があります。
-
パフォーマンスの向上
-
生産性の向上
-
完全な移植性
-
Oracleとの密接な統合
-
厳重なセキュリティ