目次 | 前の項目 | 次の項目 JDBCTM ガイド: 使用の開始


7 Java オブジェクトの持続性

JDBC 1.0 API では、getObject() および setObject() の機構により、オブジェクトの格納および Java オブジェクトのデータベースからの取得がある程度サポートされていました。新規 JDBC API では、データソースに含まれる Java オブジェクトの情報を取得するための新しいメタデータ機能が追加され、JDBC ドライバで Java オブジェクトの持続性を実装するための機能が全般的に拡張されています。Java クラスのインスタンスは、直列化された Java オブジェクトとして、またはその他のベンダー独自の形式でデータベースに格納できます。オブジェクトの直列化を使用した場合は、オブジェクト間の参照を Java オブジェクト直列化で規定された規則に従って扱うことができます。

この章で説明している新規 JDBC API の機能は、「Java リレーショナル DBMS」と呼ばれる新型の Java 対応データベース管理システムをサポートすることを目的としたものです。Java リレーショナル DBMS では、Java オブジェクト型が使用できるように型を扱う方法が拡張されており、Java オブジェクト型を参照するクエリーを記述できるようになっています。現在、何社かのデータベースベンダーが、Java リレーショナル機能に対応した製品を開発中です。この章で説明している機構は必須の機構ではありません。したがって、この章で説明している機能をサポートしない JDBC ドライバでは、それを実装する必要はありません。

以降、JDBC API を使用して Java オブジェクトの格納と取得を行う、Java 言語で記述された典型的なアプリケーション (Java アプリケーション) を見ていきます。

7.1     Java オブジェクトの取得

下の例では、JDBC API を使用してオブジェクトを取得する方法を示しています。クエリーの行では、Employee という Java クラスのインスタンスが格納された Employee という列を持つ PERSONNEL テーブルを参照しています。列名と Java クラス名がどちらも Employee と同じになっていますが、JDBC API の仕様で同じであることが要求されているわけではありません。実際、現時点では、Java の型を参照する SQL クエリーに関して、合意された標準的な構文は存在しないため、JDBC API では特定のクエリー構文の使用を求めてはいません。

ResultSet rs = stmt.executeQuery(
	"SELECT Employee FROM PERSONNEL");
rs.next();
Employee emp = (Employee)rs.getObject(1);

この例では、PERSONNEL テーブルから Employee のすべてのインスタンスが選択されます。ResultSet.next() メソッドは、Employee が含まれる最初の行に移動するために呼び出されます。次に、ResultSet.getObject() を使用して Employee のインスタンスを取得しています。これを受けて、JDBC ドライバは、可能であれば直列化されたオブジェクトのインスタンスを直列化復元するという方法で、Employee クラスのインスタンスを生成し、それを java.lang.Object として返します。 最後に、このコードでは、返されたインスタンスを Employee にナロー変換しています。

この例では、JDBC API で規定されていない形式の拡張 SQL クエリー構文を使用している点を除き、JDBC 1.0 API にない機能は使用していません。なお、この JDBC ベースのコードで、Java クラスにマッピングされた SQL のユーザ定義型のデータを取得することも可能です。具体的な方法については、あとの章で説明します。

7.2     Java オブジェクトの格納

次の例では、Java オブジェクトを更新し、JDBC 技術を使用して、更新された持続性オブジェクトのコピーを作成する方法を示しています。

emp.setSalary(emp.getSalary() * 1.5);
PreparedStatement pstmt = con.preparedStatement(
"UPDATE PERSONNEL SET Employee = ? WHERE Employee.no = 1001");
pstmt.setObject(1, emp);
pstmt.executeUpdate();


この例では、社員の給与額を 50% 上げています。まず、Employee.setSalary() メソッドを使用して社員の給与額を更新します。Employee クラスに対するメソッドのセマンティクスは、JDBC API では規定されていません。ここでは、Employee クラスを通常の Java クラスと仮定しているので、Employee.setSalary() では、Employee のインスタンスに含まれる private データフィールドの値を変更するだけです。この例では、Employee.setSalary() を呼び出してもデータベースは更新されませんが、Employee クラスを使用するアプリケーションから透過的にデータベースを更新するという形で、Employee.setSalary() を呼び出すとデータベースも更新されるような実装も可能です。

次に、拡張された SQL UPDATE コマンドを使用して PreparedStatement オブジェクトを作成しています。 なお、この例で使用しているクエリー構文も JDBC API で規定されているわけではありません。この UPDATE コマンドでは、PERSONNEL テーブル中の指定した行について、Employee 列の内容を変更しています。PreparedStatement.setObject() は、Employee オブジェクトを preparedStatement に渡すために使用しています。 最後に、executeUpdate() メソッドでデータベースに格納されている Employee の値を更新しています。

