この章では、Java Database Connectivity(JDBC)のユーザー定義オブジェクト型サポートについて説明します。汎用的な弱い型指定のoracle.sql.STRUCT
クラスの機能を説明します。また、JDBC標準SQLData
インタフェースまたはOracle ORAData
インタフェースを実装するカスタムJavaクラスにマップする方法も説明します。
次の項目があります。
関連項目: 『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』 |
Oracleオブジェクト型ではデータベースの複合データ構造がサポートされます。たとえば、name
(CHAR
型)、phoneNumber
(CHAR
型)およびemployeeNumber
(NUMBER
型)の属性を持つPerson
型を定義できます。
Oracleでは、Oracleオブジェクト機能とJDBC機能が密接に統合されています。標準の汎用JDBC型を使用してOracleオブジェクトにマップすることも、カスタムJava型定義クラスを作成してマッピングをカスタマイズすることもできます。
カスタム・オブジェクト・クラスは、データの読取りおよび書込みを行う標準JDBCインタフェースまたはOracle拡張機能インタフェースを実装できます。JDBCでは、Oracleオブジェクトを特定のJavaクラスのインスタンスとしてインスタンス化します。JDBCを使用してOracleオブジェクトにアクセスするには、次の2つの処理を行います。
Oracleオブジェクト用にJavaクラスを作成します。
そのクラスにデータを移入します。次の方法からどちらかを選んで行います。
JDBCを使用して、オブジェクトをSTRUCT
オブジェクトとしてインスタンス化します。
OracleオブジェクトとJavaクラス間のマッピングを明示的に指定します。
これにはオブジェクト・データ用にJavaクラスをカスタマイズすることも含まれます。そうすることにより、ドライバが指定されたカスタム・オブジェクト・クラスのインスタンスにデータを移入できるようになります。この場合、Javaクラスにいくらかの制約が生じます。これらの制約を満たすには、JDBC標準java.sql.SQLData
インタフェースまたはOracle拡張機能oracle.sql.ORAData
インタフェースを実装するようにクラスを定義します。
Oracle JPublisherユーティリティを使用して、カスタムJavaクラスを生成できます。
注意: SQLData インタフェースを使用する場合、弱い型指定のjava.sql.Struct オブジェクトで十分な場合を除き、Java型マップを使用してSQLとJavaのマッピングを指定する必要があります。 |
OracleオブジェクトのSQLとJavaのマッピングを行うカスタムJavaクラスを提供しない場合、Oracle JDBCはオブジェクトをoracle.sql.STRUCT
クラスのインスタンスとしてインスタンス化します。
実際のSQL型が不明な場合は、通常、カスタムJavaオブジェクトのかわりにSTRUCT
オブジェクトを使用します。たとえば、Javaアプリケーションを、エンド・ユーザー・アプリケーションではなく、データベースの任意のオブジェクト・データを操作するツールとして使用する場合があります。データベースから選択したデータをSTRUCT
オブジェクトに挿入したり、データベースにデータを挿入するためにSTRUCT
オブジェクトを作成したりできます。STRUCT
オブジェクトは、データをSQL形式で維持するため、データを完全に保存します。アプリケーション固有の形式による情報が不要な場合は、STRUCT
オブジェクトを使用すると、データをより効率的に、より正確に保存できます。
この項には、次の項目が含まれます。
この項では、標準メソッドの機能とoracle.sql.STRUCT
のOracle固有の機能を対比させて説明します。また、STRUCT
記述子を説明し、STRUCT
クラスのメソッド一覧を示すことにより、機能の概要を示します。
標準java.sql.Structメソッド
コードを標準JDBC 2.0に準拠させる必要がある場合、java.sql.Struct
インスタンスを使用し、次の標準メソッドを使用します。
getAttributes(map)
このメソッドは属性の値を取り出します。このときは、指定された型マップのエントリから、構造化オブジェクト型である属性のインスタンス化に使用するJavaクラスが判断されます。その他の属性値のJava型は、基礎となるSQL型のデータでgetObject
をコールしたときと同じになります。
getAttributes
このメソッドは、前述のgetAttributes(map)
メソッドと同じですが、接続にはデフォルト型マップが使用されます。
このメソッドは、このStruct
が表すOracleオブジェクト型の完全修飾名を表すJava String
を戻します。
Oracle oracle.sql.STRUCTクラス・メソッド
Oracle定義のメソッドで提供される拡張機能を利用するには、oracle.sql.STRUCT
インスタンスを使用します。
oracle.sql.STRUCT
クラスはjava.sql.Struct
インタフェースを実装し、JDBC 2.0標準を超える拡張機能を提供します。
STRUCT
クラスには、標準Struct
機能の他に、次のメソッドが含まれます。
この項では、Oracle固有の機能またはJDBC 2.0標準機能を使用して、Oracleオブジェクトとその属性を取り出し、操作する方法を説明します。
oracle.sql.STRUCTオブジェクトとしてのOracleオブジェクトの取出し
Oracleオブジェクトを直接oracle.sql.STRUCT
インスタンスに取り出すことができます。次の例では、getObject
を使用して、表struct_table
のcol1
列からtype_struct
オブジェクトを取得しています。getObject
によってObject
型が戻されるため、戻り値はoracle.sql.STRUCT
にキャストされます。次の例では、Statement
オブジェクトstmt
はすでに生成されているものとします。
String cmd; cmd = "CREATE TYPE type_struct AS object (field1 NUMBER,field2 DATE)"; stmt.execute(cmd); cmd = "CREATE TABLE struct_table (col1 type_struct)"; stmt.execute(cmd); cmd = "INSERT INTO struct_table VALUES (type_struct(10,'01-apr-01'))"; stmt.execute(cmd); cmd = "INSERT INTO struct_table VALUES (type_struct(20,'02-may-02'))"; stmt.execute(cmd); ResultSet rs= stmt.executeQuery("SELECT * FROM struct_table"); oracle.sql.STRUCT oracleSTRUCT=(oracle.sql.STRUCT)rs.getObject(1);
オブジェクトをSTRUCT
オブジェクトとして戻すには、結果セットをOracleResultSet
にキャストし、Oracle拡張機能getSTRUCT
メソッドを使用する方法もあります。
oracle.sql.STRUCT oracleSTRUCT=((OracleResultSet)rs).getSTRUCT(1);
java.sql.StructオブジェクトとしてのOracleオブジェクトの取出し
前述の例では、getObject
などの標準JDBC機能を使用して、データベースからOracleオブジェクトをjava.sql.Struct
のインスタンスとして取り出すこともできます。getObject
によってjava.lang.Object
が戻されるため、メソッドの出力はStruct
にキャストする必要があります。たとえば、次のようになります。
ResultSet rs= stmt.executeQuery("SELECT * FROM struct_table"); java.sql.Struct jdbcStruct = (java.sql.Struct)rs.getObject(1);
STRUCT
インスタンスまたはStruct
インスタンスからoracle.sql
型としてOracleオブジェクト属性を取り出すには、次のように、oracle.sql.STRUCT
クラスのgetOracleAttributes
メソッドを使用します。
oracle.sql.Datum[] attrs = oracleSTRUCT.getOracleAttributes();
または
oracle.sql.Datum[] attrs = ((oracle.sql.STRUCT)jdbcStruct).getOracleAttributes();
標準Java型としての属性の取出し
STRUCT
またはStruct
インスタンスから標準Java型としてOracleオブジェクト属性を取り出すには、次のように標準getAttributes
メソッドを使用します。
Object[] attrs = jdbcStruct.getAttributes();
注意: Oracle JDBCドライバは、配列および構造の記述子をキャッシュします。そのためパフォーマンスは大きく向上します。ただし、データベース内で構造型の基礎となる型定義を変更すると、その構造型のキャッシュされた記述子は古くなり、アプリケーションでSQLException 例外が通知されます。 |
この項では、STRUCT
オブジェクトを作成する方法について説明します。
StructDescriptorおよびSTRUCTオブジェクト作成の手順
STRUCT
オブジェクトを作成するには、次を実行します。
指定されたOracleオブジェクト型のStructDescriptor
オブジェクトがまだ作成されていない場合は作成します。
StructDescriptor
を使用して、STRUCT
オブジェクトを作成します。
StructDescriptor
はoracle.sql.StructDescriptor
クラスのインスタンスで、Oracleオブジェクトの型を記述します。各Oracleオブジェクト型に必要なStructDescriptor
は、1つのみです。ドライバは、StructDescriptor
オブジェクトをキャッシュして、すでに遭遇した型を再作成しなくても済むようにします。
STRUCT
オブジェクトを作成するには、先に、指定されたOracleオブジェクト型のStructDescriptor
が存在している必要があります。StructDescriptor
オブジェクトが存在しない場合は、静的StructDescriptor.createDescriptor
メソッドをコールして作成できます。このメソッドには、次のように、Oracleオブジェクト型のSQL型名と接続オブジェクトを渡す必要があります。
StructDescriptor structdesc = StructDescriptor.createDescriptor (sql_type_name, connection);
sql_type_name
パラメータは、Oracleオブジェクト型の名前(EMPLOYEE
など)を含むJava String
です。connection
は接続オブジェクトです。
Oracleオブジェクト型のStructDescriptor
オブジェクトを作成した後、STRUCT
オブジェクトを作成できます。そのためには、Connection
オブジェクト、StructDescriptor
オブジェクト、およびSTRUCT
に含める属性が含まれたJavaオブジェクトの配列を指定します。
STRUCT
の次のコンストラクタを使用できます。
STRUCT(Connection conn, java.sql.StructDescriptor structDesc, Object[] attributes) STRUCT(Connection conn, java.sql.StructDescriptor structDesc, java.util.Map map)
structDesc
パラメータには、以前に作成したStructDescriptor
オブジェクトを、conn
には、使用するConnection
オブジェクトを指定します。属性は、java.lang.Object
の配列として、またはjava.util.Map
オブジェクトとして渡すことができます。
次のコードは、Object
配列を取るコンストラクタの使用方法を示しています。
... Object[] attributes = {"attribute1", null}; STRUCT struct = new STRUCT(connection, structDescriptor, attributes); ...
次のコードは、Map
オブジェクトを取るコンストラクタの使用方法を示しています。
... HashMap map = new HashMap(1); map.put("A1","attribute1"); STRUCT struct = new STRUCT(connection, structDescriptor, map); ...
oracle.sql.STRUCT
オブジェクトをプリコンパイルされたSQL文またはコール可能文にバインドするには、標準setObject
メソッド(型コードを指定)を使用するか、文オブジェクトをOracle文の型にキャストしてからOracle拡張機能のsetOracleObject
メソッドを使用します。たとえば、次のようになります。
PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
STRUCT mySTRUCT = new STRUCT (...);
ps.setObject(1, mySTRUCT, Types.STRUCT);
または
PreparedStatement ps= conn.prepareStatement("text_of_prepared_statement");
STRUCT mySTRUCT = new STRUCT (...);
((OraclePreparedStatement)ps).setOracleObject(1, mySTRUCT);
Oracle JDBCドライバには、STRUCT
属性のバッファリングを有効または無効にするためのパブリック・メソッドが用意されています。
oracle.sql.STRUCT
クラスには、次のメソッドが含まれます。
setAutoBuffering(boolean)
メソッドは自動バッファリングを有効または無効にします。getAutoBuffering
メソッドは、現行の自動バッファリング・モードを戻します。デフォルトでは、自動バッファリングは無効です。
Java Virtual Machine(JVM)メモリーに、ARRAY
データをオーバーフローなしに格納できると仮定し、STRUCT
属性にgetAttributes
メソッドとgetArray
メソッドで複数回アクセスする場合は、JDBCアプリケーションの自動バッファリングを有効にすることをお薦めします。
注意: 変換した属性をバッファリングすると、JDBCアプリケーションでは、大量のメモリーが消費されます。 |
自動バッファリングを有効にすると、oracle.sql.STRUCT
オブジェクトでは、変換したすべての属性のローカルのコピーが保持されます。このデータは保持されるため、この情報に後でアクセスするときにはデータ・フォーマット変換処理を実行しなくて済みます。
Oracleオブジェクト用にカスタム・オブジェクト・クラスを作成する場合は、型マップのエントリを定義する必要があります。ドライバはこの型マップに従ってOracleオブジェクトに対応するカスタム・オブジェクト・クラスをインスタンス化します。
Oracleオブジェクトとその属性データからカスタム・オブジェクト・クラスのインスタンスを作成し、データを移入する方法も指定する必要があります。ドライバによって、カスタム・オブジェクト・クラスからのデータの読取り、およびカスタム・オブジェクト・クラスへのデータの移入が実行できる必要があります。また、カスタム・オブジェクト・クラスは、提供する必要があるかどうかにかかわらず、Oracleオブジェクトの属性に対応するget
XXX
メソッドおよびset
XXX
メソッドも提供できます。カスタム・クラスの作成とデータ移入、およびドライバの読取り/書込み機能の設定を行うには、次のインタフェースのいずれかを選択します。
JDBC標準SQLData
インタフェース
Oracleが提供するORAData
インタフェースおよびORADataFactory
インタフェース
作成するカスタム・オブジェクト・クラスでは、これらのインタフェースのどちらかを実装する必要があります。ORAData
インタフェースは、カスタム・オブジェクト・クラスに対応するカスタム参照クラスを実装するときにも使用できます。ただし、SQLData
インタフェースを使用している場合、使用できるのは、java.sql.Ref
やoracle.sql.REF
など、弱いJava参照型のみです。SQLData
インタフェースは、SQLオブジェクトのマッピング専用です。
たとえば、データベースにEMPLOYEE
というOracleオブジェクト型があり、そのオブジェクト型にはName
(CHAR
型)およびEmpNum
(NUMBER
型)という2つの属性が設定されているとします。型マップを使用して、EMPLOYEE
オブジェクトがJEmployee
というカスタム・オブジェクト・クラスにマップされるように指定します。JEmployee
クラスでは、SQLData
またはORAData
インタフェースのどちらかを実装できます。
カスタム・オブジェクト・クラスは独自に作成できますが、Oracle JPublisherユーティリティを使用して作成すると便利です。JPublisherは標準SQLData
インタフェースとOracle固有のORAData
インタフェースの両方をサポートしており、どちらかを実装するクラスを生成できます。
この項には、次の項目が含まれます。
2つのインタフェースのどちらを実装するかを決定する場合は、ORAData
とSQLData
の利点を考慮する必要があります。
SQLData
インタフェースは、SQLオブジェクトのマッピング専用です。ORAData
インタフェースは、より柔軟性が高く、他のSQL型と同じようにSQLオブジェクトをマップし、処理をカスタマイズできます。ORAData
オブジェクトは、Oracle Databaseの任意のデータ型から作成できます。これは、たとえば、JavaのRAW
データをシリアライズするときに役立ちます。
ORAData
の利点は次のとおりです。
Oracleオブジェクトの型マップ・エントリが必要ありません。
Oracle拡張機能に対応しています。
oracle.sql.STRUCT
からORAData
を作成できます。この方法は、ネイティブなJava型への変換が最小限で済むため、より効率的です。
パフォーマンスが向上します。ORAData
は、Datum
型を直接使用して動作します。この型は、Oracleオブジェクトを保持するために、ドライバによって使用される内部形式です。
SQLData
はJDBC標準であるため、コードの移植が可能です。
カスタム・オブジェクト・クラスでSQLData
インタフェースを使用する場合は、カスタム・オブジェクト・クラスを指定する型マップ・エントリを作成する必要があります。このエントリを使用して、Oracleオブジェクト型をJavaにマップします。接続オブジェクトのデフォルト型マップを使用することも、結果セットからデータを取り出すときに指定する型マップを使用することもできます。ResultSet
インタフェースのgetObject
メソッドには、型マップを指定するためのシグネチャがあります。次のいずれかのシグネチャを使用できます。
rs.getObject(int columnIndex); rs.getObject(int columnIndex, Map map);
SQLData実装を使用する場合、型マップ・エントリを含めないと、オブジェクトはデフォルトでoracle.sql.STRUCT
クラスにマップされます。これに対し、ORAData
実装には独自のマッピング機能があるため、型マップ・エントリが必要ありません。ORAData
実装を使用する場合は、標準getObject
メソッドではなく、Oracle getORAData
メソッドを使用します。
型マップを使用して、JavaクラスをOracleオブジェクトのSQL型名に関連付けます。このマップは1対1のマッピングで、ハッシュ表にキーワードと値のペアとして格納されます。Oracleオブジェクトからデータを読み取ると、JDBCドライバでは、型マップが参照され、Oracleオブジェクト型のデータのインスタンス化に使用されるJavaクラスが決定されます。Oracleオブジェクトにデータを書き込むと、JDBCドライバによって、SQLData
インタフェースのgetSQLTypeName
メソッドがコールされ、JavaクラスのSQL型名が取り出されます。SQLとJava間の実際の変換は、ドライバにより実行されます。
Oracleオブジェクトに対応しているJavaクラスの属性では、ネイティブなJava型またはOracleネイティブ型を使用して属性を格納できます。
SQLData
実装を使用する場合、型マップを提供するのは、JDBCアプリケーション・プログラマの役割です。型マップは、標準のjava.util.Map
インタフェースを実装するクラスのインスタンスにする必要があります。
独自のクラスも作成できますが、標準のjava.util.Hashtable
クラスが要件を満たしています。
型マップに使用するHashtable
などのクラスは、put
メソッドを実装します。このメソッドは、キーワードと値のペアを入力として取ります。各キーは完全修飾SQL型名で、対応する値は指定されたJavaクラスのインスタンスです。
型マップは、接続インスタンスに関連付けられます。標準java.sql.Connection
インタフェースとOracle固有oracle.jdbc.OracleConnection
クラスには、getTypeMap
メソッドが含まれています。両方ともMap
オブジェクトを戻します。
この項には、次の項目が含まれます。
最初に接続インスタンスが確立されたときには、デフォルト型マップは空です。デフォルト型マップにデータを移入する必要があります。
既存の型マップにエントリを追加するには、次の手順を実行してください。
OracleConnection
オブジェクトのgetTypeMap
メソッドを使用して、接続の型マップ・オブジェクトを戻します。getTypeMap
メソッドはjava.util.Map
オブジェクトを戻します。たとえば、OracleConnection
インスタンスoraconn
があるとします。
java.util.Map myMap = oraconn.getTypeMap();
注意: OracleConnection インスタンスの型マップが初期化されていないと、getTypeMap を最初にコールしたとき、空のマップが戻されます。 |
型マップのput
メソッドを使用して、マップ・エントリを追加します。put
メソッドでは2つの引数、つまり、SQL型名文字列およびそのSQL型をマップするJavaクラスのインスタンスを指定します。
myMap.put(sqlTypeName, classObject);
sqlTypeName
は、データベースのSQL型名の完全修飾名を表す文字列です。classObject
は、そのSQL型をマップするJavaクラス・オブジェクトです。次のようにClass.forName
メソッドを使用して、クラス・オブジェクトを取り出します。
myMap.put(sqlTypeName, Class.forName(className));
たとえば、CORPORATE
データベース・スキーマにPERSON
SQLデータ型が定義されている場合は、そのSQLデータ型を、次の文でPerson
として定義されたPERSON
Javaクラスにマップできます。
myMap.put("CORPORATE.PERSON", Class.forName("Person"));
マップには、CORPORATE
データベースのPERSON
SQLデータ型がPerson
Javaクラスにマップされているエントリがあります。
注意: 型マップのSQL型名は、Oracle Databaseに大文字で格納されているので、すべて大文字にする必要があります。 |
新しい型マップを作成するには、次の手順を実行してください。この例では、java.util.Hashtable
のインスタンスを使用します。これは、java.util.Dictionary
を拡張し、java.util.Map
を実装します。
新しい型マップ・オブジェクトを作成します。
Hashtable newMap = new Hashtable();
型マップ・オブジェクトのput
メソッドを使用して、マップにエントリを追加します。たとえば、CORPORATE
データベースにEMPLOYEE
というSQL型が定義されている場合は、次のように、そのSQL型をEmployee.java
に定義されているEmployee
クラス・オブジェクトにマップできます。
newMap.put("CORPORATE.EMPLOYEE", class.forName("Employee"));
エントリをマップに追加した後に、OracleConnection
オブジェクトのsetTypeMap
メソッドを使用して、接続の既存の型マップを上書きします。たとえば、次のようになります。
oraconn.setTypeMap(newMap);
この例では、setTypeMap
によってoraconn
接続オブジェクトの元のマップがnewMap
に上書きされます。
注意: 接続インスタンスのデフォルト型マップは、マッピングが必要なときに、マップ名を指定しないと使用されます。たとえば、入力としてマップを指定せずに、結果セットのgetObject をコールしたときに使用されます。 |
getObject
コールを使用するときに、適切なエントリを持つ型マップを指定しないと、JDBCドライバはoracle.sql.STRUCT
クラスのインスタンスとしてOracleオブジェクトをインスタンス化します。Oracleオブジェクト型に埋込みオブジェクトが格納されていて、それらのオブジェクトが型マップに存在しない場合、ドライバは埋込みオブジェクトもoracle.sql.STRUCT
のインスタンスとしてインスタンス化します。埋込みオブジェクトが型マップに存在する場合、getAttributes
メソッドをコールすると、埋込みオブジェクトは型マップで指定されたJavaクラスのインスタンスとして戻されます。
Javaアプリケーションで使用可能なOracleオブジェクトとその属性データを作成する方法の1つに、SQLData
インタフェースを実装するカスタム・オブジェクト・クラスを作成する方法があります。このインタフェースを使用する場合は、データベースのOracleオブジェクト型、およびそのオブジェクトに対して作成するカスタム・オブジェクト・クラスに対応する名前を指定する型マップを提供する必要があります。
SQLData
インタフェースでは、Oracleデータベース・オブジェクトに対して行うSQLとJava間の変換の方法を定義します。標準JDBCのjava.sql
パッケージには、SQLData
インタフェースと、そのコンパニオン・インタフェースであるSQLInput
およびSQLOutput
インタフェースが含まれています。
SQLData
を実装するカスタム・オブジェクト・クラスを作成する場合、SQLData
インタフェースで指定されているように、readSQL
メソッドおよびwriteSQL
メソッドを用意する必要があります。
JDBCドライバはreadSQL
メソッドをコールし、データベースからデータ値のストリームを読み取り、カスタム・オブジェクト・クラスのインスタンスに移入します。通常、ドライバでは、OracleResultSet
オブジェクトのgetObject
コールの一部としてこのメソッドが使用されます。
同様に、JDBCドライバはwriteSQL
メソッドをコールし、カスタム・オブジェクト・クラスのインスタンスからデータ値のシーケンスを読み取り、データベースに書き込めるストリームに書き込みます。通常、ドライバでは、OraclePreparedStatement
オブジェクトのsetObject
コールの一部としてこのメソッドが使用されます。
SQLInputインタフェースおよびSQLOutputインタフェース
JDBCドライバには、SQLInput
およびSQLOutput
インタフェースを実装するクラスが含まれます。SQLOutput
オブジェクトまたはSQLInput
オブジェクトの実装は不要です。JDBCドライバで実装されます。
SQLInput
の実装は入力ストリーム・クラスです。このクラスのインスタンスがreadSQL
メソッドに渡されます。SQLInput
には、readObject
、readInt
、readLong
、readFloat
、readBlob
など、Oracleオブジェクトの属性とJava型の変換に使用できるすべてのread
XXX
メソッドが含まれます。各read
XXX
メソッドによって、SQLデータがJavaデータに変換され、対応するJava型とともに結果として戻されます。たとえば、readInt
ではint
が戻されます。
SQLOutput
の実装は出力ストリーム・クラスで、このインスタンスはwriteSQL
メソッドに渡されます。SQLOutput
には、各Java型のwrite
XXX
メソッドが含まれます。各write
XXX
メソッドでは、関連するJava型のパラメータを入力として指定し、JavaデータをSQLデータに変換します。たとえば、writeString
では、JavaクラスのString
属性を入力として指定します。
readSQLおよびwriteSQLメソッドの実装
SQLData
を実装するカスタム・オブジェクト・クラスを作成するときは、readSQL
およびwriteSQL
メソッドを実装する必要があります。
public void readSQL(SQLInput stream, String sql_type_name) throws SQLException
readSQL
メソッドは、SQLInput
ストリームと、データのSQL型名を示す文字列、つまりEMPLOYEE
などのOracleオブジェクト型の名前を入力として取ります。
JavaアプリケーションからgetObject
をコールすると、JDBCドライバではSQLInput
ストリーム・オブジェクトを作成し、データベースのデータをそのオブジェクトに移入します。また、ドライバでは、データベースからデータを読み取るときに、データのSQL型名を決定します。ドライバでは、readSQL
をコールするときに、これらのパラメータを渡します。
readSQL
では、Oracleオブジェクトの属性にマップするJavaデータ型ごとに、渡されたSQLInput
ストリームの適切なread
XXX
メソッドをコールする必要があります。
たとえば、CHAR
変数に従業員名、NUMBER
変数に従業員番号が定義されているEMPLOYEE
オブジェクトを読み取る場合、readSQL
メソッドには、readString
コールとreadInt
コールが必要です。JDBCでは、Oracleオブジェクト型のSQL定義に属性が表示される順序に従ってメソッドをコールします。
readSQL
メソッドは、read
XXX
メソッドによって読み取られて変換されたデータを受け取り、カスタム・オブジェクト・クラス・インスタンスの適切なフィールドまたは要素に割り当てます。
writeSQL
は、次のように実装する必要があります。
public void writeSQL(SQLOutput stream) throws SQLException
writeSQL
メソッドは、SQLOutput
ストリームを入力として受け取ります。
JavaアプリケーションからsetObject
をコールすると、JDBCドライバはSQLOutput
ストリーム・オブジェクトを作成します。ドライバでは、writeSQL
をコールするときに、このストリーム・パラメータを渡します。
writeSQL
では、Oracleオブジェクトの属性にマップするJavaデータ型ごとに、渡されたSQLInput
ストリームの適切なwrite
XXX
メソッドをコールする必要があります。
たとえば、CHAR
変数に従業員名、NUMBER
変数に従業員番号が定義されているEMPLOYEE
オブジェクトを書き込む場合、writeSQL
メソッドには、writeString
コールとwriteInt
コールが必要です。これらのメソッドは、Oracleオブジェクト型のSQL定義に属性が表示される順序に従ってコールする必要があります。
writeSQL
メソッドは、write
XXX
メソッドをコールしてデータをSQLOutput
ストリームに書き込みます。このデータは、プリコンパイルされたSQL文を実行したときに、データベースに送信されます。
この項では、Oracleオブジェクトに対応するJavaクラスがSQLData
を実装している場合に、そのOracleオブジェクトに対してデータの読取りまたは書込みを行う方法について説明します。
結果セットからのSQLDataオブジェクトの読取り
ここでは、カスタム・オブジェクト・クラスに対してSQLData
実装を選択したときに、OracleオブジェクトのデータをJavaアプリケーションに読み取る手順について説明します。
この手順では、すでにOracleオブジェクト型を定義し、対応するカスタム・オブジェクト・クラスを作成し、OracleオブジェクトとJavaクラス間のマッピングを定義する型マップを更新し、文オブジェクトstmt
を定義しているものとします。
データベースに問合せを行い、OracleオブジェクトをJDBC結果セットに読み取ります。
ResultSet rs = stmt.executeQuery("SELECT emp_col FROM personnel");
表PERSONNEL
には、SQL型EMP_OBJECT
のEMP_COL
という列が1つ含まれています。このSQL型は、JavaクラスEmployee
にマップされるように、型マップに定義されています。
結果セットのgetObject
メソッドを使用して、カスタム・オブジェクト・クラスのインスタンスに結果セットの1行からデータを移入します。型マップにはEmployee
のエントリが含まれるため、getObject
メソッドによりユーザー定義のSQLData
オブジェクトが戻されます。
if (rs.next()) Employee emp = (Employee)rs.getObject(1);
型マップにオブジェクトのエントリが存在しない場合は、getObject
によりoracle.sql.STRUCT
オブジェクトが戻されます。getObject
メソッド・シグネチャによって、汎用のjava.lang.Object
型が戻されるため、出力をSTRUCT
にキャストする必要があります。
if (rs.next()) STRUCT empstruct = (STRUCT)rs.getObject(1);
getObject
メソッドがreadSQL
をコールすると、SQLData
インタフェースからread
XXX
がコールされます。
注意: 定義済の型マップを使用しないようにするには、getSTRUCT メソッドを使用します。このメソッドでは、型マップにマッピング・エントリが定義されている場合でも、常にSTRUCT オブジェクトが戻されます。 |
カスタム・オブジェクト・クラスにget
メソッドが定義されている場合、このメソッドを使用して、オブジェクト属性のデータを読み取ります。たとえば、EMPLOYEE
に、CHAR
型の属性EmpName
およびNUMBER
型の属性EmpNum
がある場合は、Java String
を戻すgetEmpName
メソッドおよびint
値を戻すgetEmpNum
メソッドを指定します。次に、Javaアプリケーションでこれらのメソッドを次の方法でコールします。
String empname = emp.getEmpName(); int empnumber = emp.getEmpNum();
コール可能文OUTパラメータからのSQLDataオブジェクトの取出し
PL/SQLファンクションGETEMPLOYEE
をコールするOracleCallableStatement
インスタンスocs
について考えてみます。このファンクションには、プログラムによって従業員番号が渡されます。そのファンクションから対応するEmployee
オブジェクトが戻されます。このオブジェクトを取り出すには、次の手順を実行します。
GETEMPLOYEE
ファンクションをコールするOracleCallableStatement
を次のように準備します。
OracleCallableStatement ocs = (OracleCallableStatement)conn.prepareCall("{ ? = call GETEMPLOYEE(?) }");
empnumber
を、GETEMPLOYEE
の入力パラメータとして宣言します。SQLData
オブジェクトを、型コードOracleTypes.STRUCT
を指定してOUT
パラメータとして登録します。次に、文を実行します。次のように実行します。
ocs.setInt(2, empnumber); ocs.registerOutParameter(1, OracleTypes.STRUCT, "EMP_OBJECT"); ocs.execute();
getObject
メソッドを使用して、employeeオブジェクトを取り出します。次のコードでは、OracleオブジェクトをJava型Employee
にマップする型マップ・エントリがあるものとします。
Employee emp = (Employee)ocs.getObject(1);
型マップ・エントリが存在しない場合、getObject
はoracle.sql.STRUCT
オブジェクトを戻します。getObject
メソッドによって、汎用のjava.lang.Object
クラスのインスタンスが戻されるため、出力をSTRUCT
型にキャストする必要があります。次のように実行します。
STRUCT emp = (STRUCT)ocs.getObject(1);
SQLDataオブジェクトのINパラメータとしてのコール可能文への引渡し
Employee
オブジェクトをIN
パラメータとして指定され、そのオブジェクトがPERSONNEL
表に追加されているPL/SQLファンクションaddEmployee(?)
を仮定します。この例のemp
は、有効なEmployee
オブジェクトです。
addEmployee(?)
ファンクションをコールするためにOracleCallableStatement
を準備します。
OracleCallableStatement ocs = (OracleCallableStatement) conn.prepareCall("{ call addEmployee(?) }");
setObject
を使用して、emp
オブジェクトをIN
パラメータとしてコール可能文に渡します。次に、文をコールします。
ocs.setObject(1, emp); ocs.execute();
SQLData実装を使用したデータのOracleオブジェクトへの書込み
ここでは、カスタム・オブジェクト・クラスに対してSQLData
実装を選択したときに、JavaアプリケーションのデータをOracleオブジェクトに書き込む手順について説明します。
ここでは、あらかじめOracleオブジェクト型を定義し、対応するカスタムJavaクラスを作成し、OracleオブジェクトとJavaクラス間のマップを定義する型マップを更新していることを前提としています。
カスタム・オブジェクト・クラスにset
メソッドが定義されている場合、このメソッドを使用して、アプリケーションのJava変数のデータをJavaデータ型オブジェクトの属性に書き込みます。
emp.setEmpName(empname); emp.setEmpNum(empnumber);
この文では、前述の例で割り当てたemp
オブジェクト、empname
変数およびempnumber
変数を使用します。
Javaデータ型オブジェクトのデータを使用して、データベース表の行に格納されているOracleオブジェクトを更新する文を、適切に準備します。
PreparedStatement pstmt = conn.prepareStatement ("INSERT INTO PERSONNEL VALUES (?)");
conn
は接続オブジェクトです。
プリコンパイルされたSQL文のsetObject
メソッドを使用して、Javaデータ型オブジェクトをプリコンパイルされたSQL文にバインドします。
pstmt.setObject(1, emp);
文を実行すると、データベースが更新されます。
pstmt.executeUpdate();
Javaアプリケーションで使用できるOracleオブジェクトとその属性データを作成する方法の1つに、oracle.sql.ORAData
インタフェースとoracle.sql.ORADataFactory
インタフェースを実装するカスタム・オブジェクト・クラスを作成する方法があります。ORAData
およびORADataFactory
インタフェースはOracleが提供するもので、JDBC標準の一部ではありません。
注意: JPublisherユーティリティは、ORAData およびORADataFactory インタフェースを実装するクラスの生成をサポートしています。 |
ORADataの機能
ORAData
インタフェースには、次の利点があります。
JDBCのOracle拡張機能を認識しています。ORAData
では、oracle.sql.Datum
型が直接使用されます。
作成中のJavaカスタム・クラスの名前を指定するときに、型マップは必要ありません。
パフォーマンスが向上します。ORAData
は、Datum
型を直接使用して動作します。この型は、Oracleオブジェクトを保持するために、ドライバによって使用される内部形式です。
ORAData
およびORADataFactory
インタフェースでは、次の処理が実行されます。
ORADataFactory
では、カスタム・オブジェクト・クラスのコンストラクタと等価のcreate
メソッドが指定されます。このメソッドでは、ORAData
インスタンスを作成および戻します。JDBCドライバは、create
メソッドを使用して、カスタム・オブジェクト・クラスのインスタンスをJavaアプリケーションまたはアプレットに戻します。このメソッドは、入力として、oracle.sql.Datum
オブジェクトおよびOracleTypes
クラスで指定された対応するSQL型コードを示す整数を取ります。
ORAData
およびORADataFactory
は、次のように定義されます。
public interface ORAData { Datum toDatum (OracleConnection conn) throws SQLException; } public interface ORADataFactory { ORAData create (Datum d, int sql_Type_Code) throws SQLException; }
conn
は接続オブジェクトを、d
はoracle.sql.Datum
型のオブジェクトを、sql_Type_Code
はDatum
オブジェクトのSQL型コードをそれぞれ表します。
オブジェクト・データの取出しと挿入
オブジェクト・データをORAData
のインスタンスとして取得および挿入を行う場合、JDBCドライバでは次のメソッドを使用します。
オブジェクト・データは、次のいずれかの方法で取り出すことができます。
Oracle固有OracleResultSet
クラスの次のgetORAData
メソッドを使用します。
ors.getORAData (int col_index, ORADataFactory factory);
このメソッドでは、結果セットのデータの列索引およびORADataFactory
インスタンスを入力として指定します。たとえば、カスタム・オブジェクト・クラスにgetORAFactory
メソッドを実装して、getORAData
に入力するORADataFactory
インスタンスを作成できます。ORAData
を実装するJavaクラスを使用するときは、型マップは必要ありません。
ResultSet
インタフェースで指定される標準getObject(
index
,
map
)
メソッドを使用して、ORAData
のインスタンスとしてデータを取り出します。この場合、指定されたオブジェクト型で使用されるファクトリ・クラスおよび対応するSQL型名を識別するには、型マップにエントリを定義する必要があります。
オブジェクト・データは、次のいずれかの方法で挿入できます。
Oracle固有OraclePreparedStatement
クラスの次のsetORAData
メソッドを使用します。
ops.setORAData (int bind_index, ORAData custom_obj);
このメソッドでは、バインド変数のパラメータ索引、および変数を含むオブジェクト名を入力として指定します。
PreparedStatement
インタフェースで指定される標準setObject
メソッドを使用します。このメソッドを別のフォームで使用して、型マップなしでORAData
インスタンスを挿入することもできます。
次の項以降では、getORAData
およびsetORAData
メソッドについて説明します。
OracleオブジェクトEMPLOYEE
の例を引き続き使用するには、Javaアプリケーションに次のコードを記述する必要があります。
ORAData datum = ors.getORAData(1, Employee.getORAFactory());
この例では、ors
はOracle結果セット、getORAData
はORAData
オブジェクトの取出しに使用されるOracleResultSet
クラス、およびEMPLOYEE
は結果セットの列1です。static
Employee.getORAFactory
メソッドによって、ORADataFactory
がJDBCドライバに戻されます。JDBCドライバでは、このオブジェクトからcreate()
をコールし、結果セットのデータが移入されたEmployee
クラスのインスタンスをJavaアプリケーションに戻します。
注意:
|
この項では、対応するJavaクラスがORAData
を実装する場合に、Oracleオブジェクトに対してデータの読取りまたは書込みを行う方法について説明します。
ORAData実装を使用したOracleオブジェクトからのデータの読取り
ここでは、データをOracleオブジェクトからJavaアプリケーションに読み取る手順について説明します。この手順は、ORAData
を手動で実装する場合と、JPublisherを使用してカスタム・オブジェクト・クラスを作成する場合の両方に適用されます。
この手順では、すでにOracleオブジェクト型を定義し、対応するカスタム・オブジェクト・クラスを手動、またはJPublisherを使用して作成し、文オブジェクトstmt
を定義しているものとします。
データベースに問合せを行ってOracleオブジェクトを結果セットに読み取り、Oracle結果セットにキャストします。
OracleResultSet ors = (OracleResultSet)stmt.executeQuery ("SELECT Emp_col FROM PERSONNEL");
PERSONNEL
は、1列で構成される表です。列名はEmp_col
、型はEmployee_object
です。
Oracle結果セットのgetORAData
メソッドを使用して、カスタム・オブジェクト・クラスのインスタンスに結果セットの1行からデータを移入します。getORAData
メソッドによりoracle.sql.ORAData
オブジェクトが戻されます。このオブジェクトは特定のカスタム・オブジェクト・クラスにキャストできます。
if (ors.next()) Employee emp = (Employee)ors.getORAData(1, Employee.getORAFactory());
または
if (ors.next()) ORAData datum = ors.getORAData(1, Employee.getORAFactory());
この例では、Employee
はカスタム・オブジェクト・クラス名、ors
はOracleResultSet
オブジェクト名です。
getORAData
を使用しない場合、標準JDBC ResultSet
のgetObject
メソッドを使用してORAData
データを取り出せます。ただし、型マップにはエントリが必要です。このエントリは、指定されたオブジェクト型で使用されるファクトリ・クラス、および対応するSQL型名を識別します。
たとえば、オブジェクトのSQL型名がEMPLOYEE
の場合は、対応するJavaクラスはEmployee
で、ORAData
が実装されます。対応するファクトリ・クラスはEmployeeFactory
で、ORADataFactory
が実装されます。
次の文を使用して、型マップにEmployeeFactory
エントリを宣言します。
map.put ("EMPLOYEE", Class.forName ("EmployeeFactory"));
次に、getObject
の形式を使用し、マップ・オブジェクトを指定します。
Employee emp = (Employee) rs.getObject (1, map);
接続のデフォルトの型マップに、指定されたオブジェクト型と対応するSQL型名に対して使用されるファクトリ・クラスを識別するエントリがすでにある場合は、次の形式のgetObject
を使用できます。
Employee emp = (Employee) rs.getObject (1);
カスタム・オブジェクト・クラスにget
メソッドがある場合は、そのメソッドを使用して、オブジェクト属性のデータをアプリケーションのJava変数に読み取ります。たとえば、EMPLOYEE
に、CHAR
型のEmpName
およびNUMBER
型のEmpNum
がある場合は、Java String
を戻すgetEmpName
メソッドおよび整数値を戻すgetEmpNum
メソッドを指定します。次に、Javaアプリケーションでこれらのメソッドを次の方法でコールします。
String empname = emp.getEmpName(); int empnumber = emp.getEmpNum();
注意: または、コール可能文オブジェクトを使用してデータをフェッチできます。OracleCallableStatement クラスには、getORAData メソッドも定義されています。 |
ORAData実装を使用したデータのOracleオブジェクトへの書込み
ここでは、データをJavaアプリケーションからOracleオブジェクトに書き込む手順について説明します。この手順は、ORAData
を手動で実装する場合と、JPublisherを使用してカスタム・オブジェクト・クラスを作成する場合の両方に適用されます。
この手順では、すでにOracleオブジェクト型を定義し、対応するカスタム・オブジェクト・クラスを作成しているものとします。
注意: データベースのINSERT およびUPDATE 操作の実行時には、型マップは使用されません。 |
カスタム・オブジェクト・クラスにset
メソッドが定義されている場合、このメソッドを使用して、アプリケーションのJava変数のデータをJavaデータ型オブジェクトの属性に書き込みます。
emp.setEmpName(empname); emp.setEmpNum(empnumber);
Javaデータ型オブジェクトのデータを使用して、Oracleオブジェクトを更新するプリコンパイルされたSQL文を、適切にデータベース表の行に書き込みます。
OraclePreparedStatement opstmt = conn.prepareStatement ("UPDATE PERSONNEL SET Employee = ? WHERE Employee.EmpNum = 28959);
この例では、conn
はConnection
オブジェクトです。
プリコンパイルされたSQL文のsetORAData
メソッドを使用して、Javaデータ型オブジェクトをプリコンパイルされたSQL文にバインドします。
opstmt.setORAData(1, emp);
setORAData
メソッドでは、カスタム・オブジェクト・クラス・インスタンスのtoDatum
メソッドをコールすることにより、データベースに書き込むことができるoracle.sql.STRUCT
オブジェクトが取り出されます。
この手順では、setObject
メソッドを使用してJavaデータ型をバインドすることもできます。たとえば、次のようになります。
opstmt.setObject(1,emp);
注意: Javaデータ型オブジェクトを、IN またはOUT バインド変数として使用できます。 |
ORAData
インタフェースには、SQLData
インタフェースより優れた柔軟性があります。SQLData
インタフェースは、Oracleオブジェクト型から目的のJava型へのマッピングをカスタマイズする目的で設計されています。SQLData
インタフェースを実装すると、JavaとSQL型間の変換が正常に終了してから、元のSQLオブジェクト・データからカスタムJavaクラス・インスタンスのフィールドへのデータ移入、およびその逆が、JDBCドライバによって実行されます。
ORAData
インタフェースの場合は、Oracleオブジェクト型からJava型へのカスタマイズがサポートされるのみでなく、このインタフェースによって、Javaオブジェクト型とoracle.sql
パッケージがサポートするすべてのSQL型との間のマッピングが可能になります。
このインタフェースは、oracle.sql.*
型をラップするためのカスタムJavaクラスを提供したり、カスタマイズされた変換または機能を実装したりするときに役立ちます。次の使用例が考えられます。
データの暗号化および復号化、または妥当性チェックを実行します。
読取りまたは書込みを行った値のロギングを実行します。
URL情報を含む文字フィールドなどのキャラクタ列を小さなコンポーネントに解析します。
文字列を数値定数にマップします。
データをより適したJava形式にマップします。たとえば、DATE
フィールドをjava.util.Date
形式にマップします。
データ表現をカスタマイズします。たとえば、表の列のデータがフィート単位のとき、選択後にメートルで表現します。
Javaオブジェクトをシリアライズおよびデシリアライズします。
たとえば、ORAData
を使用すると、データベースの特定のSQLオブジェクト型に対応していないJavaオブジェクトのインスタンスを、SQL型RAW
の列に格納できます。ORADataFactory
のcreate
メソッドでは、oracle.sql.RAW
型のオブジェクトから目的のJavaオブジェクトへの変換を実装する必要があります。ORAData
のtoDatum
メソッドでは、Javaオブジェクトからoracle.sql.RAW
型のオブジェクトへの変換を実装する必要があります。これには、Javaのシリアライズなどを使用します。
JDBCドライバでは、データのRAWバイトをoracle.sql.RAW
形式で透過的に取り出します。次に、ORADataFactory
のcreate
メソッドをコールし、oracle.sql.RAW
オブジェクトを目的のJavaクラスに変換します。
データベースにJavaオブジェクトを挿入するときは、そのオブジェクトをRAW
型の列にバインドするのみでデータベースに格納できます。ドライバは、ORAData
のtoDatum
メソッドを透過的にコールして、Javaオブジェクトをoracle.sql.RAW
型のオブジェクトに変換します。このオブジェクトは、データベースにRAW
型の1列として格納されます。
ORAData
インタフェースのサポートにより、これらの変換がoracle.sql.*
形式を使用して動作するように設計されています。この形式はJDBCドライバで使用されている内部形式であるため、効率が大幅に向上します。また、ORAData
を実装するJavaクラスを使用するときに、SQLData
インタフェースで必要な型マップは必要ありません。
oracle.jdbc
インタフェースがoracle.jdbc.driver
クラスにかわってOracle9i Databaseに導入された後、カスタマイズされたオブジェクトへのアクセスに使用されていたoracle.sql.CustomDatum
インタフェースとoracle.sql.CustomDatumFactory
インタフェースは非推奨となりました。新しいインタフェースoracle.sql.ORAData
およびoracle.sql.ORADataFactory
を使用することをお薦めします。
オブジェクト型の継承により、別のオブジェクト型を拡張して新しいオブジェクト型を作成することができます。新しいオブジェクト型は、拡張元のオブジェクト型のサブタイプになります。サブタイプは、そのスーパータイプに定義されたすべての属性およびメソッドを自動的に継承します。サブタイプは、属性およびメソッドを追加し、スーパータイプから継承されたメソッドをオーバーロードまたはオーバーライドできます。
オブジェクト型の継承によって、代入可能性が導入されます。代入可能性とは、T
型の任意のサブタイプに加えて、T
型の値を保持するように宣言したスロットの機能です。Oracle JDBCドライバは、透過的に代入可能性を処理します。
データベース・オブジェクトは、情報が失われることなく、最も固有の型で戻されます。たとえば、STUDENT_T
オブジェクトがPERSON_T
スロットに格納されている場合、Oracle JDBCドライバはSTUDENT_T
オブジェクトを表すJavaオブジェクトを戻します。
この項には、次の項目が含まれます。
明示的にOracleオブジェクト型に対応するJavaクラスを作成するには、カスタム・オブジェクト・クラスを作成します。オブジェクト型の階層がある場合には、Javaクラスの対応する階層を作成できます。
JDBCでデータベース・サブタイプを作成する最も一般的な方法は、java.sql.Statement
インタフェースのexecute
メソッドを使用して、SQLのCREATE TYPE
コマンドを実行することです。たとえば、次のように型継承階層を作成する場合があります。
PERSON_T | STUDENT_T | PARTTIMESTUDENT_T
この場合、JDBCコードは次のようになります。
Statement s = conn.createStatement(); s.execute ("CREATE TYPE Person_T (SSN NUMBER, name VARCHAR2(30), address VARCHAR2(255))"); s.execute ("CREATE TYPE Student_T UNDER Person_t (deptid NUMBER, major VARCHAR2(100))"); s.execute ("CREATE TYPE PartTimeStudent_t UNDER Student_t (numHours NUMBER)");
次のコードでは、ST
型のfoo
メンバー・プロシージャがオーバーロードされ、print
メンバー・プロシージャによってT
型から継承されたコピーが上書きされます。
CREATE TYPE T AS OBJECT (..., MEMBER PROCEDURE foo(x NUMBER), MEMBER PROCEDURE Print(), ... NOT FINAL; CREATE TYPE ST UNDER T (..., MEMBER PROCEDURE foo(x DATE), <-- overload "foo" OVERRIDING MEMBER PROCEDURE Print(), <-- override "print" STATIC FUNCTION bar(...) ... ... );
サブタイプを作成すると、実表の列またはオブジェクト型の属性として使用できます。
関連項目: 『Oracle Databaseオブジェクト・リレーショナル開発者ガイド』 |
一般に、カスタマイズされたJavaクラスはデータベース・オブジェクト・タイプを表します。サブタイプに対してカスタマイズされたJavaクラスを作成するときには、Javaクラスでデータベース・オブジェクト・タイプの階層をミラー化するかどうかを選択できます。
クラスの作成には、ORAData
またはSQLData
ソリューションのいずれかを使用して、オブジェクト型の階層をマップできます。
この項には、次の項目が含まれます。
oracle.sql.ORAData
インタフェースを実装するJavaクラスを使用した、カスタマイズされたマッピングを使用することをお薦めします。ORAData
のマッピングでは、JDBCアプリケーションがORAData
およびORADataFactory
インタフェースを実装する必要があります。ORADataFactory
インタフェースを実装するクラスは、オブジェクトを作成するファクトリを格納します。各オブジェクトはそれぞれ1つのデータベース・オブジェクトを表します。
ORAData
インタフェースを実装するクラスの階層は、データベース・オブジェクト・タイプ階層をミラー化できます。たとえば、PERSON_T
およびSTUDENT_T
に対するJavaクラスのマッピングは、次のようになります。
ORADataを使用したPerson_java
次のコードは、ORAData
およびORADataFactory
インタフェースを実装するPerson_java
クラスを示します。
class Person implements ORAData, ORADataFactory { static final Person _personFactory = new Person(); public NUMBER ssn; public CHAR name; public CHAR address; public static ORADataFactory getORADataFactory() { return _personFactory; } public Person () {} public Person(NUMBER ssn, CHAR name, CHAR address) { this.ssn = ssn; this.name = name; this.address = address; } public Datum toDatum(OracleConnection c) throws SQLException { StructDescriptor sd = StructDescriptor.createDescriptor("SCOTT.PERSON_T", c); Object [] attributes = { ssn, name, address }; return new STRUCT(sd, c, attributes); } public ORAData create(Datum d, int sqlType) throws SQLException { if (d == null) return null; Object [] attributes = ((STRUCT) d).getOracleAttributes(); return new Person((NUMBER) attributes[0], (CHAR) attributes[1], (CHAR) attributes[2]); } }
Person.javaを拡張するStudent.java
次のコードは、Person.java
クラスを拡張するStudent.java
クラスを示します。
class Student extends Person { static final Student _studentFactory = new Student (); public NUMBER deptid; public CHAR major; public static ORADataFactory getORADataFactory() { return _studentFactory; } public Student () {} public Student (NUMBER ssn, CHAR name, CHAR address, NUMBER deptid, CHAR major) { super (ssn, name, address); this.deptid = deptid; this.major = major; } public Datum toDatum(OracleConnection c) throws SQLException { StructDescriptor sd = StructDescriptor.createDescriptor("SCOTT.STUDENT_T", c); Object [] attributes = { ssn, name, address, deptid, major }; return new STRUCT(sd, c, attributes); } public CustomDatum create(Datum d, int sqlType) throws SQLException { if (d == null) return null; Object [] attributes = ((STRUCT) d).getOracleAttributes(); return new Student((NUMBER) attributes[0], (CHAR) attributes[1], (CHAR) attributes[2], (NUMBER) attributes[3], (CHAR) attributes[4]); } }
ORAData
インタフェースを実装するカスタマイズされたクラスでは、必ずしもオブジェクト型階層をミラー化する必要はありません。たとえば、スーパークラスを指定せずにStudent
クラスを宣言できます。この場合、Student
には、PERSON_T
から継承された属性およびSTUDENT_T
によって宣言された属性を保持するフィールドが含まれます。
ORADataFactoryの実装
次の例に示すように、JDBCアプリケーションでは、データベースの問合せにファクトリ・クラスを使用して、Person
またはそのサブクラスのインスタンスを戻します。
ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { Object s = rset.getORAData (1, PersonFactory.getORADataFactory()); ... }
ORADataFactory
インタフェースを実装したクラスでは、関連付けられたカスタム・オブジェクト型のインスタンスおよび任意のサブタイプのインスタンス、または少なくともサポートされるすべての型のインスタンスの作成が可能になります。
次の例で、PersonFactory.getORADataFactory
メソッドは、Javaインスタンスperson
、student
またはparttimestudent
を戻すことにより、PERSON_T
オブジェクト、STUDENT_T
オブジェクトおよびPARTTIMESTUDENT_T
オブジェクトを処理できるファクトリを戻します。
class PersonFactory implements ORADataFactory { static final PersonFactory _factory = new PersonFactory (); public static ORADataFactory getORADataFactory() { return _factory; } public ORAData create(Datum d, int sqlType) throws SQLException { STRUCT s = (STRUCT) d; if (s.getSQLTypeName ().equals ("SCOTT.PERSON_T")) return Person.getORADataFactory ().create (d, sqlType); else if (s.getSQLTypeName ().equals ("SCOTT.STUDENT_T")) return Student.getORADataFactory ().create(d, sqlType); else if (s.getSQLTypeName ().equals ("SCOTT.PARTTIMESTUDENT_T")) return ParttimeStudent.getORADataFactory ().create(d, sqlType); else return null; } }
次の例では、次のような表tabl1
があることを想定しています。
CREATE TABLE tabl1 (idx NUMBER, person PERSON_T); INSERT INTO tabl1 VALUES (1, PERSON_T (1000, 'Scott', '100 Oracle Parkway')); INSERT INTO tabl1 VALUES (2, STUDENT_T (1001, 'Peter', '200 Oracle Parkway', 101, 'CS')); INSERT INTO tabl1 VALUES (3, PARTTIMESTUDENT_T (1002, 'David', '300 Oracle Parkway', 102, 'EE'));
java.sql.SQLData
インタフェースを実装するカスタマイズされたクラスを使用すると、データベース・オブジェクト・タイプ階層をミラー化できます。サブクラスのreadSQL
およびwriteSQL
メソッドは、通常、対応するスーパークラスのメソッドをコールして、そのスーパークラスの属性を読取りまたは書込みを行ってから、サブクラス属性の読取りまたは書込みを行います。たとえば、PERSON_T
およびSTUDENT_T
に対するJavaクラスのマッピングは、次のようになります。
SQLDataを使用したPerson.java
次のコードは、SQLData
インタフェースを実装するPerson.java
クラスを示します。
import java.sql.*; public class Person implements SQLData { private String sql_type; public int ssn; public String name; public String address; public Person () {} public String getSQLTypeName() throws SQLException { return sql_type; } public void readSQL(SQLInput stream, String typeName) throws SQLException { sql_type = typeName; ssn = stream.readInt(); name = stream.readString(); address = stream.readString(); } public void writeSQL(SQLOutput stream) throws SQLException { stream.writeInt (ssn); stream.writeString (name); stream.writeString (address); } }
Student.javaを拡張するStudent.java
次のコードは、Person.java
クラスを拡張するStudent.java
クラスを示します。
import java.sql.*; public class Student extends Person { private String sql_type; public int deptid; public String major; public Student () { super(); } public String getSQLTypeName() throws SQLException { return sql_type; } public void readSQL(SQLInput stream, String typeName) throws SQLException { super.readSQL (stream, typeName); // read supertype attributes sql_type = typeName; deptid = stream.readInt(); major = stream.readString(); } public void writeSQL(SQLOutput stream) throws SQLException { super.writeSQL (stream); // write supertype // attributes stream.writeInt (deptid); stream.writeString (major); } }
必須ではありませんが、SQLData
インタフェースを実装するカスタマイズされたクラスでは、データベース・オブジェクト型階層のミラー化をお薦めします。たとえば、スーパークラスを指定せずにStudent
クラスを宣言できます。この場合、Student
には、PERSON_T
から継承された属性およびSTUDENT_T
によって宣言された属性を保持するフィールドが含まれます。
SQLDataを使用したStudent.java
次のコードは、Person.java
クラスを拡張せずに、SQLDataインタフェースを直接実装するStudent.java
クラスを示します。
import java.sql.*; public class Student implements SQLData { private String sql_type; public int ssn; public String name; public String address; public int deptid; public String major; public Student () {} public String getSQLTypeName() throws SQLException { return sql_type; } public void readSQL(SQLInput stream, String typeName) throws SQLException { sql_type = typeName; ssn = stream.readInt(); name = stream.readString(); address = stream.readString(); deptid = stream.readInt(); major = stream.readString(); } public void writeSQL(SQLOutput stream) throws SQLException { stream.writeInt (ssn); stream.writeString (name); stream.writeString (address); stream.writeInt (deptid); stream.writeString (major); } }
一般的なJDBCアプリケーションでは、サブタイプ・オブジェクトは次のいずれかとして戻されます。
問合せ結果
PL/SQL OUT
パラメータ
型属性
サブタイプの取得には、デフォルト・マッピング、SQLData
マッピングまたはORAData
マッピングのいずれかを使用できます。
デフォルト・マッピングの使用
デフォルトで、データベース・オブジェクトは、oracle.sql.STRUCT
クラスのインスタンスとして戻されます。このインスタンスは、宣言された型または宣言された型のサブタイプのオブジェクトを表します。STRUCT
クラスがデータベースのサブタイプ・オブジェクトを表す場合、このクラスにはそのスーパータイプの属性と、サブタイプに定義された属性が含まれます。
Oracle JDBCドライバは、最も固有の型でデータベース・オブジェクトを戻します。JDBCアプリケーションは、STRUCT
クラスのgetSQLTypeName
メソッドを使用して、STRUCT
オブジェクトのSQL型を判断します。次のコードを参照してください。
// tab1.person column can store PERSON_T, STUDENT_T and PARTIMESTUDENT_T objects ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { oracle.sql.STRUCT s = (oracle.sql.STRUCT) rset.getObject(1); if (s != null) System.out.println (s.getSQLTypeName()); // print out the type name which // may be SCOTT.PERSON_T, SCOTT.STUDENT_T or SCOTT.PARTTIMESTUDENT_T }
SQLDataマッピングの使用
SQLData
マッピングの場合、JDBCドライバはSQLData
インタフェースを実装するクラスのインスタンスとして、データベース・オブジェクトを戻します。
データベース・オブジェクトの取得にSQLData
マッピングを使用するには、次の操作を実行します。
目的のオブジェクト型のSQLData
インタフェースを実装するコンテナ・クラスを実装します。
接続型マップに各Oracleオブジェクト型に対応するカスタムJava型を指定するエントリが移入されます。
SQLオブジェクト値へのアクセスには、getObject
メソッドを使用します。
JDBCドライバによって、型マップと一致するエントリがチェックされます。一致するエントリが見つかると、ドライバはSQLData
インタフェースを実装するクラスのインスタンスとしてデータベース・オブジェクトを戻します。
次のコードは、カスタマイズされたSQLDataマッピングの全プロセスを示します。
// The JDBC application developer implements Person.java for PERSON_T, // Student.java for STUDENT_T // and ParttimeStudent.java for PARTTIMESTUDEN_T. Connection conn = ...; // make a JDBC connection // obtains the connection typemap java.util.Map map = conn.getTypeMap (); // populate the type map map.put ("SCOTT.PERSON_T", Class.forName ("Person")); map.put ("SCOTT.STUDENT_T", Class.forName ("Student")); map.put ("SCOTT.PARTTIMESTUDENT_T", Class.forName ("ParttimeStudent")); // tab1.person column can store PERSON_T, STUDENT_T and PARTTIMESTUDENT_T objects ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { // "s" is instance of Person, Student or ParttimeStudent Object s = rset.getObject(1); if (s != null) { if (s instanceof Person) System.out.println ("This is a Person"); else if (s instanceof Student) System.out.println ("This is a Student"); else if (s instanceof ParttimeStudent) System.out.pritnln ("This is a PartimeStudent"); else System.out.println ("Unknown type"); } }
JDBCドライバにより、各コールの接続型マップと次のものが照合されます。
java.sql.ResultSet
およびjava.sql.CallableStatement
インタフェースのgetObject
メソッド
java.sql.Struct
インタフェースのgetAttribute
メソッド
java.sql.Array
インタフェースのgetArray
メソッド
oracle.sql.REF
インタフェースのgetValue
メソッド
ORADataマッピングの使用
ORAData
マッピングの場合、JDBCドライバはORAData
インタフェースを実装するクラスのインスタンスとして、データベース・オブジェクトを戻します。
Oracle JDBCドライバは、Oracleオブジェクト型に対するJavaクラスのマッピングを認識する必要があります。Oracle JDBCドライバにこの情報を通知するには、次のような2つの方法があります。
JDBCアプリケーションは、getORAData(int idx, ORADataFactory f)
メソッドを使用して、データベース・オブジェクトにアクセスします。getORAData
メソッドの2番目のパラメータは、カスタマイズされたクラスを作成するファクトリ・クラスのインスタンスを指定します。getORAData
メソッドは、OracleResultSet
およびOracleCallableStatement
クラスで使用可能です。
JDBCアプリケーションは、接続型マップに各Oracleオブジェクト型に対応するカスタムJava型を指定するエントリを移入します。Oracleオブジェクト値へのアクセスには、getObject
メソッドが使用されます。
2番目の方法では、標準getObject
メソッドが使用されます。次のサンプル・コードは、最初の方法を示します。
// tab1.person column can store both PERSON_T and STUDENT_T objects ResultSet rset = stmt.executeQuery ("select person from tab1"); while (rset.next()) { Object s = rset.getORAData (1, PersonFactory.getORADataFactory()); if (s != null) { if (s instanceof Person) System.out.println ("This is a Person"); else if (s instanceof Student) System.out.println ("This is a Student"); else if (s instanceof ParttimeStudent) System.out.pritnln ("This is a PartimeStudent"); else System.out.println ("Unknown type"); } }
JDBCアプリケーションが、JDBCドライバを持つデータベース・サブタイプ・オブジェクトを作成する場合があります。これらのオブジェクトは、バインド変数としてデータベースに送られるか、JDBCアプリケーション内での情報交換に使用されます。
カスタマイズされたマッピングの場合、JDBCアプリケーションは、開発者が選択した方法に応じて、データベース・サブタイプ・オブジェクトを表すSQLData
またはORAData
ベースのオブジェクトを作成します。デフォルト・マッピングの場合、データベース・サブタイプ・オブジェクトを表すSTRUCT
オブジェクトを作成します。スーパータイプから継承されたすべてのデータ・フィールド、およびサブタイプに定義されたすべてのフィールドに値が必要になります。次のコードを参照してください。
Connection conn = ... // make a JDBC connection StructDescriptor desc = StructDescriptor.createDescriptor ("SCOTT.PARTTIMESTUDENT", conn); Object[] attrs = { new Integer(1234), "Scott", "500 Oracle Parkway", // data fields defined in // PERSON_T new Integer(102), "CS", // data fields defined in // STUDENT_T new Integer(4) // data fields defined in // PARTTIMESTUDENT_T }; STRUCT s = new STRUCT (desc, conn, attrs);
s
は、PERSON_T
とSTUDENT_T
から継承したデータ・フィールドおよびPARTTIMESTUDENT_T
で定義されているデータ・フィールドを使用して初期化されます。
一般的なJDBCアプリケーションでは、データベース・オブジェクトを表すJavaオブジェクトは次のいずれかとしてデータベースに送られます。
データ操作言語(DML)バインド変数
PL/SQL IN
パラメータ
オブジェクト型属性値
Javaオブジェクトは、STRUCT
クラスのインスタンス、またはSQLData
またはORAData
インタフェースを実装するクラスのインスタンスです。Oracle JDBCドライバは、データベースのSQLエンジンが認識できるシリアライズされた形式にJavaオブジェクトを変換します。サブタイプ・オブジェクトは、標準のオブジェクトの場合と同じ方法でバインドされます。
サブタイプ・データ・フィールドにアクセスするためのロジックはカスタマイズされたクラスの一部ですが、デフォルト・マッピングではこのロジックはJDBCアプリケーションそのものに定義されます。データベース・オブジェクトは、oracle.sql.STRUCT
クラスのインスタンスとして戻されます。JDBCアプリケーションは、STRUCT
クラスの次のいずれかのアクセス・メソッドをコールして、データ・フィールドにアクセスする必要があります。
Object[] getAttribute()
oracle.sql.Datum[] getOracleAttribute()
getAttributeメソッドのサブタイプ・データ・フィールド
JDBC 2.0では、java.sql.Struct
インタフェースのgetAttribute
メソッドを使用してオブジェクト・データ・フィールドにアクセスします。このメソッドは、java.lang.Object
配列を戻します。配列の要素はそれぞれ1つのオブジェクト属性を表します。個々の要素型は、JDBC変換マトリックス内の対応する属性型を参照することで確認できます。このマトリックスは、表4-1にリストされています。たとえば、SQL NUMBER
属性はjava.math.BigDecimal
オブジェクトに変換されます。getAttribute
メソッドは、そのオブジェクト型のスーパータイプに定義されたすべてのデータ・フィールドと、そのサブタイプに定義されたデータ・フィールドを戻します。最初にスーパータイプのデータ・フィールドがリストされ、次にサブタイプのデータ・フィールドがリストされます。
getOracleAttributeメソッドのサブタイプ・データ・フィールド
getOracleAttribute
メソッドはOracleの拡張機能メソッドで、getAttribute
メソッドよりも効率的です。getOracleAttribute
メソッドは、データ・フィールドを保持するoracle.sql.Datum
配列を戻します。oracle.sql.Datum
配列の各要素は属性を表します。個々の要素型は、Oracle変換マトリックス内の対応する属性型を参照することで確認できます。このマトリックスは、表4-1にリストされています。たとえば、SQL NUMBER
属性はoracle.sql.NUMBER
オブジェクトに変換されます。getOracleAttribute
メソッドは、そのオブジェクト型のスーパータイプに定義されたすべての属性と、そのサブタイプに定義された属性を戻します。最初にスーパータイプのデータ・フィールドがリストされ、次にサブタイプのデータ・フィールドがリストされます。
次のコードは、getAttribute
メソッドの使用方法を示します。
// tab1.person column can store PERSON_T, STUDENT_T and PARTIMESTUDENT_T objects
ResultSet rset = stmt.executeQuery ("select person from tab1");
while (rset.next())
{
oracle.sql.STRUCT s = (oracle.sql.STRUCT) rset.getObject(1);
if (s != null)
{
String sqlname = s.getSQLTypeName();
Object[] attrs = s.getAttribute();
if (sqlname.equals ("SCOTT.PERSON")
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
}
else if (sqlname.equals ("SCOTT.STUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
}
else if (sqlname.equals ("SCOTT.PARTTIMESTUDENT"))
{
System.out.println ("ssn="+((BigDecimal)attrs[0]).intValue());
System.out.println ("name="+((String)attrs[1]));
System.out.println ("address="+((String)attrs[2]));
System.out.println ("deptid="+((BigDecimal)attrs[3]).intValue());
System.out.println ("major="+((String)attrs[4]));
System.out.println ("numHours="+((BigDecimal)attrs[5]).intValue());
}
else
throw new Exception ("Invalid type name: "+sqlname);
}
}
rset.close ();
stmt.close ();
conn.close ();
Oracle JDBCドライバでは、継承プロパティにアクセスするための一連のメタデータ・メソッドを提供します。継承メタデータ・メソッドは、oracle.sql.StructDescriptor
クラスおよびoracle.jdbc.StructMetaData
クラスに定義されます。
StructMetaData
クラスは、サブタイプ属性の継承メタデータ・メソッドを提供します。StructDescriptor
クラスのgetMetaData
メソッドは、その型のStructMetaData
のインスタンスを戻します。StructMetaData
クラスには、次の継承メタデータ・メソッドが含まれます。
カスタム・オブジェクト・クラスを作成するには、その他のカスタムJavaクラスを作成するときと同様に、Oracle JPublisherユーティリティを使用すると便利です。このユーティリティにより、カスタムJavaクラスの完全なクラス定義が生成されます。このカスタムJavaクラスをインスタンス化することにより、Oracleオブジェクトのデータを保持できます。JPublisherが生成するクラスには、SQLとJavaの間でデータを変換するメソッド、およびオブジェクト属性のgetterメソッドとsetterメソッドが含まれます。
この項には、次の項目が含まれます。
関連項目: 『Oracle Database JPublisherユーザーズ・ガイド』 |
JPublisherを使用して、JPublisher型マッピングの設定に従ったSQLData
インタフェースまたはORAData
インタフェースを実装するカスタム・オブジェクト・クラスを作成できます。
ORAData
インタフェースを使用する場合は、JPublisherによって、Oracleオブジェクト型のオブジェクト参照にマップされるカスタム参照クラスも作成されます。SQLData
インタフェースを使用する場合、Jpublisherによるカスタム参照クラスの作成はありません。かわりに、標準java.sql.Ref
インスタンスを使用します。
機能を追加する場合は、必要に応じてカスタム・オブジェクト・クラスをサブクラス化し、機能を追加します。JPublisherを実行するとき、生成するクラスの名前と実装するサブクラスの名前の両方を指定するコマンドライン・オプションがあります。SQLとJavaのマッピングを正しく機能させるために、JPublisherはサブクラスの名前を必要とします。サブクラス名は、生成されるクラスの機能の一部に組み込まれます。
注意: JPublisherで生成されたクラスをサブクラス化せずに手動で編集する方法はお薦めできません。クラスを手動で編集した後になんらかの理由によってJPublisherを再実行する場合は、変更を実装しなおす必要があります。 |
JPublisherでは、ユーザー定義型とその属性型をSQLとJavaとの間でマップする、様々な方法が用意されています。この項では、SQL型のカテゴリおよび各カテゴリで使用可能なマップ・オプションの一覧を示します。
Jpublisherでは、SQL型が次のグループに分類されます。それぞれのグループでは、対応する次のJPublisherオプションを指定します。
ユーザー定義型(UDT)
Oracleオブジェクト、参照およびコレクションが含まれます。JPublisher -usertypes
オプションを使用して、UDTの型マッピング実装が標準SQLData
実装か、Oracle固有のORAData
実装かを指定します。
数値型
NUMBER
SQL型としてデータベースに格納されるものが含まれます。JPublisher -numbertypes
オプションを使用して、数値型の型マッピングを指定します。
ラージ・オブジェクト(LOB)型
SQL型BLOB
およびCLOB
が含まれます。JPublisher -lobtypes
オプションを使用して、LOB型の型マッピングを指定します。
組込み型
前述のカテゴリに当てはまらないSQL型としてデータベースに格納されるものが含まれます。たとえば、CHAR
、VARCHAR2
、LONG
、RAW
などがあります。JPublisher -builtintypes
オプションを使用して、組込み型の型マッピングを指定します。
JPublisherでは、次の型マッピング・モードが定義されています。このうち2つは、数値型にのみ適用されます。
SQL型とネイティブなJava型間の標準デフォルト・マッピングを使用します。カスタム・オブジェクト・クラスの場合、SQLData
実装を使用します。
対応するoracle.sql
型を使用して、SQL型にマップします。カスタム・オブジェクト・クラス、参照クラスまたはコレクション・クラスの場合、ORAData
実装を使用します。
オブジェクトJDBCマッピング(objectjdbc
を設定)
これは、JDBCマッピングの拡張要素です。オブジェクトJDBCマッピングでは、適切であれば、Javaプリミティブ型(int
、float
、double
など)のかわりに、標準java.lang
パッケージの数値オブジェクト型(java.lang.Integer
、Float
、Double
など)が使用されます。java.lang
型はNULL化可能ですが、プリミティブ型はNULL化できません。
BigDecimal
マッピング(bigdecimal
を設定)
java.math.BigDecimal
を使用して、すべての数値属性をマップします。これは、oracle.sql.NUMBER
クラスにマップせずに、大きな数値を扱う場合に適しています。
注意: BigDecimal マッピングを使用すると、パフォーマンスが大幅に低下することがあります。 |
Oracleオブジェクト型からJavaへのマッピング
JPublisher -usertypes
オプションを使用すると、Oracleオブジェクト型に対応するカスタムJavaクラスを実装する方法が判断されます。
-usertypes=oracle
と設定すると(デフォルト設定)、JPublisherによって、カスタム・オブジェクト・クラスに対するORAData
実装が作成されます。また、対応するカスタム参照クラスのORAData
実装が作成されます。
-usertypes=jdbc
と設定すると、JPublisherによって、カスタム・オブジェクト・クラスに対するSQLData
実装が作成されます。カスタム参照クラスは作成されません。参照型には、java.sql.Ref
またはoracle.sql.REF
を使用する必要があります。
注意: -usertypes=oracle を設定してJPublisherを使用すると、SQLコレクション型をマップするためのORAData 実装を作成することもできます。
|
属性型からJavaへのマッピング
Oracleオブジェクト型の属性型にマッピングを指定しない場合、JPublisherは次のデフォルトを使用します。
数値属性型の場合、デフォルト・マッピングはオブジェクトJDBCです。
LOB属性型の場合、デフォルト・マッピングはOracleです。
組込み型属性の場合、デフォルト・マッピングはJDBCです。
代替マッピングが必要な場合は、必要に応じて、属性型と必要なマッピングに対応する-numbertypes
、-lobtypes
および-builtintypes
オプションを使用します。
属性型自体がOracleオブジェクト型の場合は、-usertypes
の設定に従ってマップされます。
重要: カスタム・オブジェクト・クラスに対してSQLData 実装を指定し、コードを移植可能にする場合は、属性値に対して移植可能なマッピングを使用する必要があることに注意してください。数値型と組込み型のデフォルトは移植可能ですが、LOB型には-lobtypes=jdbc を指定する必要があります。 |
SQL型カテゴリとマッピング設定のサマリー
表13-1に、SQL型のJPublisherカテゴリ、各カテゴリで使用できるマッピング設定およびデフォルト設定を示します。
Oracle JDBCには、構造化オブジェクト型の属性名と型に関する情報を取り出す機能が含まれています。この機能は、概念的には結果セットから列名と型に関する情報を取り出す機能に似ています。実際、ほぼ同一のメソッドを使用します。
この項には、次の項目が含まれます。
oracle.sql.StructDescriptor
クラスには、構造化オブジェクト型に関するメタデータを取り出す機能が含まれています。StructDescriptor
クラスには、結果セット・オブジェクトで使用可能な標準getMetaData
メソッドと同じ機能を持つgetMetaData
メソッドがあります。このメソッドは、属性名や型など、属性情報の集合を戻します。このメソッドをStructDescriptor
オブジェクトでコールして、そのStructDescriptor
オブジェクトによって記述されているOracleオブジェクト型に関するメタデータを取り出します。
StructDescriptor
クラスのgetMetaData
メソッドのシグネチャは、標準ResultSet
インタフェースのgetMetaData
に指定されているシグネチャと同じです。シグネチャは次のとおりです。
ResultSetMetaData getMetaData() throws SQLException
ただし、このメソッドは、実際にはoracle.jdbc.StructMetaData
のインスタンスを戻します。このクラスは、標準java.sql.ResultSetMetaData
インタフェースが結果セット・メタデータのサポートを指定するのと同じ方法で、構造化オブジェクト・メタデータをサポートします。
次のメソッドもStructMetaData
でサポートされます。
String getOracleColumnClassName(int column) throws SQLException
このメソッドは、指定した属性の値を取り出すためにOracleResultSet
クラスのgetOracleObject
メソッドがコールされた場合にインスタンスが作成されるoracle.sql.Datum
サブクラスの完全修飾名を戻します。たとえば、oracle.sql.NUMBER
が戻されます。
getOracleColumnClassName
メソッドを使用するには、getMetaData
メソッドで戻されたResultSetMetaData
オブジェクトをStructMetaData
にキャストする必要があります。
注意: 前述のメソッド・シグネチャのcolumn は、誤解を招く表現です。column の値に4を指定すると、オブジェクトの4番目の属性を指すことになります。 |
次の手順を使用して、構造化オブジェクト型のメタデータを取り出します。
該当する構造化オブジェクト型を記述するStructDescriptor
インスタンスを作成または取り出します。
StructDescriptor
インスタンスのgetMetaData
メソッドをコールします。
適切なメタデータgetterメソッド(getColumnName
、getColumnType
およびgetColumnTypeName
)をコールします。
例
次のメソッドは、構造化オブジェクト型の属性情報を取り出す方法を示します。この例には、StructDescriptor
インスタンスを作成する最初の手順が含まれています。
// // Print out the ADT's attribute names and types // void getAttributeInfo (Connection conn, String type_name) throws SQLException { // get the type descriptor StructDescriptor desc = StructDescriptor.createDescriptor (type_name, conn); // get type metadata ResultSetMetaData md = desc.getMetaData (); // get # of attrs of this type int numAttrs = desc.length (); // temporary buffers String attr_name; int attr_type; String attr_typeName; System.out.println ("Attributes of "+type_name+" :"); for (int i=0; i<numAttrs; i++) { attr_name = md.getColumnName (i+1); attr_type = md.getColumnType (i+1); System.out.println (" index"+(i+1)+" name="+attr_name+" type="+attr_type); // drill down nested object if (attrType == OracleTypes.STRUCT) { attr_typeName = md.getColumnTypeName (i+1); // recursive calls to print out nested object metadata getAttributeInfo (conn, attr_typeName); } } }