4 Oracle拡張機能
Oracleには、Java Database Connectivity(JDBC)標準の実装を拡張するJavaクラスとインタフェースが用意されており、開発者は、Oracleデータ型にアクセスして操作し、Oracleパフォーマンス拡張機能を使用できます。この章では、JDBC標準実装を拡張するためにOracleで提供されるクラスとインタフェースの概要を示します。また、この拡張機能がサポートする主な機能についても説明します。
この章の構成は、次のとおりです。
関連トピック
4.1 Oracle拡張機能の概要
標準機能に加えて、Oracle JDBCドライバにはOracle固有型拡張機能およびパフォーマンス拡張機能があります。これらの拡張機能は、次のJavaパッケージに用意されています。
-
oracle.sqlOracle形式でSQLデータを示すクラスを提供します。
-
oracle.jdbcOracle型形式でのデータベース・アクセスおよび更新をサポートするためのインタフェースを提供します。
関連トピック
4.2 Oracle拡張機能
JDBCへのOracle拡張機能には、Oracle Databaseを操作する能力を高めるいくつかの機能があります。次のようなものがあります:
4.2.1 JDBCを使用したデータベース管理
Oracle Database 11gリリース1以降、2つのJDBCメソッド、startupおよびshutdownがoracle.jdbc.OracleConnectionインタフェースに追加されており、これによりOracle Databaseインスタンスの起動と停止を実行できます。
ノート:
My Oracle Supportノート335754.1に、Oracle Database 11g JDBCドライバでoracle.jdbc.driver.*パッケージがサポート対象外であることが記載されています。つまり、Oracle Database 10gリリース2がこのパッケージをサポートする最後のデータベースであり、現在のリリースのデータベースでは、oracle.jdbc.driver.*パッケージに依存するすべてのAPIはコンパイルできなくなります。このようなAPIを削除して、標準のAPIに移行する必要があります。たとえば、コードでoracle.jdbc.CustomDatumおよびoracle.jdbc.CustomDatumFactoryインタフェースを使用する場合、これらをjava.sql.Structまたはjava.sql.SQLDataインタフェースで置き換える必要があります。
関連トピック
4.2.2 Oracleデータ型のサポート
Oracle JDBC拡張機能の1つは、oracle.sqlパッケージの型のサポートです。このパッケージには、Oracle形式でのデータの正確な表現であるクラスが含まれています。プログラムでoracle.sql型を使用する際には、次の重要な点に注意してください。
-
数値型データの場合、標準Java型への変換では、データ変換プロセスの制限のために完全な精度が維持されません。データ損失の問題を最小限に抑えるには、
BigDecimal型を使用してください。 -
特定のデータ型では、標準Java型への変換がシステムの設定によって決まる可能性があり、プログラムが予想どおりに実行されない場合があります。これは、
oracle.sql型から標準Java型へのデータ変換中に発生することが知られている制限です。 -
プログラムの機能が、1つの表からのデータの読取りと、もう1つの表への同じデータの書込みに限定されている場合、数値および日付データについては、標準Java型と比べて
oracle.sql型の方がわずかに速くなります。しかし、比較や印刷などの単純なデータ操作が1つでも含まれている場合は、標準Java型の方が速くなります。 -
oracle.sql.CHARはOracle形式に従うデータの正確な表現ではありません。oracle.sql.CHARはjava.lang.Stringから構成されます。java.lang.Stringの方が常に高速で、同じ文字セットを表すため、いくつかのサポートされていない文字セットを除いて、oracle.sql.CHARを使用する利点がありません。
ノート:
標準のJava型を使用して、既存のoracle.sql型のデータを標準のJava型に変換することを強くお薦めします。内部的には、Oracle JDBCドライバはJava標準型のパフォーマンスを最適化するように動作します。oracle.sql型は、下位互換性のためにのみサポートされており、使用は推奨されません。
4.2.3 Oracleオブジェクトのサポート
Oracle JDBCはデータベース内の構造化オブジェクトの使用をサポートしています。ここで、オブジェクトのデータ型はネスト属性を持つユーザー定義の型です。たとえば、ユーザー・アプリケーションがEmployeeオブジェクト型を定義し、各Employeeオブジェクトが、firstname属性(文字列)、lastname属性(文字列)およびemployeenumber属性(整数値)を持つ例が考えられます。
Oracle JDBCは、Oracleオブジェクト・データ型をサポートします。JavaアプリケーションでOracleオブジェクト・データ型を使用する場合、次の点を考慮する必要があります。
-
Oracleオブジェクト・データ型とJavaクラス間のマップ方法
-
Oracleオブジェクトの属性を対応するJavaオブジェクトに格納する方法
-
SQLとJava形式間で属性データを変換する方法
-
データへのアクセス方法
Oracleオブジェクトは、弱い型指定のjava.sql.Struct、または強い型指定のカスタマイズされたクラスのいずれかにマップできます。これらの強い型はカスタムJavaクラスとして参照され、標準java.sql.SQLDataインタフェースまたはOracle拡張機能のoracle.jdbc.OracleDataインタフェースのいずれかを実装している必要があります。各インタフェースは、SQLとJavaとの間でデータ変換を行うメソッドを指定します。
ノート:
Oracle Database 12cリリース1 (12.1)以降、OracleDataインタフェースはORADataインタフェースに置き換わりました。
Oracleオブジェクトに対応するカスタムJavaクラスを作成する場合は、Oracle JVM Webサービス・コールアウト・ユーティリティを使用することをお薦めします。
4.2.4 スキーマの命名サポート
Oracleオブジェクト・データ型クラスには、完全修飾スキーマ名の受入れおよび復帰を行う機能があります。完全修飾スキーマ名は、次の構文になります。
{[schema_name].}[sql_type_name]
ここで、schema_nameはスキーマの名前、sql_type_nameはオブジェクトのSQL型名で、schema_nameとsql_type_nameはピリオド(.)で区切られています。
JDBCでオブジェクト型を指定するには、その完全修飾名を使用します。型名が現行ネームスペース内、つまり現行スキーマ内にある場合は、スキーマ名を入力する必要はありません。スキーマは、次の規則に従って命名されます。
-
スキーマ名と型名は、どちらも引用符で囲んでも囲まなくてもかまいません。ただし、
CORPORATE.EMPLOYEEのように、SQL型名にピリオドが含まれている場合は、型名を引用符で囲む必要があります。 -
JDBCドライバは、オブジェクト名内の引用符で囲まれていない最初のピリオドを検索して、ピリオドの前の文字列をスキーマ名として使用し、ピリオドの後の文字列を型名として使用します。ピリオドが見つからない場合、JDBCドライバは現行スキーマをデフォルトとします。つまり、オブジェクト型名が現行スキーマに属している場合は、完全修飾名を指定するかわりに、スキーマを指定せずに型名のみを指定できます。これが、型名にピリオドが含まれない場合に型名を引用符で囲む理由です。
たとえば、ユーザー
HRがperson.addressという型を作成し、自分のセッション内でそれを使用するとします。HRは、スキーマ名を省略して、person.addressで型をJDBCドライバに渡します。この場合、person.addressを引用符で囲まないとピリオドが検出され、JDBCドライバはpersonをスキーマ名、addressを型名として誤って解釈してしまいます。 -
JDBCは、オブジェクト型名の文字列をデータベースにそのまま渡します。つまり、JDBCドライバは、オブジェクト型名が引用符で囲まれていてもその大/小文字を変更しません。
たとえば、
HR.PersonTypeがJDBCドライバにオブジェクト型名として渡されると、JDBCドライバはその文字列をそのままデータベースに渡します。別の例として、型名の文字列内に空白文字が含まれている場合、JDBCドライバは空白文字を削除しません。
4.2.5 DML RETURNING
Oracle Databaseでは、データ操作言語(DML)文にRETURNING句を使用できます。これによって、2つのSQL文を1文に結合できます。DML RETURNINGは、Oracle JDBC Oracle Call Interface(OCI)ドライバとOracle JDBC Thinドライバの両方でサポートされます。
関連項目:
4.3 Oracle JDBCパッケージ
この項では、Oracle JDBC拡張機能をサポートする、次のJavaパッケージについて説明します。
4.3.1 パッケージoracle.sql
oracle.sqlパッケージは、SQL形式でデータへの直接アクセスをサポートしています。このパッケージは、主に、SQLデータ型とそのサポート・クラスへのJavaマッピングを提供するクラスで構成されています。実質的に、このクラスはSQLデータのJavaコンテナとして機能します。
oracle.sql.*データ型の各クラスは、すべてのデータ型に共通する機能をカプセル化したスーパークラスのoracle.sql.Datumを拡張します。その中には、JDBC 2.0準拠のデータ型に対応したクラスもあります。これらのクラスは、oracle.sql.Datumクラスを拡張すると同時に、java.sqlパッケージの標準JDBC 2.0インタフェースを実装します。
LONGおよびLONG RAWのSQL型と、REF CURSOR型カテゴリには、oracle.sql.*クラスは含まれません。これらの型では、標準JDBC機能を使用してください。たとえば、LONGまたはLONG RAWデータを、標準JDBC結果セットおよびコール可能文メソッドgetBinaryStreamおよびgetCharacterStreamを使用して入力ストリームとして取り出します。REF CURSOR型にはgetCursorメソッドを使用します。
ノート:
可能な場合はJDBC標準型またはJava型の使用をお薦めします。パッケージoracle.sql.*の方は主に下位互換性、またはOracleの少数の特定機能(OPAQUE、OracleData、TIMESTAMPTZなど)のサポートのために用意されています。
oracle.sql.*データ型の一般的なサポート
各Oracleデータ型クラスは、特に次の機能をサポートします。
-
SQLデータ用のJavaバイト配列であるデータ記憶域。
-
SQLデータをバイト配列で戻す
getBytes()メソッド。 -
JDBC仕様の定義に従って、データを対応するJavaクラスのオブジェクトに変換する
toJdbc()メソッド。JDBCドライバは、
BFILEなどの、JDBC仕様の一部ではないOracle固有のデータ型を変換しません。ドライバは、対応するoracle.sql.*形式でオブジェクトを戻します。 -
SQLデータをJava型に変換するのに適切な
xxxValueメソッド。たとえば、stringValue、intValue、booleanValue、dateValueおよびbigDecimalValueがあげられます。 -
補足的な変換メソッド。データをストリームとして取り出すラージ・オブジェクト(LOB)クラスのメソッド、およびオブジェクト参照を使用してオブジェクト・データの取出しや設定を行う
REFクラスのメソッドなど、データ型の機能に適したgetXXXおよびsetXXX。
クラスoracle.sql.STRUCTの概要
oracle.sql.STRUCTクラスは、java.sql.StructインタフェースのOracle実装です。このクラスは値クラスです。構成後にクラスの内容を変更しないでください。このクラスは、すべてのoracle.sql.*データ型のクラスと同様に、oracle.sql.Datumクラスのサブクラスです。
ノート:
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.STRUCTクラスは非推奨となり、oracle.jdbc.OracleStructインタフェースに置き換えられています。このインタフェースはoracle.jdbcパッケージに属します。標準互換性には(可能であれば)java.sqlパッケージの使用可能なメソッドを使用し、Oracle固有の拡張機能にはoracle.jdbcパッケージの使用可能なメソッドを使用することを強くお薦めします。oracle.jdbc.OracleStructインタフェースの詳細は、MoSノート1364193.1を参照してください。
クラスoracle.sql.REFの概要
oracle.sql.REFクラスは、Oracleオブジェクト参照をサポートする一般クラスです。このクラスは、すべてのoracle.sql.*データ型のクラスと同様に、oracle.sql.Datumクラスのサブクラスです。
ノート:
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.REFクラスは非推奨となり、oracle.jdbc.OracleRefインタフェースに置き換えられています。このインタフェースはoracle.jdbcパッケージに属します。標準互換性には(可能であれば)java.sqlパッケージの使用可能なメソッドを使用し、Oracle固有の拡張機能にはoracle.jdbcパッケージの使用可能なメソッドを使用することを強くお薦めします。oracle.jdbc.OracleRefインタフェースの詳細は、MoSノート1364193.1を参照してください。
REFクラスには、オブジェクト参照を取り出して渡すためのメソッドがあります。ただし、オブジェクト参照の選択によって取り出されるのは、オブジェクトへのポインタのみです。これによってオブジェクト自体がインスタンス化されることはありません。ただし、REFクラスにはオブジェクト・データを取り出して渡すためのメソッドも含まれています。JDBCアプリケーションではREFオブジェクトを作成できません。データベースから取り出すことができるのは、既存のREFオブジェクトのみです。
oracle.sql.REFを使用するのではなく、JDBC標準型、java.sql.RefおよびJDBC標準メソッドを使用する必要があります。コードを移植可能にする場合、Oracle JDBCドライバのみがoracle.sql.REF型のインスタンスを使用するので、標準型を使用する必要があります。
クラスoracle.sql.BLOB、oracle.sql.CLOB、oracle.sql.BFILEの概要
バイナリ・ラージ・オブジェクト(BLOB)、キャラクタ・ラージ・オブジェクト(CLOB)およびバイナリ・ファイル(BFILE)は、大きすぎてデータベース表に直接格納できないデータ項目に使用します。一方、データベース表はデータの実際の場所を指すロケータを格納します。
ノート:
-
Oracle Database 12cリリース1 (12.1)以降、
oracle.sql.BLOBクラスおよびOracle.sql.CLOBクラスは非推奨となり、それぞれoracle.jdbc.OracleBlobインタフェースおよびoracle.jdbc.OracleClobインタフェースに置き換えられています。これらのインタフェースはoracle.jdbcパッケージに属します。標準互換性には(可能であれば)java.sqlパッケージの使用可能なメソッドを使用し、Oracle固有の拡張機能にはoracle.jdbcパッケージの使用可能なメソッドを使用することを強くお薦めします。oracle.jdbc.OracleBlobインタフェースおよびoracle.jdbc.OracleClobインタフェースの詳細は、MoSノート1364193.1を参照してください。 -
oracle.sql.BFILEはOracle独自の拡張機能であり、これに相当するJDBC標準機能はありません。
oracle.sqlパッケージは、これらのデータ型を次のいくつかの方法でサポートします。
-
BLOBは、ラージ非構造化バイナリ・データ項目を指し、
oracle.sql.BLOBクラスによりサポートされます。 -
CLOBは、ラージ文字データ項目を指し、
oracle.sql.CLOBクラスによりサポートされます。 -
BFILEは、外部ファイル(オペレーティング・システム・ファイル)の内容を指し、
oracle.sql.BFILEクラスによりサポートされます。BFILEは読取り専用です。
BLOB、CLOBまたはBFILEの各ロケータは、標準的なSELECT文を使用してデータベースから選択できます。ただし、受け取るのはデータではなく、ロケータのみです。データの取出しには、追加ステップが必要です。
クラスoracle.sql.DATE、oracle.sql.NUMBERおよびoracle.sql.RAWの概要
これらのクラスは、プリミティブSQLデータ型を、Oracleネイティブの表現で保持します。ほとんどの場合、ドライバはこれらの型を内部的に使用しません。なるべく標準JDBC型を使用してください。
JavaのDouble値およびFloat NaN値には、等価のOracleのNUMBER表現がありません。たとえば、OracleのBINARY_FLOATデータ型およびBINARY_DOUBLEデータ型の場合、負のゼロは正のゼロに強制変換され、NaNはすべて正規のものに強制変換されます。そのため、oracle.sql.NUMBERクラスを使用して、Double.NaN値またはFloat.NaN値がOracleのNUMBERに変換されると、必ずNullPointerExceptionがスローされます。たとえば、次のコードにより、NullPointerExceptionが発生します。
oracle.sql.NUMBER n = new oracle.sql.NUMBER(Double.NaN); System.out.println(n.doubleValue()); // throws NullPointerException
クラスoracle.sql.TIMESTAMP、oracle.sql.TIMESTAMPTZおよびoracle.sql.TIMESTAMPLTZの概要
JDBCドライバでは、次のような日付/時刻データ型をサポートしています。
-
TIMESTAMP(TIMESTAMP) -
TIMESTAMP WITH TIME ZONE(TIMESTAMPTZ) -
TIMESTAMP WITH LOCAL TIME ZONE(TIMESTAMPLTZ)
JDBCドライバでは、DATEと日付/時刻データ型の間での変換が可能です。たとえば、DATE値としてTIMESTAMP WITH TIME ZONE列にアクセスできます。
JDBCドライバは、業界で最も一般的なタイムゾーン名と、JDKで定義されたタイムゾーン名をサポートしています。タイムゾーンは、java.util.TimeZoneクラスを使用して指定します。
ノート:
-
タイムゾーン・オブジェクトの作成には
TimeZone.getTimeZoneを使用しないでください。これは、Oracleのタイムゾーン・データ型では、JDKよりも多くのタイムゾーン名をサポートしているためです。 -
結果セットの
TIMESTAMPLTZ列の後にLONG列が続く場合、LONG列を読み取ろうとするとエラーになります。
次のコードは、JDKに定義されていないタイムゾーン名であるUS_PACIFICにTimeZoneオブジェクトとCalendarオブジェクトを作成する方法を示します。
TimeZone tz = TimeZone.getDefault();
tz.setID("US_PACIFIC");
GregorianCalendar gcal = new GregorianCalendar(tz);
次のJavaクラスは、SQL日付/時刻データ型を表します。
-
oracle.sql.TIMESTAMP -
oracle.sql.TIMESTAMPTZ -
oracle.sql.TIMESTAMPLTZ
TIMESTAMP WITH LOCAL TIME ZONEデータにアクセスする前に、OracleConnection.setSessionTimeZone(String regionName)メソッドをコールして、セッション・タイム・ゾーンを設定します。このメソッドがコールされると、JDBCドライバは接続のセッション・タイム・ゾーンを設定、保存して、JDBCを介してアクセスされるTIMESTAMP WITH LOCAL TIME ZONEデータをセッション・タイム・ゾーンを使用して調整できるようにします。
ノート:
TIMESTAMP WITH TIME ZONE型とTIMESTAMP WITH LOCAL TIME ZONE型は、標準のjava.sql.Timestamp型として表せます。TIMESTAMP WITH TIME ZONE型とTIMESTAMP WITH LOCAL TIME ZONE型のjava.sql.Timestampに対するバイト表現は簡単です。これは、TIMESTAMP WITH TIME ZONEデータ型とTIMESTAMP WITH LOCAL TIME ZONEデータ型の内部形式はGMTで、java.sql.Timestamp型オブジェクトは内部では、エポックからのミリ秒数であるミリ秒時間値を使用するためです。ただし、これらのデータ型のString表現には、サーバーから動的に取得され、クライアント側にキャッシュされているタイム・ゾーン情報が必要です。
JDBCドライバの旧バージョンでは、タイム・ゾーンのキャッシュは様々な接続で共有されていました。このため、様々なタイム・ゾーンでの非互換性が原因で問題が発生することがよくありました。Oracle Database 11リリース2のJDBCドライバから、タイム・ゾーン・キャッシュは、データベースが提供するタイム・ゾーンのバージョンを基礎とします。この新設計のキャッシュは、タイム・ゾーンのバージョン非互換性に関連するどのような問題も回避します。
クラスoracle.sql.OPAQUEの概要
oracle.sql.OPAQUEクラスは、OPAQUE型の名前と特性および任意の属性を提供します。OPAQUE型では、インスタンスの連続バイトにのみアクセスできます。
ノート:
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.OPAQUEクラスは非推奨となり、oracle.jdbc.OracleOpaqueインタフェースに置き換えられています。このインタフェースはoracle.jdbcパッケージに属します。標準互換性には(可能であれば)java.sqlパッケージの使用可能なメソッドを使用し、Oracle固有の拡張機能にはoracle.jdbcパッケージの使用可能なメソッドを使用することをお薦めします。oracle.jdbc.OracleOpaqueインタフェースの詳細は、MoSノート1364193.1を参照してください。
4.4 Oracle文字データ型のサポート
Oracle文字データ型には、SQL CHARおよびNCHARデータ型が含まれます。次の各項では、oracle.sql.*クラスを使用してこれらのデータ型にアクセスする方法について説明します。
4.4.1 SQL CHARデータ型
SQL CHARデータ型には、CHAR、VARCHAR2およびCLOBデータ型が含まれます。これらのデータ型を使用すると、文字データをデータベース文字セットのコード体系で格納できます。データベースの文字セットは、データベースの作成時に決まります。
4.4.2 SQL NCHARデータ型
SQL NCHARデータ型は、グローバリゼーション・サポート用に作成されたものです。SQL NCHARデータ型には、NCHAR、NVARCHAR2およびNCLOBデータ型が含まれます。これらのデータ型を使用すると、UnicodeデータをデータベースNCHAR文字セットのコード体系で格納できます。NCHAR文字セットは、データベースの作成時に決まり、変更されることはありません。
ノート:
UnicodeStreamクラスが非推奨となってCharacterStreamクラスが導入されたため、NCHARデータ型でのアクセスではsetUnicodeStreamメソッドとgetUnicodeStreamメソッドはサポートされません。ストリーム・アクセスを使用する場合、setCharacterStreamメソッドとgetCharacterStreamメソッドを使用します。
SQL NCHARデータ型の使用方法は、SQL CHARデータ型の場合に類似しています。JDBCでは、対応するSQL CHARデータ型で使用されるのと同じクラスおよびメソッドを使用して、SQL NCHARデータ型にアクセスします。したがって、oracle.sqlパッケージには、SQL NCHARデータ型用の対応する別のクラスが定義されていません。同様に、SQL NCHARデータ型用のoracle.jdbc.OracleTypesクラスにも、対応する別の定数は定義されていません。
ノート:
setFormOfUseメソッドは、registerOutParameterメソッドをコールする前にコールして、予測できない結果を回避する必要があります。
次のコードは、SQL NCHARデータにアクセスする方法を示します。
//
// Table TEST has the following columns:
// - NUMBER
// - NVARCHAR2
// - NCHAR
//
oracle.jdbc.OraclePreparedStatement pstmt =
(oracle.jdbc.OraclePreparedStatement)
conn.prepareStatement("insert into TEST values(?, ?, ?)");
//
// oracle.jdbc.OraclePreparedStatement.FORM_NCHAR should be used for all NCHAR,
// NVARCHAR2 and NCLOB data types.
//
pstmt.setInt(1, 1); // NUMBER column
pstmt.setNString(2, myUnicodeString1); // NVARCHAR2 column
pstmt.setNString(3, myUnicodeString2); // NCHAR column
pstmt.execute();
4.4.3 クラスoracle.sql.CHAR
oracle.sql.CHARクラスは、文字データを処理および変換するためにOracle JDBCによって使用されます。このクラスは、文字データを変換するためのグローバリゼーション・サポート機能を提供します。このクラスには、グローバリゼーション・サポート文字セットおよび文字データという2つの主要な属性があります。グローバリゼーション・サポート文字セットは、文字データのエンコーディングを定義します。これは、CHARオブジェクトの作成時に必ず渡されるパラメータです。グローバリゼーション・サポート文字セット情報がない状態では、CHARオブジェクト内のデータ・バイトは無意味です。oracle.sql.CHARクラスは、SQL CHARおよびSQL NCHARの両方のデータ型に使用されます。
ノート:
10g リリース1より前のバージョンのOracle JDBCドライバでは、oracle.SQL.CHARを使用することでパフォーマンス上の利点がありました。Oracle Database 10g以上では、このような利点はありません。実際には、java.lang.Stringを使用することで最適なパフォーマンスを実現できます。すべてのOracle JDBCドライバが、Java UCS2文字セット内のすべての文字データを処理します。oracle.sql.CHARを使用すると、データベース文字セットとUCS2文字セットとの間の変換が発生します。
oracle.sql.CHARクラスに残された唯一の使用方法は、文字データをOracleグローバリゼーション・サポート文字セットでエンコードされたRAWバイトの形式で処理する場合です。Oracle Databaseから取り出された文字データはすべてjava.lang.Stringクラスを使用してアクセスしてください。別のソースからのバイト・データを処理する場合は、oracle.sql.CHARを使用してバイトをjava.lang.Stringに変換できます。
oracle.sql.CHARを変換するには、データ・バイトと、そのデータ・バイトのエンコードに使用するグローバリゼーション・サポート文字セットを示すoracle.sql.CharacterSetインスタンスを用意する必要があります。
Oracleオブジェクト属性であるCHARオブジェクトは、データベース文字セットで戻されます。
CHARオブジェクトは、必要に応じてJDBCドライバで自動的に作成されるため、まれに作成する必要がある場合でも、JDBCアプリケーション・コードでCHARオブジェクトを直接作成する必要はほとんどありません。
CHARオブジェクトを作成する場合は、CharacterSetクラスのインスタンスによって、CHARオブジェクトに文字セット情報を提供する必要があります。このクラスの各インスタンスは、Oracleがサポートしているグローバリゼーション・サポート文字セットの1つを表します。CharacterSetインスタンスは、文字セットのメソッドおよび属性をカプセル化し、主に他の文字セットとの相互変換機能を提供します。
oracle.sql.CHARオブジェクトの作成
CHARオブジェクトを構築する際、次の一般的なステップに従ってください。
-
CharacterSetオブジェクトは、staticCharacterSet.makeメソッドをコールして作成します。このメソッドは、文字セット・インスタンスのファクトリです。
makeメソッドは、Oracleがサポートする文字セットIDに対応する整数を入力として取ります。たとえば:int oracleId = CharacterSet.JA16SJIS_CHARSET; // this is character set ID, // 832 ... CharacterSet mycharset = CharacterSet.make(oracleId);Oracleがサポートする各文字セットは、事前定義済の一意なOracle IDを保持します。
-
CHARオブジェクトを作成します。文字列または文字列を表すバイトを、文字セットに基づくバイトの解釈方法を指定する
CharacterSetオブジェクトとともに、コンストラクタに渡します。たとえば:String mystring = "teststring"; ... CHAR mychar = new CHAR(teststring, mycharset);
CHARには、CharacterSetオブジェクトとともに、String、byte配列またはオブジェクトを入力として使用できる複数のコンストラクタがあります。Stringの場合、文字列は、CharacterSetオブジェクトが示す文字セットに変換されてから、CHARオブジェクトに格納されます。ノート:
-
CharacterSetオブジェクトをNULL値にすることはできません。 -
CharacterSetクラスは抽象クラスであるため、コンストラクタを持ちません。インスタンスを作成するには、makeメソッドを使用するのが唯一の方法です。 -
サーバーは、特別な値である
CharacterSet.DEFAULT_CHARSETをデータベース文字セットとして認識します。クライアントの場合、この値は無意味です。 -
ユーザーが
CharacterSetクラスを拡張することを、オラクル社は意図しておらず、お薦めもしません。
-
oracle.sql.CHAR変換メソッド
CHARクラスは、文字データを文字列に変換するための次のようなメソッドを提供します。
-
getStringこのメソッドは、
CHARオブジェクトによって表された文字のシーケンスを文字列に変換し、JavaStringオブジェクトを戻します。無効なOracleIDを入力した場合、文字セットは認識されず、getStringメソッドはSQLException例外をスローします。 -
toStringこのメソッドは
getStringメソッドと同じです。ただし、無効なOracleIDを入力すると、文字セットが認識されず、toStringメソッドによりCHARデータの16進表現が戻されます。SQLException例外はスローされません。 -
getStringWithReplacementこのメソッドは
getStringメソッドと同一ですが、CHARオブジェクトの文字セットにUnicode表現のない文字が、デフォルトの置換文字で置き換えられる点が異なります。デフォルトの置換文字は文字セットによって異なりますが、多くの場合は疑問符(?)です。
データベース・サーバーとクライアント、またはクライアント上で動作するアプリケーションでは、異なる文字セットを使用できます。CHARクラスのメソッドを使用してデータをサーバーとクライアント間で転送する場合、JDBCドライバはデータをサーバーの文字セットからクライアントの文字セットに(またはその逆に)変換する必要があります。データを変換する際、ドライバはグローバリゼーション・サポートを使用します。
関連項目:
4.5 その他のOracle型拡張機能
Oracle JDBCドライバは、Oracle固有のBFILEデータ型、ROWIDデータ型およびREF CURSOR型をサポートしますが、これらは標準JDBC仕様に含まれていません。このセクションでは、ROWIDおよびREF CURSOR型の拡張について説明します。ROWIDはJava文字列としてサポートされ、REF CURSOR型はJDBC結果セットとしてサポートされます。
この項の内容は次のとおりです。
4.5.1 Oracle ROWID型
ROWIDは、Oracle Database表の行ごとに一意の識別タグです。ROWIDは、各行のIDを含む仮想列とみなすこともできます。
oracle.sql.ROWIDクラスは、ROWID SQLデータ型のコンテナとして提供されます。
ROWIDは、java.sql.ResultSetインタフェースで指定されるgetCursorNameメソッドおよびjava.sql.Statementインタフェースで指定されるsetCursorNameメソッドに類似した機能を提供します。
問合せにROWID擬似列を指定した場合は、結果セットgetStringメソッドを使用してROWIDを取得できます。また、setStringメソッドを使用すると、ROWIDにPreparedStatementパラメータをバインドできます。これによって、次の例に示すように、埋込み更新を実行できます。
ノート:
oracle.sql.ROWIDクラスを使用するのは、J2SE 5.0を使用する場合のみとしてください。JSE 6の場合は、標準のjava.sql.RowIdインタフェースを使用してください。
例
次の例では、ROWIDデータに対するアクセスおよび操作の方法を示します。
ノート:
次の例は、JSE 6でのみ動作します。
Statement stmt = conn.createStatement();
// Query the employee names with "FOR UPDATE" to lock the rows.
// Select the ROWID to identify the rows to be updated.
ResultSet rset =
stmt.executeQuery ("SELECT first_name, rowid FROM employees FOR UPDATE");
// Prepare a statement to update the first_name column at a given ROWID
PreparedStatement pstmt =
conn.prepareStatement ("UPDATE employees SET first_name = ? WHERE rowid = ?");
// Loop through the results of the query
while (rset.next ())
{
String ename = rset.getString (1);
RowId rowid = rset.getROWID(2); // Get the ROWID as a String
pstmt.setString (1, ename.toLowerCase ());
pstmt.setROWID (2, rowid); // Pass ROWID to the update statement
pstmt.executeUpdate (); // Do the update
}
4.5.2 OracleのREF CURSOR型のカテゴリ
カーソル変数は、問合せ作業領域の(内容でなく)メモリーの場所を保持します。カーソル変数を宣言すると、ポインタが作成されます。SQLでは、ポインタはデータ型REF xを取ります。ここで、REFはREFERENCEの省略形で、xは参照されるエンティティを表します。したがって、REF CURSORはカーソル変数への参照を表します。多くの作業領域を参照する多くのカーソル変数が存在する可能性があるため、REF CURSORは、異なる多くの型のカーソル変数を識別するカテゴリまたはデータ型指定子と考えることができます。Oracle Databaseリリース18c以降、JDBCドライバはINバインド変数としてREF CURSORをサポートしています。
ノート:
REF CURSORインスタンスはスクロールできません。
カーソル変数を作成するには、次のステップを実行します。
-
REFCURSORカテゴリに属している型を指定します。たとえば:DECLARE TYPE DeptCursorTyp IS REF CURSOR -
次に、
DeptCursorTyp型であることを宣言して、カーソル変数を作成します。dept_cv DeptCursorTyp - - declare cursor variable ...REFCURSORは、特定のデータ型というよりも、データ型のカテゴリです。
ストアド・プロシージャは、REF CURSORカテゴリのカーソル変数を受け入れるか、または戻します。この出力は、データベース・カーソルまたはJDBC結果セットと等価です。REF CURSORには、基本的に問合せの結果が格納されます。
JDBCでは、REF CURSORは次のようにアクセスできます。
-
ストアド・プロシージャをコールするには、JDBCコール可能文またはプリペアド文を使用します。
-
ストアド・プロシージャは、
REF CURSORを受け入れるか、または戻します。 -
Javaアプリケーションは、コール可能文またはプリペアド文をOracleコール可能文またはOracleプリペアド文にキャストします。
-
Javaアプリケーションは、
OraclePreparedStatementインタフェースのsetCursorメソッドまたはOracleCallableStatementインタフェースのgetCursorメソッドを使用して、REF CURSORをJDBCResultSetオブジェクトとしてインスタンス化します。 -
結果セットは要求どおりに処理されます。
ノート:
-
REF CURSORと関連付けられたカーソルは、そのREF CURSORを作成したStatementオブジェクトがクローズされるたびにクローズされます。 -
過去のリリースとは異なり、
REF CURSORのインスタンス化が行われた結果セット・オブジェクトがクローズされても、REF CURSORに関連付けられたカーソルはクローズされません。
-
例
この例では、REF CURSORデータにアクセスする方法を示します。
...
// Prepare a PL/SQL call
CallableStatement cstmt =
conn.prepareCall ("DECLARE rc sys_refcursor; curid NUMBER;BEGIN open rc FOR SELECT empno FROM emp order by empno; ? := rc; END;");
cstmt.registerOutParameter (1, OracleTypes.CURSOR);
cstmt.execute ();
ResultSet rset = (ResultSet)cstmt.getObject (1);
if (rset.next ()) {
show (rset.getString ("empno"));
}
CallableStatement cstmt2 =
conn.prepareCall ("DECLARE rc sys_refcursor; v1 NUMBER; BEGIN rc := ?; fetch rc INTO v1; ? := v1; END;");
((OracleCallableStatement)call2).setCursor(1, rset);
cstmt2.registerOutParameter (2, OracleTypes.INTEGER);
cstmt2.execute();
int empno = cstmt2.getInt(2);
show("Fetch in PL/SQL empno=" + empno);
// Dump the cursor
while (rset.next ())
show (rset.getString ("empno"));
// Close all the resources
rset.close();
cstmt.close();
cstmt2.close();
...前述の例は、次のとおりです。
-
cstmt1とcstmt2という2つのCallableStatementオブジェクトがConnectionクラスのprepareCallメソッドを使用して作成されます。 -
cstmt2コール可能文では入力パラメータとしてREF CURSORを使用します。 -
コール可能文によって、
REF CURSORを戻すPL/SQLプロシージャが実装されます。 -
コール可能文の出力パラメータは、通常どおり登録してその型を定義する必要があります。
REF CURSORには、型コードOracleTypes.CURSORを使用します。 -
コール可能文が実行され、
REF CURSORを返すか、またはREF CURSORを入力バインドとして送信します。
4.5.3 Oracle BINARY_FLOAT型およびBINARY_DOUBLE型
Oracle BINARY_FLOAT型およびBINARY_DOUBLE型は、IEEE 574のfloat型とdouble型のデータを格納するために使用します。これらの型は、負とゼロおよびNaNを除いて、Javaのfloatスカラー型とdoubleスカラー型に相当します。
BINARY_DOUBLE列を問合せに含めると、データはデータベースからバイナリ形式で取り出されます。getDoubleメソッドも、データをバイナリ形式で戻します。一方、NUMBERデータ型の列の場合は、数値ビットが戻り、Javaのdoubleデータ型に変換されます。
ノート:
SQL FLOAT型、DOUBLE PRECISION型およびREALデータ型のOracle表現は、Oracle NUMBER表現を使用します。BINARY_FLOAT型とBINARY_DOUBLEデータ型は、独自の型とみなされます。
PreparedStatementインタフェースのJDBC標準setDouble(int, double)メソッドのコールは、Javaのdouble引数をOracleのNUMBERスタイル・ビットに変換してからデータベースに送信します。一方、oracle.jdbc.OraclePreparedStatementインタフェースのsetBinaryDouble(int, double)メソッドは、データを内部バイナリ・ビットに変換してからデータベースに送信します。
使用するデータ形式が、PreparedStatementインタフェースのターゲット・パラメータの型と一致していることを確認してください。この確認によって、データの正確性が保持され、CPUの使用も最小限に抑えられます。NUMBERパラメータにsetBinaryDoubleを使用すると、バイナリ・ビットはサーバーに送信され、NUMBER形式に変換されます。データの正確性は保持されますが、サーバーのCPU負荷は増加します。BINARY_DOUBLEパラメータにsetDoubleを使用すると、データは、クライアントでNUMBERビットに変換されてからサーバーに送信され、そこでバイナリ形式に再変換されます。この方法では、クライアントとサーバーの両方でCPU負荷が増大し、データの精度も低下する可能性があります。
SetFloatAndDoubleUseBinary接続プロパティがtrueに設定されていると、JDBC標準API、setFloat(int, float)、setDouble(int, double)、およびすべての変数では、NUBMERビットではなく、内部バイナリ・ビットを送信するようになります。
ノート:
ここでは、主にBINARY_DOUBLEについて説明しましたが、BINARY_FLOATについても同じ内容が適用されます。
4.5.4 Oracle SYS.ANYTYPE型およびSYS.ANYDATA型
Oracle Database 12cリリース1 (12.1)では、SYS.ANYTYPEおよびSYS.ANYDATAというOracle型にアクセスするためのJavaインタフェースが提供されています。
関連項目:
これらのOracle型の詳細は、『Oracle Database PL/SQLパッケージおよびタイプ・リファレンス』を参照してください
SYS.ANYTYPE型のインスタンスには、オブジェクト型およびコレクション型も含め、SQL型の型記述(永続か一時、名前付きか名前なし)が含まれます。oracle.sql.TypeDescriptorクラスを使用すると、SYS.ANYTYPE型にアクセスできます。ANYTYPEインスタンスは、PL/SQLのプロシージャまたはSQLのSELECT文(SYS.ANYTYPEを列型として使用)を使用して取り出すことができます。ANYTYPEインスタンスをデータベースから取り出すには、getObjectメソッドを使用します。このメソッドは、TypeDescriptorのインスタンスを戻します。
次の任意のANYTYPEインスタンスを取り出すことができます。
-
一時オブジェクト型
-
一時事前定義済型
-
永続オブジェクト型
-
永続事前定義済型
例4-1 SYS.ANYTYPE型へのアクセス
次のコードは、ANYTYPEのインスタンスをデータベースから取り出す方法を示しています。
...
ResultSet rs = stmt.executeQuery("select anytype_column from my_table");
TypeDescriptor td = (TypeDescriptor)rs.getObject(1);
short typeCode = td.getInternalTypeCode();
if(typeCode == TypeDescriptor.TYPECODE_OBJECT)
{
// check if it's a transient type
if(td.isTransientType())
{
AttributeDescriptor[] attributes = ((StructDescriptor)td).getAttributesDescriptor();
for(int i=0; i<attributes.length; i++)
System.out.println(attributes[i].getAttributeName());
}
else
{ System.out.println(td.getTypeName()); }}
...例4-2 一時オブジェクト型のPL/SQLによる作成とJDBCによる取出し
次のサンプル・コードは、JDBCによる一時オブジェクト型の取出し方法を示しています。
...
OracleCallableStatement cstmt = (OracleCallableStatement)conn.prepareCall
("BEGIN ? := transient_obj_type (); END;");
cstmt.registerOutParameter(1,OracleTypes.OPAQUE,"SYS.ANYTYPE");
cstmt.execute();
TypeDescriptor obj = (TypeDescriptor)cstmt.getObject(1);
if(!obj.isTransient())
System.out.println("This must be a JDBC bug");
cstmt.close();
return obj;
...
例4-3 ANYTYPEをINパラメータとして受け取るPL/SQLストアド・プロシージャのコール
次のコードは、ANYTYPEをINパラメータとして受け取るPL/SQLストアド・プロシージャのコール方法を示しています。
...
CallableStatement cstmt = conn.prepareCall("BEGIN ? := dumpanytype(?); END;");
cstmt.registerOutParameter(1,OracleTypes.VARCHAR);
// obj is the instance of TypeDescriptor that you have retrieved
cstmt.setObject(2,obj);
cstmt.execute();
String str = (String)cstmt.getObject(1);
...
oracle.sql.ANYDATAクラスを使用すると、データベースからSYS.ANYDATAインスタンスにアクセスできます。このクラスのインスタンスは、oracle.sql.Datumの任意の有効なインスタンスから取得できます。convertDatumファクトリ・メソッドは、Datumのインスタンスを受け取り、ANYDATAのインスタンスを戻します。このファクトリ・メソッドの構文は、次のとおりです。
public static ANYDATA convertDatum(Datum datum) throws SQLException
oracle.sql.ANYDATAのインスタンスを作成するためのサンプル・コードを、次に示します。
// struct is a valid instance of oracle.sql.STRUCT that either comes from the // database or has been constructed in Java. ANYDATA myAnyData = ANYDATA.convertDatum(struct);
例4-4 ANYDATAのインスタンスに対するデータベースからのアクセス
...
// anydata_table has been created as:
// CREATE TABLE anydata_tab (data SYS.ANYDATA)
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select data from my_anydata_tab");
while(rs.next())
{
ANYDATA anydata = (ANYDATA)rs.getObject(1);
if(!anydata.isNull())
{
TypeDescriptor td = anydata.getTypeDescriptor();
if(td.getTypeCode() == OracleType.TYPECODE_OBJECT)
STRUCT struct = (STRUCT)anydata.accessDatum();
}
}
...
例4-5 データベース表へのANYDATAとしてのオブジェクトの挿入
表およびオブジェクト型が次のように定義されているものとします。
CREATE TABLE anydata_tab ( id NUMBER, data SYS.ANYDATA) CREATE OR REPLACE TYPE employee AS OBJECT ( employee_id NUMBER, first_name VARCHAR2(10) )
次の方法で、SQLオブジェクト型EMPLOYEEのインスタンスを作成し、anydata_tableに挿入することができます。
...
PreparedStatement pstmt = conn.prepareStatement("insert into anydata_table values (?,?)");
Struct myEmployeeStr = conn.createStruct("EMPLOYEE", new Object[]{1120, "Papageno"});
ANYDATA anyda = ANYDATA.convertDatum(myEmployeeStr);
pstmt.setInt(1,123);
pstmt.setObject(2,anyda);
pstmt.executeUpdate();
...
例4-6 データベース表からのANYDATA列の選択
...
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("select data from anydata_table");
while(rs.next())
{
ANYDATA obj = (ANYDATA)rs.getObject(1);
TypeDescriptor td = obj.getTypeDescriptor();
}
rs.close();
stmt.close();
...
4.5.5 oracle.jdbcパッケージ
oracle.jdbcパッケージのインタフェースは、java.sqlのインタフェースに対するOracle拡張機能を定義します。これらの拡張機能によって、この章に記載されているSQL形式のデータへのアクセスが可能になります。また、Oracleパフォーマンス拡張要素など、Oracle固有の他の機能へのアクセスも可能になります。
表4-1に、oracle.jdbcパッケージに含まれる接続に使用する主なインタフェースとクラス、文および結果セットのリストを示します。
表4-1 oracle.jdbcパッケージの主なインタフェースおよびクラス
| 名前 | インタフェースまたはクラス | 主要機能 |
|---|---|---|
|
|
クラス |
|
|
|
インタフェース |
Oracle Databaseインスタンスを起動または停止するためのメソッド、Oracle Statementオブジェクトを戻すメソッド、および現行接続で実行される任意の文に対応したOracleパフォーマンス拡張機能を設定するメソッドを提供します。
|
|
|
インタフェース |
文ごとにOracleパフォーマンス拡張機能を設定するメソッドを提供します。
|
|
|
インタフェース |
SELECT文を実行しないでプリペアド文からメタデータを取得する
|
|
|
インタフェース |
データを
|
|
|
インタフェース |
|
|
|
インタフェース |
列名やデータ型などのOracle結果セットのメタデータ情報を取得するメソッドを提供します。
|
|
|
クラス |
データベース製品名/バージョン、表情報、デフォルト・トランザクション分離レベルなどのデータベースに関するメタデータ情報を取得するメソッドを提供します。
|
|
|
クラス |
SQL型を識別する整数定数を定義します。 標準型の場合、同じ値を標準 |
|
|
インタフェース |
配列全体を取り出し、配列要素のサブセットを取り出し、配列要素のSQLベース型名を取り出すための機能があります。 |
|
|
インタフェース |
|
|
|
インタフェース |
|
|
|
インタフェース |
|
|
|
インタフェース |
|
|
|
インタフェース |
4.5.5.1 インタフェースoracle.jdbc.OracleConnection
このインタフェースは、標準JDBC接続機能を拡張して、Oracle Statementオブジェクトの作成と取得、Oracleパフォーマンス拡張機能用のフラグやオプションの設定、Oracleオブジェクト用型マップのサポート、およびクライアント識別子のサポートを実施します。
Oracle Database 11gリリース1では、Oracle Databaseインスタンスの起動と停止を実行できる新しいメソッドがこのインタフェースに追加されました。また、OracleConnectionインタフェースでは、可視性および透明性を向上させるために、すべての接続プロパティを定数として定義します。
このインタフェースは、DATEおよびNUMBERのようなoracle.sqlデータ値を構築するために、ファクトリ・メソッドも定義します。ファクトリ・メソッドの使用時には次の点に注意してください。
-
oracle.sql型のインスタンスを構築するすべてのコードで、Oracle拡張ファクトリ・メソッドを使用する必要があります。たとえば、ARRAY、BFILE、DATE、INTERVALDS、NUMBER、STRUCT、TIME、TIMESTAMPなどです。 -
標準型のインスタンスを構築するすべてのコードで、JDBC4.0標準ファクトリ・メソッドを使用する必要があります。たとえば、
CLOBBLOBNCLOBなどです。 -
CHAR、JAVA_STRUCT、ArrayDescriptorおよびStructDescriptorには、ファクトリ・メソッドがありません。これらのタイプは内部ドライバ専用です。ノート:
Oracle Database 11gリリース1より前では、引数として
ARRAYおよびSTRUCTクラス・コンストラクタに渡すために、ArrayDescriptorsおよびStructDescriptorsを作成する必要がありました。新しいARRAYおよびStructファクトリ・メソッドは記述子の引数がありません。ドライバはまだ内部で記述子を使用していますが、作成する必要はありません。
クライアント識別子
クライアント識別子を接続プーリング環境で使用すると、データベース・セッションを現在使用している軽量ユーザーを識別できます。クライアント識別子を使用すると、異なるデータベース・セッション間でグローバル・アクセス・アプリケーション・コンテキストを共有することもできます。データベース・セッションで設定されたクライアント識別子は、データベース監査がオンにされたときに監査されます。
関連項目:
詳細は、Oracle Database JDBC Java APIリファレンスを参照してください
4.5.5.3 インタフェースoracle.jdbc.OraclePreparedStatement
このインタフェースは、OracleStatementインタフェースを拡張し、標準JDBCのプリペアド文の機能を拡張します。また、oracle.jdbc.OraclePreparedStatementインタフェースはOracleCallableStatementインタフェースによって拡張されます。拡張機能は次の機能から構成されます。
-
oracle.sql.*型とオブジェクトをプリペアド文にバインドするためのsetXXXメソッド -
SELECT文を実行しないで、プリペアド文からメタデータを取得するための
getMetaDataメソッド -
文単位でOracleパフォーマンス拡張機能をサポートするためのメソッド
ノート:
:NEWまたは:OLD列を参照するトリガーの作成にPreparedStatementインタフェースを使用しないでください。かわりに、Statementを使用してください。PreparedStatementを使用すると、実行が失敗し、メッセージ「java.sql.SQLException: INまたはOUTパラメータがありません - 索引:: 1」が発行されます。
4.5.5.4 インタフェースoracle.jdbc.OracleCallableStatement
このインタフェースは、OracleStatementインタフェースを拡張するOraclePreparedStatementインタフェースを機能拡張し、標準JDBCのコール可能文機能を組み込みます。
ノート:
:NEWまたは:OLD列を参照するトリガーの作成にCallableStatementインタフェースを使用しないでください。かわりにStatementを使用してください。CallableStatementを使用すると、実行が失敗し、メッセージ「java.sql.SQLException: INまたはOUTパラメータがありません - 索引:: 1」が発行されます。
ノート:
-
setXXX(String,...)とregisterOutParameter(String,...)メソッドは、すべてのバインドがプロシージャまたは関数パラメータのみの場合にかぎり使用できます。文はそれ以外のバインドを含むことができません。パラメータ・バインドは疑問符で示す必要があります(:XXではなく、?)。 -
setXXX(int,...)またはsetXXXAtName(String,...)メソッドを使用している場合、出力パラメータは、名前付きパラメータを指定するためのregisterOutParameter(String,...)ではなく、registerOutParameter(int,...)を使用してバインドされます。
4.5.5.6 インタフェースoracle.jdbc.OracleResultSetMetaData
4.5.5.7 クラスoracle.jdbc.OracleTypes
OracleTypesクラスは、JDBCがSQL型を識別するのに使用する定数を定義します。このクラス内の各変数は、整数の定数値を持ちます。oracle.jdbc.OracleTypesクラスには、標準Java java.sql.Typesクラスの型コード定義の複製と、次のOracle拡張機能用の補足的な型コードが含まれます。
-
OracleTypes.BFILE -
OracleTypes.ROWID -
OracleTypes.CURSOR(REF CURSOR型の場合) -
OracleTypes.CHAR_BYTES(同じ列のsetNullとsetCHARメソッドをコールする場合)
java.sql.Typesの場合と同様に、変数名はすべて大文字にする必要があります。
JDBCは、OracleTypesクラスの要素によって識別されたSQL型を、出力パラメータの登録、およびPreparedStatementクラスのsetNullメソッドという2つの分野で使用します。
OracleTypesと出力パラメータの登録
java.sql.Typesまたはoracle.jdbc.OracleTypesの型コードは、java.sql.CallableStatementインタフェースおよびoracle.jdbc.OracleCallableStatementインタフェースのregisterOutParameterメソッドで出力パラメータのSQL型を識別します。
次に、CallableStatementインタフェースおよびOracleCallableStatementインタフェースでregisterOutputParameterメソッドが使用可能な形式を示します。
cs.registerOutParameter(int index, int sqlType); cs.registerOutParameter(int index, int sqlType, String sql_name); cs.registerOutParameter(int index, int sqlType, int scale);
これらのシグネチャでは、indexにはパラメータ索引が、sqlTypeにはSQLデータ型の型コードが入ります。sql_nameにはデータ型に与えられた名前が入りますが、sqlTypeがSTRUCT、REFまたはARRAY型コードの場合にはユーザー定義型の名前が入ります。さらに、sqlTypeがNUMERICまたはDECIMAL型コードの場合には、scaleに、小数点の右側にある桁の数が入ります。
次の例は、CallableStatementインタフェースを使用して、charoutという名前付きプロシージャをコールしています。CHARデータ型が戻されます。registerOutParameterメソッドにおけるOracleTypes.CHAR型のコードの使用に注意してください。
CallableStatement cs = conn.prepareCall ("BEGIN charout (?); END;");
cs.registerOutParameter (1, OracleTypes.CHAR);
cs.execute ();
System.out.println ("Out argument is: " + cs.getString (1));
次の例は、CallableStatementインタフェースを使用して、structoutをコールしています。STRUCTデータ型が戻されます。registerOutParameterの形式では、型コードにTypes.STRUCTまたはOracleTypes.STRUCT、SQL名にEMPLOYEEを指定する必要があります。
この例では、EMPLOYEE型でいかなる型マップも宣言されていないことを前提としているため、STRUCTデータ型内に取得されます。oracle.sql.STRUCTオブジェクトとしてEMPLOYEEの値を取り出すために、Statemenオブジェクトcsは、OracleCallableStatementにキャストされ、Oracle拡張機能getSTRUCTメソッドが実行されます。
CallableStatement cs = conn.prepareCall ("BEGIN structout (?); END;");
cs.registerOutParameter (1, OracleTypes.STRUCT, "EMPLOYEE");
cs.execute ();
// get the value into a STRUCT because it
// is assumed that no type map has been defined
STRUCT emp = ((OracleCallableStatement)cs).getSTRUCT (1);OracleTypesおよびsetNullメソッド
TypesおよびOracleTypesでの型コードは、データ項目のSQL型を特定します。setNullメソッドがそれをNULLに設定します。setNullメソッドは、java.sql.PreparedStatementインタフェースとoracle.jdbc.OraclePreparedStatementインタフェースにあります。
次に、PreparedStatementおよびOraclePreparedStatementオブジェクトでsetNullメソッドが使用可能な形式を示します。
ps.setNull(int index, int sqlType); ps.setNull(int index, int sqlType, String sql_name);
これらのシグネチャでは、indexがパラメータ索引を表します。sqlTypeはSQLデータ型のための型コードです。sql_nameは、sqlTypeがSTRUCT、REFまたはARRAY型コードである場合に、ユーザー定義のデータ型に対して指定される名前です。無効なsqlTypeを入力すると、ParameterTypeConflict例外がスローされます。
次の例では、プリペアド文を使用してNULL値をデータベースに挿入します。NULLに設定する数値オブジェクトの識別にはOracleTypes.NUMERICを使用することに注意してください。ただし、Types.NUMERICも使用されることがあります。
PreparedStatement pstmt =
conn.prepareStatement ("INSERT INTO num_table VALUES (?)");
pstmt.setNull (1, OracleTypes.NUMERIC);
pstmt.execute ();
この例では、プリペアド文を使用して、EMPLOYEE型のNULL STRUCTオブジェクトをデータベースに挿入します。
PreparedStatement pstmt = conn.prepareStatement
("INSERT INTO employees VALUES (?)");
pstmt.setNull (1, OracleTypes.STRUCT, "EMPLOYEE");
pstmt.execute ();
同じ列のsetCHARメソッドもコールする場合、OracleTypes.CHAR_BYTES型をsetNullメソッドで使用することもできます。たとえば:
ps.setCHAR(n, aCHAR); ps.addBatch(); ps.setNull(n, OracleTypes.CHAR_BYTES); ps.addBatch();
この例では、OracleTypes.CHAR_BYTES型以外のどの型を使用しても、データベースとの余計なラウンドトリップが発生します。また、setNullメソッドを使用しないでコードを記述することもできます。たとえば、次の例のようにコードを記述することもできます。
ps.setCHAR(n, null);
4.6 DML RETURNING
DML RETURNING機能は、自動生成キーの取出しに比べて、より豊富な機能を提供します。この機能は、自動生成キーの取出しに使用できますが、アプリケーションで使用する可能性がある他の列や値の取出しにも使用できます。
ノート:
-
サーバー側内部ドライバは、DML RETURNINGおよび自動生成キーの取出しをサポートしていません。
-
同一文中でDML RETURNINGと自動生成キーの取得の両方を使用することはできません。
次の各項では、DML RETURNING機能のサポートについて説明します。
関連項目:
4.6.1 Oracle固有のAPI
OraclePreparedStatementインタフェースは、DML RETURNINGをサポートするOracle固有のApplication Program Interface(API)に伴って機能拡張されました。DML RETURNINGによって戻されるパラメータおよび取り出されるデータを登録するために、registerReturnParameterメソッドおよびgetReturnResultSetメソッドがoracle.jdbc.OraclePreparedStatementインタフェースに追加されています。
DML RETURNING機能の戻りパラメータは、registerReturnParameterメソッドを使用して登録します。エラーが発生した場合、メソッドはSQLExceptionインスタンスをスローします。戻りパラメータの索引を指定する正の整数を渡す必要があります。また、戻りパラメータの型も指定する必要があります。戻りパラメータの最大バイト数または最大文字数も指定できます。このメソッドは、charまたはRAW型でのみ使用できます。SQL構造型の完全修飾名も指定できます。
ノート:
戻りパラメータの最大サイズが不明な場合は、デフォルトの最大サイズを選択するregisterReturnParameter(int paramIndex, int externalType)を使用してください。戻りパラメータの最大サイズが判明している場合は、registerReturnParameter(int paramIndex, int externalType, int maxSize)を使用することでメモリー消費を抑制できます。
getReturnResultSetメソッドは、DML RETURNING機能で戻されたデータをフェッチし、ResultSetオブジェクトとして戻します。エラーが検出された場合は、SQLException例外が発生します。
ノート:
DML RETURNING機能のためのOracle固有のAPIは、Java Development Kit (JDK) 6.0の場合はojdbc6.jar、JDK 7の場合はojdbc7.jarに含まれています。
4.6.2 DML RETURNING文の実行について
DML RETURNING文を実行する前に、JDBCアプリケーションが、registerReturnParameterメソッドを1つ以上コールする必要があります。これらのメソッドは、戻りパラメータに関する型やサイズなどの情報をJDBCドライバに提供します。DML RETURNING文は、executeUpdateまたはexecuteのいずれかの標準JDBC APIを使用して処理されます。戻されたパラメータは、oracle.jdbc.OraclePreparedStatementインタフェースのgetReturnResultSetメソッドを使用して、ResultSetオブジェクトとしてフェッチできます。
ResultSetオブジェクトの値を読み取るには、基礎となるStatementオブジェクトをオープンする必要があります。基礎となるStatementオブジェクトがクローズされている場合は、戻されたResultSetオブジェクトもクローズ状態となります。この状態は、SQL問合せ文を処理することで取り出されたResultSetオブジェクトの状態と一致します。
DML RETURNING文を実行する場合、getReturnResultSetメソッドで戻されるResultSetオブジェクトの同時実行性はCONCUR_READ_ONLYであり、そのResultSetオブジェクト型はTYPE_FORWARD_ONLYまたはTYPE_SCROLL_INSENSITIVEである必要があります。
4.6.3 DML RETURNINGの例
ここでは、DML RETURNING機能に関する2つのコード例を示します。
次のコードは、DML RETURNING機能の使用例です。この例では、name列の最大サイズを100文字と仮定します。name列の最大サイズが判明しているため、registerReturnParameter(int paramIndex, int externalType, int maxSize)メソッドを使用します。
...
OraclePreparedStatement pstmt = (OraclePreparedStatement)conn.prepareStatement(
"delete from tab1 where age < ? returning name into ?");
pstmt.setInt(1,18);
/** register returned parameter
* in this case the maximum size of name is 100 chars
*/
pstmt.registerReturnParameter(2, OracleTypes.VARCHAR, 100);
// process the DML returning statement
count = pstmt.executeUpdate();
if (count>0)
{
ResultSet rset = pstmt.getReturnResultSet(); //rest is not null and not empty
while(rset.next())
{
String name = rset.getString(1);
...
}
}
...
次のコードも、DML RETURNING機能の使用例です。ただし、この例では、戻りパラメータの最大サイズが不明です。したがって、registerReturnParameter(int paramIndex, int externalType)メソッドを使用します。
...
OraclePreparedStatement pstmt = (OraclePreparedStatement)conn.prepareStatement(
"insert into lobtab values (100, empty_clob()) returning col1, col2 into ?, ?");
// register return parameters
pstmt.registerReturnParameter(1, OracleTypes.INTEGER);
pstmt.registerReturnParameter(2, OracleTypes.CLOB);
// process the DML returning SQL statement
pstmt.executeUpdate();
ResultSet rset = pstmt.getReturnResultSet();
int r;
CLOB clob;
if (rset.next())
{
r = rset.getInt(1);
System.out.println(r);
clob = (CLOB)rset.getClob(2);
...
}
...
4.6.4 DML RETURNINGの制限事項
DML RETURNING機能を使用する場合は、次の点に注意してください。
-
getReturnResultSetメソッドを複数回起動した場合は、その戻り値が不正確になります。そのため、これに関連するアクションには依存しないようにします。 -
DML RETURNING文の実行で戻る
ResultSetオブジェクトは、ResultSetMetaData型をサポートしません。したがって、アプリケーションでは、DML RETURNING文を実行する前に、戻りパラメータの情報を把握している必要があります。 -
DML RETURNINGでは、ストリームはサポートされません。
-
DML RETURNING機能をバッチ更新と組み合せることはできません。
-
単一のSQL DML文の中で自動生成キー機能とDML RETURNING機能を両方とも使用することはできません。たとえば、次のような使用方法は許可されません。
... PreparedStatement pstmt = conn.prepareStatement('insert into orders (?, ?, ?) returning order_id into ?"); pstmt.setInt(1, seq01.NEXTVAL); pstmt.setInt(2, 100); pstmt.setInt(3, 966431502); pstmt.registerReturnParam(4, OracleTypes.INTEGER); pstmt.executeUpdate; ResultSet rset = pstmt.getGeneratedKeys; ...
4.7 PL/SQL連想配列へのアクセス
Oracle JDBCドライバを使用すると、JDBCアプリケーションで、連想配列パラメータを使用してPL/SQLをコールできます。PL/SQLでは、連想配列はキーと値ペアのセットです。キーはPLS_INTEGERまたは文字列の場合があります。キーは任意の値であり、稠密である必要はありません。クライアント・アプリケーションから、PLS_INTEGERまたはBINARY_INTEGERキーのみを使用できます。
ノート:
PLS_INTEGERとBINARY_INTEGERは同一のデータ・タイプです。
Oracle JDBCドライバの以前のリリースでは、スカラー・データ型のPL/SQL連想配列のみがサポートされていました。また、サポートは、配列のキーと値のペアの値のみに制限されていました。Oracle Databaseリリース18cでは、連想配列のキー(索引)と値の両方へのアクセスがサポートされ、オブジェクト型の連想配列もサポートされます。新しい機能を実現するには、次のメソッドを使用します。
Array createOracleArray(String arrayTypeName, Object elements) throws SQLExceptionARRAY createARRAY(String typeName, Object elements) throws SQLException前述のメソッドの両方で、2番目のパラメータは、連想配列のキーと値のペアを保持する
java.util.Map<Integer, ?>にすることも、または値の配列だけにすることもできます。これが値の配列である場合、JDBCドライバによって索引が0,1,2などにデフォルト設定されます。java.util.Map<Integer, ?>である場合、JDBCドライバによってキーはデフォルト設定されません。マップで指定されたままになり、疎と負の場合があります。Map<?,?> oracle.jdbc.OracleArray.getJavaMap();このメソッドは、連想配列のデータ型に
Map<?,?>を戻し、ネストした表およびVARRAYにnullを戻します。
ノート:
-
連想配列は、以前は索引付き表と呼ばれていました。
-
文字列のデータ型を使用する場合、サイズはPL/SQLのサイズ(32767文字)に制限されます。サーバー側内部ドライバの場合、制限は小さくなります。
関連項目:
-
Oracle Database JDBC Java APIリファレンス
- 連想配列の詳細は、これらを参照してください