なお、この例でも JDBC 1.0 API にない構文は使用していません。また、Employee クラスが SQL のユーザ定義型にマッピングされている場合も、これと同じコードが使用できます。

7.3     メタデータの追加

新しい JDBC API には、新しくメタデータという機能が追加されています。 メタデータを使用することで、データソースに格納されている Java オブジェクトの完全な情報を取得できます。

7.3.1 Java オブジェクトの識別

Java オブジェクト型を表すため、java.sql.Types には JAVA_OBJECT という新しい型コードが追加されています。型コード JAVA_OBJECT は、DatabaseMetaData.getTypeInfo()DatabaseMetaData.getColumns() などのメソッドにより返されます。たとえば、Java クラスを表すことができる型を DBMS がサポートしている場合、DatabaseMetaData.getTypeInfo() は、次のエントリが含まれる結果セットを返します。

  1. TYPE_NAME String => データソース固有の名前 (NULL も可)
  2. DATA_TYPE short => java.sql.Types.JAVA_OBJECT
  3. etc.

TYPE_NAME 列には、「JavaObject」や「Serialized」など、当該 Java オブジェクトを表すデータソース固有の名前が含まれます。 TYPE_NAME は NULL であってもかまいません。

7.3.2 スキーマ固有の Java 型の情報の取得

Java クラスは、スキーマのテーブル定義で使用する前に、特定のデータベーススキーマに登録するのが普通です。スキーマ固有のユーザ定義型 (JAVA_OBJECT など) に関する情報は、DatabaseMetaData.getUDTs() メソッドで取得できます。次に例を示します。

int[] types = {Types.JAVA_OBJECT};
ResultSet rs = dmd.getUDTs("catalog-name", "schema-name",
	"%", types);

このコードでは、catalog-name.schema-name スキーマで定義されているすべての Java オブジェクト型の情報が返されます。ドライバが UDT をサポートしていない場合や、一致する UDT が見つからない場合は、空の結果セットが返されます。

それぞれの型の情報は、次の列で構成されます。

TYPE_CATString => 型のカタログ (NULL も可)
TYPE_SCHEMString => 型のスキーマ (NULL も可)
TYPE_NAMEString => データベースの型名
JAVA_CLASS String => Java クラス名
DATA_TYPEshort => java.sql.Types で定義されている値 (JAVA_OBJECT など)
REMARKSString => 型に関する説明

TYPE_CATTYPE_SCHEMDATA_TYPEREMARKS の各列については説明しません。TYPE_NAME は、実際は SQL の型名です。これは、CREATE TABLE 文で、この型の列を指定するために使用する名前です。

DATA_TYPEJAVA_OBJECT の場合、JAVA_CLASS は、TYPE_NAME に対応する Java クラスの完全指定 Java クラス名になります。TYPE_NAME 列に実際に格納されている値はすべて、このクラス、またはこのクラスのサブクラスになります。このクラス、またはそのサブクラスのインスタンスは、JDBC 技術を使用するアプリケーションが TYPE_NAME 列から値を取り出したときに、JDBC ドライバによって作成されます。

DatabaseMetaData.getUDTs() メソッドの第 3 パラメータにも完全指定の SQL 名を指定できます。この場合は、カタログパラメータとスキーマパターンパラメータは無視されます。完全指定の SQL 名には、ワイルドカードを含めることができます。たとえば、次のコードは前のコードと同等です。

int[] types = {Types.JAVA_OBJECT};
ResultSet rs = dmd.getUDTs(null, null,
	"catalog-name.schema-name.%", types);

このコードでは、完全指定名の要素間の区切りに「.」文字を使用しています。完全指定名の形式はデータベースシステムによって異なるので、この例のように完全指定名をハードコードするのは、通常は避けるべきです。DatabaseMetaData インタフェースを使用すると、特定の JDBC ドライバがサポートしている完全指定名の形式についての情報を得ることができます。

7.3.3 Java クラスオブジェクトの取得

JDBC API では、データベースに格納された Java オブジェクトに対応する Java クラスファイルのロードに関しては、特に何もサポートしていません。データベースに格納されたオブジェクトに対応するクラスオブジェクトは、Class.forName() を呼び出し、パラメータとしてクラス名を引き渡すことにより取得できます。つまり、JDBC API では、データベースに格納されたオブジェクトのバイトコードは、Java 言語の通常の機構によりロードすることを前提としています。



目次 | 前の項目 | 次の項目
jdbc@eng.sun.com または jdbc-business@eng.sun.com
Copyright © 1996-1999 Sun Microsystems, Inc. All rights reserved.