![]() |
![]() |
|
|
| |
dbKona の使い方
以下の節では、Java アプリケーションとの高レベルなデータベース接続を提供する dbKona クラスについて説明します。
dbKona の概要
dbKona クラスには、Java アプリケーションやアプレットにデータベースへのアクセスを提供する、一連の高レベルなデータベース接続オブジェクトが用意されています。dbKona は、JDBC API の最上位に位置し、WebLogic JDBC ドライバなどの JDBC 準拠ドライバと共に機能します。
dbKona クラスには、データ管理に関する低レベルの詳細を扱う JDBC よりも高レベルな抽象化概念が備えられています。dbKona クラスから提供されるオブジェクトを使用することで、プログラマは、ベンダに依存しない、高レベルな方法でデータベース データを表示および変更できるようになります。dbKona オブジェクトを使用する Java アプリケーションでは、データベースに対してデータの検索、挿入、変更、削除などを行うにあたって、DBMS のテーブル構造やフィールド タイプに関するベンダ固有の知識は不要です。
多層コンフィグレーションでの dbKona
また、dbKona は、WebLogic Server および多層ドライバで構成される多層 JDBC 実装でも使用できます。このコンフィグレーションでは、クライアントサイド ライブラリは不要です。多層コンフィグレーションでは、WebLogic JDBC は、WebLogic 多層フレームワークへのアクセス メソッドとして機能します。WebLogic では、WebLogic jDriver for Oracle などの単一の JDBC ドライバを使用して、WebLogic Server から DBMS への通信を行います。
dbKona は、多層環境でデータベース アクセス プログラムを作成する場合によく使用されます。dbKona オブジェクトを使用すれば、ベンダにまったく依存しないデータベース アプリケーションを作成できるからです。dbKona および WebLogic の多層フレームワークは、ユーザに意識させずに、複数の異種データベースからデータを取り出すようなアプリケーションに特に適しています。
WebLogic と WebLogic JDBC サーバの詳細については、『WebLogic JDBC プログラミング ガイド』を参照してください。
dbKona と JDBC ドライバの相互作用
dbKona は、DBMS への接続とその維持を JDBC ドライバに依存しています。dbKona を使用するには、JDBC ドライバをインストールする必要があります。
JavaSoft の JDBC は、BEA が jDriver JDBC ドライバを作成するために実装した一連のインタフェースです。BEA の JDBC ドライバは、Oracle、Informix、および Microsoft SQL Server 用のデータベース固有のドライバの JDBC 実装です。dbKona でデータベース固有のドライバを使用すると、パフォーマンスが向上するだけでなく、プログラマは各データベースのすべての機能にアクセスできます。
dbKona の基礎部分ではデータベース トランザクション用に JDBC が使用されていますが、dbKona を使用することによって、データベースへのより高レベルで便利なアクセスが可能になります。
dbKona と WebLogic Event の相互作用
dbKona パッケージには、ローカルまたは DBMS 内でデータが更新されるときに、WebLogic Event を使用してイベントを(WebLogic 内で)送受信する「eventful」クラスが含まれています。
dbKona アーキテクチャ
dbKona では、データベースに存在するデータの記述および操作に、高レベルな抽象化概念が使用されます。dbKona のクラスは、データを検索および変更するオブジェクトの作成と管理を行います。特定のベンダのデータ保存方法や処理方法に関する知識がなくても、アプリケーションでは一貫性のある方法で dbKona オブジェクトを使用できます。
dbKona アーキテクチャの中心的な概念は、DataSet
です。DataSet
には、クエリの結果が含まれます。DataSet
を使用すると、クライアントサイドでクエリ結果を管理できます。プログラマはレコードを 1 つずつ処理するのではなく、クエリ結果全体を制御できます。
DataSet
には Record
オブジェクトが含まれています。さらに各 Record
オブジェクトには 1 つまたは複数の Value
オブジェクトが含まれています。Record
は、データベースの行に相当し、Value
はデータベースのセルに相当します。Value
オブジェクトは、DBMS に格納される場合の自身の内部データ型を「知っています」。しかし、プログラマはベンダ固有の内部データ型を気にせずに、一貫性のある方法で Value
オブジェクトを使用できます。
DataSet
クラス(およびそのサブクラス TableDataSet
と QueryDataSet
)のメソッドを使用すると、高レベルで柔軟な方法でクエリ結果を自在に操作できます。TableDataSet
の変更内容は、DBMS に保存できます。この場合、dbKona では変更したレコードについての情報が保持され、選択的に保存されます。これにより、ネットワーク トラフィックおよび DBMS のオーバーヘッドが減少します。
また dbKona では、プログラマがベンダ固有の SQL を気にする必要のない、SelectStmt
や KeyDef
などのオブジェクトも使用できます。これらのクラスのメソッドを使用すると、dbKona によって適切な SQL が作成されます。ベンダ固有の SQL についての知識が不要な上、構文エラーも減少します。その一方で、dbKona では、プログラマは必要に応じて SQL を DBMS に渡すことができます。
dbKona API
以下の節では、dbKona API について説明します。
dbKona API リファレンス
weblogic.db.jdbc パッケージ
weblogic.db.jdbc.oracle パッケージ(Oracle 向け拡張)
Class java.lang.Object
Class weblogic.db.jdbc.Column
(implements weblogic.common.internal.Serializable)
Class weblogic.db.jdbc.DataSet
(implements weblogic.common.internal.Serializable)
Class weblogic.db.jdbc.QueryDataSet
Class weblogic.db.jdbc.TableDataSet
Class weblogic.db.jdbc.EventfulTableDataSet
(implements weblogic.event.actions.ActionDef)
Class weblogic.db.jdbc.Enums
Class weblogic.db.jdbc.KeyDef
Class weblogic.db.jdbc.Record
Class weblogic.db.jdbc.EventfulRecord
(implements weblogic.common.internal.Serializable)
Class weblogic.db.jdbc.Schema
(implements weblogic.common.internal.Serializable)
Class weblogic.db.jdbc.SelectStmt
Class weblogic.db.jdbc.oracle.Sequence
Class java.lang.Throwable
Class java.lang.Exception
Class weblogic.db.jdbc.DataSetException
Class weblogic.db.jdbc.Value
dbKona オブジェクトとそれらのクラス
dbKona のオブジェクトは、以下の 3 つのカテゴリに分けられます。
TableDataSet
オブジェクトや、Record
オブジェクトは、データ コンテナ オブジェクトの例です。
Schema
オブジェクトや、SelectStmt
オブジェクトは、このデータ記述オブジェクトの例です。
オブジェクトのこのような大きなカテゴリは、アプリケーションのビルドにおいて相互に依存し合っています。通常は、どのデータ オブジェクトにも、一連の記述オブジェクトが関連付けられています。
dbKona のデータ コンテナ オブジェクト
データ コンテナとして機能する基本的なオブジェクトには 3 種類あります。DataSet、Record、および Value の各オブジェクトです。DataSet
(またはそのサブクラスである QueryDataSet
あるいは TableDataSet
)オブジェクトには Record
オブジェクトが含まれ、Record
オブジェクトには Value
オブジェクトが含まれます。
DataSet
dbKona パッケージでは DataSet
の概念を使用して、DBMS サーバから取り出されたレコードをキャッシュできます。この概念は、SQL におけるテーブルとほぼ同じです。DataSet
クラスには 2 つのサブクラス、QueryDataSet
と TableDataSet
があります。
WebLogic Server を使用する多層モデルでは、DataSet を WebLogic Server に保存(キャッシュ)できます。
DataSet
は、クエリまたはストアド プロシージャの結果を保持する QueryDataSet
または TableDataSet
として作成されます。
DataSet
の検索パラメータは、SQL 文、または dbKona の SQL 文用の抽象オブジェクトである SelectStmt
オブジェクトによって定義されます。
DataSet
には、Value
オブジェクトを含む Record
オブジェクトが含まれます。Record
には、インデックス位置(0 が起点)を指定してアクセスします。
DataSet
は、Schema
によって記述され、Schema にバインドされます。Schema には、DataSet
に表示される各データベース カラムの名前、データ型、サイズ、順番などの属性情報が格納されます。Schema
内のカラム名には、インデックス位置(1 が起点)を指定してアクセスします。
DataSet
クラス(weblogic.db.jdbc.DataSet
を参照)は、QueryDataSet
および TableDataSet
の抽象的な親クラスです。
QueryDataSet
QueryDataSet
を使用すると、SQL クエリの結果を、インデックス位置(0 が起点)を指定してアクセスする Record のコレクションとして使用できます。TableDataSet
とは異なり、QueryDataSet
に対して変更および追加した内容はデータベースに保存できません。
QueryDataSet
と TableDataSet
には、機能的な違いが 2 つあります。1 番目の相違点は、TableDataSet
の変更内容はデータベースに保存できるという点です。QueryDataSet
の Record も変更できますが、その変更内容は保存できません。2 番目の相違点は、QueryDataSet
には、複数のテーブルからのデータを取り出せるという点です。
QueryDataSet
は、java.sql.Connection のコンテキスト内で、または java.sql.ResultSet
を使用して作成されます。つまり、Connection オブジェクトを引数として QueryDataSet
コンストラクタに渡します。QueryDataSet
のデータ検索は、SQL クエリや SelectStmt
オブジェクトによって指定されます。
QueryDataSet
には、Record オブジェクト(0 が起点のインデックスを指定してアクセスする)が含まれます。Record オブジェクトには Value オブジェクト(1 が起点のインデックスを指定してアクセスする)が含まれます。
QueryDataSet
は、Schema によって記述されます。Schema には、QueryDataSet
の属性に関する情報が格納されます。属性には、QueryDataSet
に表示される各データベース カラムの名前、データ型、サイズ、順番などがあります。
QueryDataSet
クラス(weblogic.db.jdbc.QueryDataSet
を参照)には、QueryDataSet を作成、保存、および検索するためのメソッドがあります。QueryDataSet
には、結合用の SQL など、任意の SQL を指定できます。そのスーパークラスである DataSet には、レコード キャッシュの詳細を管理するためのメソッドが含まれています。
TableDataSet
TableDataSet
と QueryDataSet
の機能的な違いは、TableDataSet
の変更内容はデータベースに保存できるという点です。TableDataSet
を使用すると、Record
の値の更新、新しい Record
の追加、および Record
への削除のマーク付けができます。TableDataSet
全体を保存する場合は TableDataSet
クラスの save()
メソッドを使用し、1 つのレコードを保存する場合は Record
クラスの save() メソッドを使用して、最終的に変更内容をデータベースに保存できます。さらに、TableDataSet
に取り出されるデータは、定義上、単一のデータベース テーブルからのデータです。複数のデータベース テーブルを結合して TableDataSet
にデータを取り出すことはできません。
更新情報または削除情報をデータベースに保存するには、KeyDef
オブジェクトを使用して TableDataSet
を作成する必要があります。KeyDef オブジェクトは、UPDATE
文または DELETE
文に WHERE
句を作成するためのユニークなキーを指定します。挿入の操作には WHERE
句は必要ないので、挿入だけを行う場合は、KeyDef
オブジェクトは不要です。KeyDef
のキーには、DBMS
によって入力または変更されるカラムが含まれないようにしてください。dbKona では、正しい WHERE
句を作成するためにキー カラムの値を把握しておく必要があるからです。
また、SQL 文の末尾を構成する任意の文字列で TableDataSet
を限定することもできます。Oracle データベースで dbKona を使用している場合、たとえば「for
UPDATE
」などの文字列で TableDataSet
を限定すると、クエリによって検索されるレコードをロックできます。
TableDataSet
は、KeyDef
を使用して作成できます。KeyDef は dbKona のオブジェクトであり、DBMS に更新情報および削除情報を保存するためのユニークなキーを設定する場合に使用されます。Oracle データベースを使用している場合は、TableDataSet
の KeyDef
を「ROWID
」に設定できます。「ROWID」は、各テーブルのユニークなキーです。その後、「ROWID
」を含む一連の属性を使用して、TableDataSet を作成します。
TableDataSet
は、java.sql.Connection
のコンテキスト内で作成されます。つまり、Connection
オブジェクトを引数として TableDataSet
コンストラクタに渡します。そのデータ検索は、DBMS テーブルの名前によって指定されます。更新情報および削除情報を保存する場合は、TableDataSet
の作成時に KeyDef
オブジェクトを指定する必要があります。TableDataSet
を作成した後で、where()
メソッドおよび order()
メソッドを使用してクエリを修正し、WHERE
句および ORDER BY
句を設定することもできます。
TableDataSet
には、関連付けられているデフォルトの SelectStmt
オブジェクトがあります。このオブジェクトは、サンプルを使用したクエリ機能を利用する場合に使用されます。
QueryDataSet
には、Record
オブジェクト(0 が起点のインデックスを指定してアクセスする)が含まれます。Record オブジェクトには Value オブジェクト(1 が起点のインデックスを指定してアクセスする)が含まれます。
TableDataSet
の属性は、Schema
によって記述されます。Schema には、TableDataSet
に表示されるデータベース カラムの名前、データ型、サイズ、順番などの TableDataSet
の属性情報が格納されます。
TableDataSet
は、WebLogic JDBC サーバにキャッシュできます。
setRefreshOnSave()
メソッドは、保存中に挿入または更新されたレコードもすぐに DBMS から更新されるように、TableDataSet
を設定します。TableDataSet
に DBMS によって変更されたカラム(Microsoft SQL Server の IDENTITY カラムや挿入または更新がきっかけとなって変更されたカラムなど)がある場合は、このフラグを設定します。
Refresh()
メソッドは、データベースに保存された TableDataSet
内のレコード、つまり TableDataSet
で変更したレコードを更新します。レコードの変更内容は失われ、レコードには更新済みのマークが付きます。削除のマークが付けられたレコードは、更新されません。TableDataSet
に追加されたレコードの場合は、更新元の DBMS の行が存在しないことを示す例外が生成されます。
saveWithoutStatusUpdate()
メソッドは、TableDataSet
内のレコードの保存状態を更新せずに DBMS に TableDataSet
レコードを保存します。トランザクション内で TableDataSet
レコードを保存する場合には、このメソッドを使用します。トランザクションがロールバックされても、TableDataSet
内のレコードはデータベースと一致しており、トランザクションを再試行できます。トランザクションのコミット後、updateStatus()
を呼び出して TableDataSet
内のレコードの保存状態を更新します。一度、saveWithoutStatusUpdate()
を使用してレコードを保存すると、そのレコードに対して updateStatus()
を呼び出すまでレコードは変更できません。
TableDataSet.setOptimisticLockingCol()
メソッドを使用すると、TableDataSet
の 1 つのカラムをオプティミスティック ロックのカラムとして指定できます。このカラムをアプリケーションで使用すると、データベースから読み込んでから他のユーザがその行を変更したかどうかを検出できます。dbKona では、行が変更されるたびに DBMS によってカラムが更新されるようになっているので、TableDataSet
の値によってこのカラムが更新されることはありません。dbKona では、レコードまたは TableDataSet
を保存するときに UPDATE
文の WHERE
句でこのカラムが使用されます。別のユーザがそのレコードを変更した場合は、dbKona による更新は失敗します。この場合、Record.refresh()
を使用してそのレコードの新しい値を取り出し、レコードに変更を加えてから、再度保存を試みることができます。
TableDataSet
クラス(weblogic.db.jdbc.TableDataSet
を参照)には、次のメソッドがあります。
TableDataSet
を作成するためのメソッド
WHERE
句および ORDER BY
句を設定するためのメソッド
KeyDef
を取得するためのメソッド
ResultSet
を取得するためのメソッド
SelectStmt
を取得するためのメソッド
そのスーパークラスである DataSet
には、レコード キャッシュを管理するためのメソッドが含まれています。
EventfulTableDataSet(非推奨)
WebLogic 内部で使用するための EventfulTableDataSet
は、データがローカルまたは DBMS で更新されたときに、イベントを送信および受信する TableDataSet
です。EventfulTableDataSet
は、WebLogic Event のすべての Action
クラスによって実装されるインタフェースである weblogic.event.actions.ActionDef
を実装しています。EventfulTableDataSet
の action()
メソッドは、DBMS を更新し、同じ DBMS テーブルに関する他のすべての EventfulTableDataSet
にその変更を通知します(WebLogic Event(非推奨)に関する詳細については、ホワイトペーパーおよび WebLogic Events の開発者ガイドを参照してください)。
EventfulTableDataSet
の EventfulRecord
が変更されると、WebLogic Server に ParamSet
を持つ EventMessage
が送信されます。ParamSet には、変更されたデータと行が含まれます。このとき、そのトピックは、WEBLOGIC.[tablename] になります。ここで tablename には EventfulTableDataSet
に関連付けられたテーブルの名前が入ります。EventfulTableDataSet
は、受信し、評価されたイベントに基づいて動作し、変更されたレコードの独自のコピーを更新します。
EventfulTableDataSet
は、java.sql.Connection オブジェクトのコンテキスト内で作成されます(Connection オブジェクトを引数としてコンストラクタに渡します)。また、t3 Client オブジェクト、挿入、更新、削除に使用される KeyDef
オブジェクト、および DBMS のテーブル名も指定する必要があります。
TableDataSet
と同様、EventfulTableDataSet
には、関連付けられているデフォルトの SelectStmt
オブジェクトがあります。このオブジェクトは、サンプルを使用したクエリ機能を利用する場合に使用されます。
EventfulTableDataSet
には、EventfulRecord
オブジェクト(0 が起点のインデックスを指定してアクセスする)が含まれます。Record
オブジェクトのように、EventfulRecord
オブジェクトには、Value オブジェクト(1 が起点のインデックスを指定してアクセスする)が含まれます。
EventfulTableDataSet
の属性は、Schema によって TableDataSet
と同じ方法で記述されます。
たとえば、EventfulTableDataSet
は、数多くのテーブル ビューを自動的に更新する、倉庫の在庫システムなどで使用されます。ここではその動作について説明します。各倉庫の従業員のクライアント アプリケーションが、「stock」テーブルから EventfulTableDataSet
を作成し、そのレコードを Java アプリケーションに表示します。別の仕事をしている従業員は別の表示を見ていますが、すべてのクライアント アプリケーションでは、「stock」テーブルの同じ EventfulTableDataSet
が使用されています。TableDataSet
が「イベントフル」であるため、データ セット内の各レコードは自動的にそれ自身に対する関心を登録済みです。WebLogic のトピック ツリーには、すべてのレコードへの関心が登録されています。そこには、クライアントごとの、TableDataSet
の各レコードに対する関心の登録があります。
ユーザがレコードを変更すると、DBMS は新しいレコードにより更新されます。同時に、EventMessage
(変更された Record
自身が埋め込まれています)が自動的に WebLogic Server に送信されます。「Stock」テーブルの EventfulTableDataSet
を使用している各クライアントは、変更された Record が埋め込まれたイベント通知を受信します。各クライアントの EventfulTableDataSet
は、変更された Record を受け入れて GUI を更新します。
Record
Record
オブジェクトは、DataSet
の一部として作成されます。Record
オブジェクトは、DataSet
およびその Schema
のコンテキスト内で、またはアクティブな Database
セッションに知られている SQL テーブルの Schema
のコンテキスト内で、手動で作成することもできます。
TableDataSet
内の Record は、Record
クラスの save()
メソッドを使用すれば個別に、または TableDataSet
クラスの save()
メソッドを使用すれば一括してデータベースに保存できます。
Record
は、DataSet
が作成され、そのクエリが実行されたときに作成されます。また、Record
は、(DataSet
の fetchRecords()
メソッドが呼び出されて、その Schema
が取得された後で)DataSet.addRecord()
メソッドまたは Record
コンストラクタを使用して既存の DataSet
に追加することもできます。
Record
には、Value
のコレクションが含まれています。Record
には、0 が起点のインデックス位置を指定してアクセスします。Record
内の Value
には、1 が起点のインデックス位置を指定してアクセスします。
Record
は、その親の DataSet
の Schema
によって記述されます。Record
に関連付けられた Schema
には、Record
内の各フィールドの名前、データ型、サイズ、および順番などに関する情報が格納されます。
Record
クラス(weblogic.db.jdbc.Record
を参照)には、次のメソッドがあります。
Record
オブジェクトを作成するためのメソッド
DataSet
および Schama
を確認するためのメソッド
Record
の保存または更新に使用する SQL 文字列を確認するためのメソッド
Value
の取得と設定を行うためのメソッド
Value
Value
オブジェクトには、親の DataSet
の Schema
によって定義される内部データ型があります。Value
オブジェクトには、有効な割り当てであればその内部データ型以外のデータ型の値を割り当てることができます。また、Value
オブジェクトには、有効なリクエストであればその内部データ型以外のデータ型の値を返すこともできます。
Value
オブジェクトでは、アプリケーションでベンダ固有のデータ型を操作しなくてもいいようになっています。Value
オブジェクトはそのデータ型を「知っています」が、すべての Value
オブジェクトはその内部データ型に関係なく同じメソッドを使用して Java アプリケーション内で操作できます。
これらのデータ型は、java.sql.Types
に表示されている JDBC のタイプに対応しています。
Value
オブジェクトは、親の DataSet
に関連付けられた Schema
によって記述されます。
Value
クラス(weblogic.db.jdbc.Value
を参照)には、Value
オブジェクトのデータおよびデータ型を取得および設定するためのメソッドがあります。
dbKona のデータ記述オブジェクト
データ記述オブジェクトには、メタデータが含まれます。メタデータとは、データ構造、DBMS へのデータの格納方法や DBMS からのデータの取り出し方法、データの更新方法などに関する情報のことです。dbKona で使用されるデータ記述オブジェクトの中には、JDBC インタフェースの実装であるオブジェクトもあります。ここでは、以下のデータ記述オブジェクトの概要とその使用法について説明します。
Schema
DataSet
をインスタンス化すると、それを記述する Schema
が暗黙に作成されます。そしてその Record
を取り出すと、その Schema
が更新されます。
Schema
は、DataSet
がインスタンス化されるときに自動的に作成されます。
DataSet
の属性(つまり、QueryDataSets
と TableDataSets
、およびそれらに関連付けられた Record の属性)は、Table
の属性のように Schema
によって定義されます。
Column
オブジェクトのコレクションとして記述されます。
Schema
クラス(weblogic.db.jdbc.Schema
を参照)には、次のメソッドがあります。
Schema
に関連付けられた Column
を追加したり返したりするためのメソッド
Schema
内のカラム数を確認するためのメソッド
Schema
内の特定のカラム名のインデックス位置(1 が起点)を確認するためのメソッド
Column
Schema
が作成されます。
Column
クラス(weblogic.db.jdbc.Column
を参照)には、次のメソッドがあります。
Column
を特定のデータ型に設定するためのメソッド
Column
のデータ型を確認するためのメソッド
Column
のデータベース固有のデータ型を確認するためのメソッド
Column
の名前、スケール、精度、およびストレージの長さを確認するためのメソッド
Column
が読み込み専用や検索可能になっているかどうかを確認するためのメソッド
KeyDef
"特定のデータベース レコードをユニークなものとして識別し操作するための「WHERE attribute1 = value1
and attribute2 = value2
」などのパターンです。KeyDef
の属性は、データベース テーブルのユニークなキーに対応させる必要があります。
属性のない KeyDef
オブジェクトは、KeyDef
クラスで作成されます。addAttrib()
メソッドを使用して、KeyDef
の属性を作成してから、KeyDef
を TableDataSet
用のコンストラクタで引数として使用します。KeyDef
は、一度 DataSet
に関連付けられると属性を追加することはできません。
Oracle データベースを使用している場合、属性「ROWID」を追加できます。「ROWID
」は、各テーブルに関連付けられた本質的にユニークなキーであり、TableDataSet
を使用した挿入および削除に使用されます。
KeyDef
クラス(weblogic.db.jdbc.KeyDef
を参照)には、次のメソッドがあります。
SelectStmt
SelectStmt
オブジェクトは、SelectStmt
クラスで作成されます。その後、SelectStmt
クラスのメソッドを使用して SelectStmt
に句を追加し、その結果の SelectStmt
オブジェクトを QueryDataSet
を作成するときの引数として使用します。TableDataSet
には、関連付けられたデフォルトの SelectStmt
オブジェクトがあります。このオブジェクトを使用すると、TableDataSet
が作成された後でデータ検索の精度を向上させることができます。
SelectStmt
クラス(weblogic.db.jdbc.SelectStmt を参照)のメソッドは、SQL 文の次の句に対応しています。
また、サンプルを使用したクエリの句の設定および追加もサポートされています。from()
メソッドでは、エリアスを含む文字列を「<i>tableName alias</i>
」という形式で指定できます。field()
メソッドでは、「<i>tableAlias.attribute</i>
」という形式の文字列を引数として使用できます。テーブルの結合が役立つかどうかは使用法によりますが、SelectStmt
オブジェクトを作成する場合には複数のテーブル名を使用できます。QueryDataSet
に関連付けられた SelectStmt
オブジェクトでは 1 つまたは複数のテーブルを結合できますが、TableDataSet
に関連付けられた SelectStmt オブジェクトではこれができません。定義上、使用できるのが 1 つのテーブルのデータに制限されているからです。
dbKona のその他オブジェクト
dbKona のその他オブジェクトには、例外、定数などがあります。
例外
通常、DataSetException
は、DataSet
にストアド プロシージャによるエラーなどの問題がある場合や、内部 IO エラーがある場合などに発生します。
SQL 文の作成または DBMS サーバでの SQL 文の実行に問題がある場合は、java.sql.SqlException
が送出されます。
定数
Enums
クラスには、以下の項目用の定数が含まれます。
java.sql.Types
クラスには、データ型用の定数が含まれています。
エンティティの関係図
継承関係図
以下に、dbKona クラス間の重要な継承関係を示します。1 つのクラスがサブクラス化されています。
DataSet
DataSet
は、QueryDataSet
および TableDataSet
の抽象的な基本クラスです。
その他の dbKona オブジェクトは DbObject
を継承します。
DataSetException
や LicenseException
などのほとんどの dbKona Exceptions
は、java.lang.Exception
および weblogic.db.jdbc.DataSetException
のサブクラスです。LicenseException は RuntimeException
のサブクラスです。
所有関係図
各 dbKona オブジェクトには、その構造をさらに詳しく定義する、関連付けられたその他のオブジェクトがある場合もあります。その関係を次に示します。
DataSet
DataSet
には、Record オブジェクトがあり、各 Record オブジェクトには Value オブジェクトがあります。また、DataSet
には、その構造を定義する Schema があり、これは 1 つまたは複数の Column で作成されています。さらに、DataSet
には、データ検索用のパラメータを設定する SelectStmt
がある場合もあります。
TableDataSet
TableDataSet
には、キーによって更新および削除を行うための KeyDef
があります。
Schema
Schema
には、その構造を定義する Columns
があります。
dbKona を使用した実装
以降の節では、リモート DBMS からデータを取り出して表示する単純な Java アプリケーションのビルド手順の概要を、一連のサンプルを使用して説明します。
dbKona を使用した DBMS へのアクセス
以下の手順では、dbKona を使用して DBMS にアクセスする方法について説明します。
手順 1. パッケージのインポート
dbKona を使用するアプリケーションは java.sql
および weblogic.db.jdbc
(WebLogic dbKona パッケージ)に加えて、使用する他の Java クラスにもアクセスする必要があります。以下の例では、ログイン プロセスで使用する java.util
の Properties クラス、および weblogic.html
パッケージもインポートします。
import java.sql.*;
import weblogic.db.jdbc.*;
import weblogic.html.*;
import java.util.Properties;
JDBC ドライバ用のパッケージは、インポートしないでください。JDBC ドライバは、接続段階で確立されます。バージョン 2.0 以降では、weblogic.db.common、weblogic.db.server
、weblogic.db.t3client
はいずれもインポートしないでください。
手順 2. 接続確立用のプロパティの設定
次のコード例は、Properties オブジェクトを作成するためのメソッドのサンプルです。このメソッドは、このチュートリアルで Oracle DBMS との接続を確立するために後で使用されます。各プロパティは、文字列をダブルクォテーション("")で囲んで設定します。
public class tutor {
public static void main(String argv[])
throws DataSetException, java.sql.SQLException,
java.io.IOException, ClassNotFoundException
{
Properties props = new java.util.Properties();
props.put("user", "scott");
props.put("password", "tiger");
props.put("server", "DEMO");
(以降に続く)
Properties
オブジェクトは、Connection
を作成するための引数として使用されます。JDBC Connection
オブジェクトは、その他のデータベース操作でも重要なコンテキストになります。
手順 3. DBMS との接続の確立
Connection
オブジェクトは、Class.forName()
メソッドでJDBC ドライバ クラスをロードし、次に java.sql.myDriver.connect()
コンストラクタを呼び出すことにより作成されます。このコンストラクタは、使用する JDBC ドライバの URL
と java.util.Properties
オブジェクトの 2 つの引数を取ります。
Properties オブジェクトの作成方法は、手順 2 の props を参照してください。
Driver myDriver = (Driver)
Class.forName("weblogic.jdbc.oci.Driver").newInstance();
conn =
myDriver.connect("jdbc:weblogic:oracle", props);
conn.setAutoCommit(false);
Connection
conn は、DBMS に関連するその他のアクション(たとえば、クエリ結果を保持する DataSet
の作成など)のための引数となります。DBMS への接続の詳細については、使用しているドライバの開発者ガイドを参照してください。
Connections
、DataSets
(使用している場合は JDBC ResultSets
)、および Statements
は、それらの操作を終了するときに close()
メソッドで閉じる必要があります。サンプルでは、この方法に従って、それらが明示的に閉じられています。
注意: java.sql.Connection
のデフォルト モードでは、autoCommit が true
に設定されています。Oracle の場合は、上記のサンプルのように autoCommit
を false
に設定するとパフォーマンスが向上します。
注意: DriverManager.getConnection()
は同期メソッドなので、特定の状況では、アプリケーションがハングする原因となります。このため、DriverManager.getConnection()
の変わりに Driver.connect()
メソッドを使用することをお勧めします。
クエリの準備、およびデータの検索と表示
以下の手順では、クエリを準備し、データを検索および表示する方法について説明します。
手順 1. データ検索用のパラメータの設定
dbKona には、データ検索を行う場合に SQL 文を作成したり、その範囲を設定したりするためのパラメータを設定する方法がいくつかあります。ここでは、JDBC ResultSet
の結果を使用し、DataSet
を作成するという、dbKona と JDBC ドライバの基本的な相互作用について説明します。このサンプルでは、SQL 文を実行するのに Statement
オブジェクトを使用しています。Statement
オブジェクトは、JDBC Connection
クラスのメソッドによって作成されます。また、ResultSet
は、Statement オブジェクトを実行することによって作成されます。
Statement stmt = conn.createStatement();
stmt.execute("SELECT * from empdemo");
ResultSet rs = stmt.getResultSet();
Statement オブジェクトを使用して実行したクエリの結果を使用して、QueryDataSet
をインスタンス化できます。この QueryDataSet
は、JDBC ResultSet
を使用して作成されます。
Statement stmt = conn.createStatement();
stmt.execute("SELECT * from empdemo");
ResultSet rs = stmt.getResultSet();
QueryDataset ds = new QueryDataSet(rs);
JDBC Statement
の実行結果を使用することが、DataSet
を作成する唯一の方法になります。この方法には、SQL に関する知識が必要であり、かつ、クエリの結果をあまり細かく指定することはできません(基本的には、JDBC の next()
メソッドを使用すれば、レコード操作を繰り返すことができます)。dbKona を使用すると、レコードを検索するのに SQL の知識はあまり必要になりません。つまり、dbKona のメソッドを使用してクエリを設定することができ、一度レコードを保持する DataSet
を作成すればレコードの操作をより細かく指定できます。
手順 2. クエリ結果用の DataSet の生成
SQL 文を作成する必要はありませんが、dbKona では SQL 文の特定の部分を設定するメソッドを使用する必要があります。DataSet
(TableDataSet
または QueryDataSet
)をクエリの結果用に作成します。
たとえば、dbKona で最も単純なデータ検索は、TableDataSet
に対するものです。TableDataSet
の作成に必要なのは、Connection
オブジェクトと検索する DBMS テーブル名だけです。Employee テーブル(エリアスは「empdemo
」)を検索するサンプルを次に示します。
TableDataSet tds = new TableDataSet(conn, "empdemo");
TableDataSet
は、DBMS テーブルの属性(カラム)のサブセットを使用して作成できます。非常に大きなテーブルから数個のカラムだけを取り出す場合には、それらのカラムを指定する方がテーブル全体を検索するより効率的です。そのためには、コンストラクタの引数としてテーブル属性のリストを渡します。次に例を示します。
TableDataSet tds = new TableDataSet(conn, "empdemo", "empno, dept");
DBMS に変更内容を保存する場合や、1 つまたは複数のテーブルの結合を行ってデータを取り出すつもりがない場合は、TableDataSet
を使用し、それ以外の場合は、QueryDataSet
を使用します。次のサンプルでは、2 つの引数(Connection
オブジェクトと SQL 文の文字列)を取る QueryDataSet
コンストラクタを使用しています。
QueryDataSet qds = new QueryDataSet(conn, "select * from empdemo");
実際には、DataSet
クラスの fetchRecords()
メソッドを呼び出すまではデータの受け取りは開始されません。DataSet
を作成した後は、データ パラメータに引き続き修正を加えることができます。たとえば、where()
メソッドを使用して、TableDataSet
に取り出すレコードの選択精度を向上させることができます。where() メソッドは、dbKona が作成する SQL 文に WHERE
句を追加します。次のサンプルでは、WHERE
句を作成する where()
メソッドを使用して、Employee テーブルからレコードを 1 つだけ取り出しています。
TableDataSet tds = new TableDataSet(conn, "empdemo");
tds.where("empno = 8000");
手順 3. 結果の取り出し
データ パラメータを設定したら、次の例のように DataSet
クラスの fetchRecords()
メソッドを呼び出します。
TableDataset tds = new TableDataSet(conn, "empdemo", "empno,
dept");
tds.where("empno = 8000");
tds.fetchRecords();
fetchRecords()
メソッドは、特定の数のレコードを取り出す引数や、特定のレコードで始まるレコードを取り出す引数を取ることができます。次のサンプルでは、最初の 20 レコードのみを取り出し、残りは clearRecords()
を使用して破棄しています。
TableDataSet tds = new TableDataSet(conn, "empdemo", "empno,
dept");
tds.where("empno > 8000");
tds.fetchRecords(20)
.clearRecords();
非常に大きなクエリ結果を処理する場合は、一度に取り出すレコード数を少なくしてまずそれを処理し、DataSet
を消去してから次の取り出しに進んだ方が良い場合もあります。次の取り出しまでの間に TableDataSet
を消去するには、DataSet
クラスから clearRecords()
メソッドを使用します。次にそのサンプルを示します。
TableDataSet tds = new TableDataSet(conn, "empdemo", "empno,
dept");
tds.where("empno > 2000");
while (!tds.allRecordsRetrieved()) {
tds.fetchRecords(100);
// 100 個のレコードを処理する . .
tds.clearRecords();
}
また、リリース 2.5.3 で新規追加されたメソッドを使用して DataSet
を再利用することもできます。その DataSet.releaseRecords()
メソッドは、DataSet
を閉じてすべての Record を解放しますが破棄は行いません。その DataSet
を再利用して、新しいレコードを生成できますが、アプリケーションによって保持されている最初に使用した DataSet からのレコードは読み込み可能のままです。
手順 4. TableDataSet の Schema の検査
TableDataSet
に関する Schema
情報を検査する簡単なサンプルを以下に示します。Schema
クラスの toString()
メソッドは、TableDataSet
tds 用にクエリされるテーブル内のカラムの名前、タイプ、長さ、精度、スケール、NULL 許容の各属性を含む、改行で区切られたリストを表示します。
Schema sch = tds.schema();
System.out.println(sch.toString());
Statement オブジェクトを使用してクエリを作成した場合は、クエリが終了して、その結果を取り出した後で Statement オブジェクトを閉じる必要があります。
stmt.close();
手順 5. htmlKona を使用したデータの検査
次のサンプルでは、htmlKona UnorderedList
を使用してデータを検査する方法を示します。このサンプルでは、DataSet.getRecord()
および Record.getValue()
を使用して、for ループで各レコードを検査し、手順 2. で作成した QueryDataSet に取り出したレコードから収入額が最高である従業員の名前、ID、および給料を検索します。
// (データベース セッション オブジェクトと QueryDataSet qds の作成)
UnorderedList ul = new UnorderedList();
String name = "";
String id = "";
String salstr = "";
int sal = 0;
for (int i = 0; i < qds.size(); i++) {
// レコードを取得する
Record rec = qds.getRecord(i);
int tmp = rec.getValue("Emp Salary").asInt();
// htmlKona ListElement に給与額を追加する
ul.addElement(new ListItem("$" + tmp));
// この給与額とこれまでに見つかった給与最高額と比較する
if (tmp > sal) {
// この給与額が新しい最高額の場合には、その従業員の情報を取得する
sal = tmp;
name = rec.getValue("Emp Name").asString();
id = rec.getValue("Emp ID").asString();
salstr = rec.getValue("Emp Salary").asString();
}
手順 6. htmlKona を使用した結果の表示
htmlKona を使用すると、上記のサンプルで作成したような動的データを簡単に表示できます。次のサンプルは、クエリの結果を表示するページを動的に作成する方法を示しています。
HtmlPage hp = new HtmlPage();
hp.getHead()
.addElement(new TitleElement("Highest Paid Employee"));
hp.getBodyElement()
.setAttribute(BodyElement.bgColor, HtmlColor.white);
hp.getBody()
.addElement(MarkupElement.HorizontalLine)
.addElement(new HeadingElement("Query String: ", +2))
.addElement(stmt.toString())
.addElement(MarkupElement.HorizontalLine)
.addElement("I examined the values: ")
.addElement(ul)
.addElement(MarkupElement.HorizontalLine)
.addElement("Max salary of those employees examined is: ")
.addElement(MarkupElement.Break)
.addElement("Name: ")
.addElement(new BoldElement(name))
.addElement(MarkupElement.Break)
.addElement("ID: ")
.addElement(new BoldElement(id))
.addElement(MarkupElement.Break)
.addElement("Salary: ")
.addElement(new BoldElement(salstr))
.addElement(MarkupElement.HorizontalLine);
hp.output();
手順 7. DataSet および接続のクローズ
qds.close();
tds.close();
DBMS への接続を閉じることも重要です。次のサンプルのように、接続を閉じるコードが、すべてのデータベース操作の最後に finally ブロック内に表示される必要があります。
try {
// 処理を行う
}
catch (Exception mye) {
// 例外を検出し処理する
}
finally {
try {conn.close();}
catch (Exception e) {
//例外を処理する
}
}
コードのまとめ
import java.sql.*;
import weblogic.db.jdbc.*;
import weblogic.html.*;
import java.util.Properties;
public class tutor {
public static void main(String[] argv)
throws java.io.IOException, DataSetException,
java.sql.SQLException, HtmlException,
ClassNotFoundException
{
Connection conn = null;
try {
Properties props = new java.util.Properties();
props.put("user", "scott");
props.put("password", "tiger");
props.put("server", "DEMO");
Driver myDriver = (Driver)
Class.forName("weblogic.jdbc.oci.Driver").newInstance();
conn =
myDriver.connect("jdbc:weblogic:oracle",
props);
conn.setAutoCommit(false);
// TableDataSet オブジェクトを作成し、レコードを 10 個追加する
TableDataSet tds = new TableDataSet(conn, "empdemo");
for (int i = 0; i < 10; i++) {
Record rec = tds.addRecord();
rec.setValue("empno", i)
.setValue("ename", "person " + i)
.setValue("esalary", 2000 + (i * 10));
}
// データを保存し TableDataSet を閉じる
tds.save();
tds.close();
// QueryDataSet を作成し、テーブルへの追加分を取り出す
Statement stmt = conn.createStatement();
stmt.execute("SELECT * from empdemo");
QueryDataSet qds = new QueryDataSet(stmt.getResultSet());
qds.fetchRecords();
// QueryDataSet 内のデータを使用する
UnorderedList ul = new UnorderedList();
String name = "";
String id = "";
String salstr = "";
int sal = 0;
for (int i = 0; i < qds.size(); i++) {
Record rec = qds.getRecord(i);
int tmp = rec.getValue("Emp Salary").asInt();
ul.addElement(new ListItem("$" + tmp));
if (tmp > sal) {
sal = tmp;
name = rec.getValue("Emp Name").asString();
id = rec.getValue("Emp ID").asString();
salstr = rec.getValue("Emp Salary").asString();
}
}
//
htmlKona
ページを使用して、取り出したデータと
//
その取り出しに使用された文を表示する
HtmlPage hp = new HtmlPage();
hp.getHead()
.addElement(new TitleElement("Highest Paid Employee"));
hp.getBodyElement()
.setAttribute(BodyElement.bgColor, HtmlColor.white);
hp.getBody()
.addElement(MarkupElement.HorizontalLine)
.addElement(new HeadingElement("Query String: ", +2))
.addElement(stmt.toString())
.addElement(MarkupElement.HorizontalLine)
.addElement("I examined the values: ")
.addElement(ul)
.addElement(MarkupElement.HorizontalLine)
.addElement("Max salary of those employees examined is: ")
.addElement(MarkupElement.Break)
.addElement("Name: ")
.addElement(new BoldElement(name))
.addElement(MarkupElement.Break)
.addElement("ID: ")
.addElement(new BoldElement(id))
.addElement(MarkupElement.Break)
.addElement("Salary: ")
.addElement(new BoldElement(salstr))
.addElement(MarkupElement.HorizontalLine);
hp.output();
// QueryDataSet を閉じる
qds.close();
}
catch (Exception e) {
//例外を処理する
}
finally {
// 接続を閉じる
try {conn.close();}
catch (Exception mye) {
//例外を処理する
}
}
}
}
各 Statement
および各 DataSet
を使用後に閉じていること、および finally
ブロックで接続を閉じていることに注意してください。
SelectStmt オブジェクトを使用したクエリの作成
以下の手順では、SelectStmt
オブジェクトを使用してクエリを作成する方法について説明します。
手順 1. SelectStmt パラメータの設定
TableDataSet
を作成すると、TableDataSet は空の SelectStmt
に関連付けられます。その後、その SelectStmt を変更してクエリを作成できます。次のサンプルでは、接続 conn は既に作成済みです。ここでは TableDataSet
の SelectStmt
にアクセスする方法を示します。
TableDataSet tds = new TableDataSet(conn, "empdemo");
SelectStmt sql = tds.selectStmt();
ここで SelectStmt
オブジェクト用のパラメータを設定します。次のサンプルでは、各フィールドの最初の引数が属性名、2 番目の引数がエリアスです。このクエリは、収入が $2000 未満のすべての従業員に関する情報を取り出します。
sql.field("empno", "Emp ID")
.field("ename", "Emp Name")
.field("sal", "Emp Salary")
.from("empdemo")
.where("sal < 2000")
.order("empno");
手順 2. QBE を使用したパラメータの修正
SelectStmt
オブジェクトでも Query-by-example
機能を提供します。Query-by-example
または QBE
は、カラム、演算子、値という形式の句を使用して、データを取得するためのパラメータを作成します。たとえば、「empno = 8000」は、employee フィールド値(「empno」、エリアスは「Emp ID」
)が 8000 に等しい、1 つまたは複数のテーブル内のすべての行を選択できる Query-by-example
の句です。
さらに、次のサンプルに示すように、SelectStmt
クラスの setQbe()
メソッドおよび addQbe()
メソッドを使用することによって、データ選択用のパラメータを定義することもできます。これらのメソッドでは、Select 文の作成にベンダ固有の QBE
構文を使用できます。
sql.setQbe("ename", "MURPHY")
.addUnquotedQbe("empno", "8000");
パラメータの定義が終わったら、2 番目のチュートリアルで実施したように、fetchRecords()
メソッドを使用して DataSet
にデータを取り込みます。
SQL 文を使用した DBMS データの変更
以下の手順では、SQL 文を使用して DBMS データを変更する方法について説明します。
手順 1. SQL 文の記述
変更するデータを取り出してその変更内容をリモート DBMS に保存する必要がある場合には、TableDataSet
にそのデータを取り出さなければなりません。QueryDataSet
に取り出しても変更を保存できないからです。
ほとんどの dbKona 操作同様、Properties
オブジェクトおよび Driver
オブジェクトを作成して Connection
をインスタンス化することによって操作を開始する必要があります。
手順 1. SQL 文の記述
String insert = "insert into empdemo(empno, " +
"ename, job, deptno) values " +
"(8000, 'MURPHY', 'SALESMAN', 10)";
2 番目の SQL 文は、名前「Murphy」を「Smith」に変更し、ジョブ ステータスを「Salesman」から「Manager」に変更するものです。
String update = "update empdemo set ename = 'SMITH', " +
"job = 'MANAGER' " +
"where empno = 8000";
3 番目の SQL 文は、データベースからこのレコードを削除するものです。
String delete = "delete from empdemo where empno = 8000";
手順 2. 各 SQL 文の実行
まず、テーブルのスナップショットを TableDataSet
に保存します。その後、各 TableDataSet
を検査して実行結果が予想どおりであるかどうかを検証します。TableDataSet
は実行されたクエリの結果によってインスタンス化されるということに注意してください。
Statement stmt1 = conn.createStatement();
stmt1.execute(insert);
TableDataSet ds1 = new TableDataSet(conn, "emp");
ds1.where("empno = 8000");
ds1.fetchRecords();
TableDataSet
に関連付けられたメソッドを使用すると、SQL の WHERE
句や ORDER BY
句を指定したり、QBE
文を設定および追加したりできます。このサンプルでは、各文を実行して execute()
メソッドの結果を調べた後に、TableDataSet
を使用してデータベース テーブル「emp
」を再クエリしています。「WHERE
」句を使用して、テーブル内のレコードを従業員番号が 8000 のレコードに限定しています。
UPDATE 文および DELETE 文に対して execute()
メソッドを繰り返して、さらに 2 つの TableDataSet
、ds2 および ds3 に結果を格納します。
手順 3. htmlKona を使用した結果の表示
ServletPage hp = new ServletPage();
hp.getHead()
.addElement(new TitleElement("Modifying data with SQL"));
hp.getBody()
.addElement(MarkupElement.HorizontalLine)
.addElement(new TableElement(tds))
.addElement(MarkupElement.HorizontalLine)
.addElement(new HeadingElement("Query results afer INSERT", 2))
.addElement(new HeadingElement("SQL: ", 3))
.addElement(new LiteralElement(insert))
.addElement(new HeadingElement("Result: ", 3))
.addElement(new LiteralElement(ds1))
.addElement(MarkupElement.HorizontalLine)
.addElement(new HeadingElement("Query results after UPDATE", 2))
.addElement(new HeadingElement("SQL: ", 3))
.addElement(new LiteralElement(update))
.addElement(new HeadingElement("Result: ", 3))
.addElement(new LiteralElement(ds2))
.addElement(MarkupElement.HorizontalLine)
.addElement(new HeadingElement("Query results after DELETE", 2))
.addElement(new HeadingElement("SQL: ", 3))
.addElement(new LiteralElement(delete))
.addElement(new HeadingElement("Result: ", 3))
.addElement(new LiteralElement(ds3))
.addElement(MarkupElement.HorizontalLine);
hp.output();
コードのまとめ
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.sql.*;
import java.util.*;
import weblogic.db.jdbc.*;
import weblogic.html.*;
public class InsertUpdateDelete extends HttpServlet {
public synchronized void service(HttpServletRequest req,
HttpServletResponse res)
throws IOException
{
Connection conn = null;
try {
res.setStatus(HttpServletResponse.SC_OK);
res.setContentType("text/html");
Properties props = new java.util.Properties();
props.put("user", "scott");
props.put("password", "tiger");
props.put("server", "DEMO");
Driver myDriver = (Driver)
Class.forName("weblogic.jdbc.oci.Driver").newInstance();
conn =
myDriver.connect("jdbc:weblogic:oracle",
props);
conn.setAutoCommit(false);
// 関連付けられた SelectStmt を持つ TableDataSet を作成する
TableDataSet tds = new TableDataSet(conn, "empdemo");
SelectStmt sql = tds.selectStmt();
sql.field("empno", "Emp ID")
.field("ename", "Emp Name")
.field("sal", "Emp Salary")
.from("empdemo")
.where("sal < 2000")
.order("empno");
sql.setQbe("ename", "MURPHY")
.addUnquotedQbe("empno", "8000");
tds.fetchRecords();
String insert = "insert into empdemo(empno, " +
"ename, job, deptno) values " +
"(8000, 'MURPHY', 'SALESMAN', 10)";
// 文を作成して、実行する
Statement stmt1 = conn.createStatement();
stmt1.execute(insert);
stmt1.close();
// 結果を検証する
TableDataSet ds1 = new TableDataSet(conn, "empdemo");
ds1.where("empno = 8000");
ds1.fetchRecords();
// 文を作成して、実行する
String update = "update empdemo set ename = 'SMITH', " +
"job = 'MANAGER' " +
"where empno = 8000";
Statement stmt2 = conn.createStatement();
stmt2.execute(insert);
stmt2.close();
// 結果を検証する
TableDataSet ds2 = new TableDataSet(conn, "empdemo");
ds2.where("empno = 8000");
ds2.fetchRecords();
// 文を作成して、実行する
String delete = "delete from empdemo where empno = 8000";
Statement stmt3 = conn.createStatement();
stmt3.execute(insert);
stmt3.close();
// 結果を検証する
TableDataSet ds3 = new TableDataSet(conn, "empdemo");
ds3.where("empno = 8000");
ds3.fetchRecords();
// 結果を表示するサーブレット ページを作成する
ServletPage hp = new ServletPage();
hp.getHead()
.addElement(new TitleElement("Modifying data with SQL"));
hp.getBody()
.addElement(MarkupElement.HorizontalRule)
.addElement(new HeadingElement("Original table", 2))
.addElement(new TableElement(tds))
.addElement(MarkupElement.HorizontalRule)
.addElement(new HeadingElement("Query results afer INSERT", 2))
.addElement(new HeadingElement("SQL: ", 3))
.addElement(new LiteralElement(insert))
.addElement(new HeadingElement("Result: ", 3))
.addElement(new LiteralElement(ds1))
.addElement(MarkupElement.HorizontalRule)
.addElement(new HeadingElement("Query results after UPDATE", 2))
.addElement(new HeadingElement("SQL: ", 3))
.addElement(new LiteralElement(update))
.addElement(new HeadingElement("Result: ", 3))
.addElement(new LiteralElement(ds2))
.addElement(MarkupElement.HorizontalRule)
.addElement(new HeadingElement("Query results after DELETE", 2))
.addElement(new HeadingElement("SQL: ", 3))
.addElement(new LiteralElement(delete))
.addElement(new HeadingElement("Result: ", 3))
.addElement(new LiteralElement(ds3))
.addElement(MarkupElement.HorizontalRule);
hp.output();
tds.close();
ds1.close();
ds2.close();
ds3.close();
}
catch (Exception e) {
// 例外を処理する
}
// 常に、finally ブロック内で接続を閉じる
finally {
conn.close();
}
}
}
KeyDef を使用した DBMS データの変更
KeyDef
オブジェクトを使用して、リモート DBMS に対するデータの削除および挿入用のキーを取得します。KeyDef
は、「WHERE KeyDef attribute1 = value1
and KeyDef attribute2 = value2
」というパターンに従って、更新および削除を行う場合に文と同じように機能します。
最初の手順は、DBMS への接続を確立することです。ここで示すサンプルでは、最初のチュートリアルで作成した Connection
オブジェクト conn を使用します。また、使用するデータベース テーブルは、empno
、ename
、job
、および deptno
の各フィールドを持つ Employee
テーブル(「empdemo
」)です。実行するクエリは、テーブル empdemo
の内容をすべて取り出します。
手順 1. KeyDef とその属性の作成
このチュートリアルで挿入および削除用に作成する KeyDef オブジェクトには、データベースの empno
カラムという 1 つの属性があります。この属性を持った KeyDef
を作成すると、WHERE empno =
および保存する各レコードの empno
に割り当てられている特定の値、というパターンに従ったキーが設定されます。
KeyDef
オブジェクトは、次のサンプルに示すように、KeyDef
クラス内で作成されます。
KeyDef key = new KeyDef().addAttrib("empno");
Oracle データベースを使用している場合は、属性「ROWID
」を持った KeyDef
を作成して、次のサンプルのようにこの Oracle キーで挿入および削除を行うことができます。
KeyDef key = new KeyDef().addAttrib("ROWID");
手順 2. KeyDef を使用した TableDataSet の作成
次の例では、クエリの結果を使用して TableDataSet
を作成します。引数として Connection オブジェクト、DBMS テーブル名、および KeyDef
を取る TableDataSet
コンストラクタを使用します。
TableDataSet tds = new TableDataSet(conn, "empdemo", key);
KeyDef
は、データに対して行うすべての変更の参照になります。TableDataSet
を保存するたびに、KeyDef
属性の値(および SQL
UPDATE
、INSERT
、DELETE
の各操作に設定された制限)に基づいて、データベースのデータを変更します。このサンプルでは、属性は従業員番号("empno
")です。
Oracle データベースを使用し、属性 ROWID
を KeyDef
に追加した場合は、次のように挿入および削除用の TableDataSet
を作成できます。
KeyDef key = new KeyDef().addAttrib("ROWID");
TableDataSet tds =
new TableDataSet(conn, "empdemo", "ROWID, dept", key);
tds.where("empno < 100");
tds.fetchRecords();
手順 3. TableDataSet へのレコードの挿入
TableDataSet
のコンテキストで新しい Record
オブジェクトを作成できます。新しいオブジェクトは、TableDataSet
クラスの addRecord()
メソッドを使用して TableDataSet に追加されます。レコードを追加すると、Record
クラスの setValue()
メソッドを使用して、レコードの各フィールドの値を設定できます。レコードをデータベース(KeyDef
フィールド)に保存するには、新しい Record
で少なくとも 1 つの値を設定する必要があります。
Record newrec = tds.addRecord();
newrec.setValue("empno", 8000)
.setValue("ename", "MURPHY")
.setValue("job", "SALESMAN")
.setValue("deptno", 10);
String insert = newrec.getSaveString();
tds.save();
Record
クラスの getSaveString()
メソッドは、Record
をデータベースに保存する場合に使用される、SQL 文字列(SQL の UPDATE 文、DELETE 文、または INSERT 文
)を返します。この文字列をオブジェクトに保存し、後でそのオブジェクトを表示させることで、挿入操作が実際どのように実行されたのかを確認できます。
手順 4. TableDataSet でのレコードの更新
setValue()
メソッドを使用して Record
を更新することもできます。次の例では、前の手順で作成したレコードを変更します。次の例では、前の手順で作成したレコードを変更します。
newrec.setValue("ename", "SMITH")
.setValue("job", "MANAGER");
String update = newrec.getSaveString();
tds.save();
手順 5. TableDataSet からのレコードの削除
Record
クラスの markToBeDeleted()
メソッドを使用して、TableDataSet のレコードに、削除するためのマークを付けることができます(または、unmarkToBeDeleted()
メソッドでマークを解除できます)。たとえば、作成したばかりのレコードを削除するには、次のように、削除するレコードにマークを付けます。
newrec.markToBeDeleted();
String delete = newrec.getSaveString();
tds.save();
削除するようにマークが付けられたレコードは、save()
メソッドを実行するか、または TableDataSet
クラスの removeDeletedRecords()
メソッドを実行するまでは TableDataSet
から削除されません。
(removeDeletedRecords()
メソッドにより)TableDataSet
から削除されたが、まだデータベースからは削除されていないレコードは、ゾンビ状態になります。レコードがゾンビ状態かどうかは、次のように Record クラスの isAZombie()
メソッドを使用して確認できます。
if (!newrec.isAZombie()) {
. . .
}
手順 6. TableDataSet の保存の詳細
Record
または TableDataset
を保存すると、データベースにデータが効率的に保存されます。dbKona では選択的に変更が行われます。つまり、変更されたデータのみが保存されます。TableDataSet
内のレコードを挿入、更新、および削除しても、Record.save()
メソッドまたは TableDataSet.save()
メソッドが実行されるまでは TableDataSet
内のデータだけが影響を受けます。
保存前の Record 状態の確認
Record
クラスのメソッドの中には、save()
を実行する前に Record
の状態に関する情報を返すメソッドがあります。以下にその一部を示します。
needsToBeSaved()
および recordIsClean()
needsToBeSaved()
メソッドを使用すると、Record
を保存する必要があるかどうかを確認できます。つまり、Record が取り出されてから、または、前回保存されてから、変更されたかどうかを確認できます。recordIsClean()
メソッドは、Record
にある Value
のいずれかを保存する必要があるかどうかを確認するために使用します。このメソッドは、スケジュールされたデータベース操作が挿入、更新、または削除のいずれであるかに関係なく、Record
が変更されている状態かどうかを確認するだけです。操作のタイプ(挿入/更新/削除)にかかわらず、needsToBeSaved()
メソッドを save()
メソッドの後で実行すると、false
が返されます。
valueIsClean(int)
Record
内の特定のインデックス位置にある Value
を保存する必要があるかどうかを確認します。このメソッドは、Value
のインデックス位置を引数に取ります。
toBeSavedWith...()
toBeSavedWithDelete()
、toBeSavedWithInsert()
、および toBeSavedWithUpdate()
の各メソッドを使用すると、特定の SQL アクションと共に、Record がどのように保存されるかを確認できます。これらのメソッドのセマンティクスは、「この行が変更されている、または変更される場合、TableDataSet
を保存するときにどのようなアクションが行われるか」という問いに対する答えと同じです。
行が DBMS への保存対象かどうかを知るには、isClean()
メソッドと needsToBeSaved()
メソッドを使用します。
Record
または TableDataSet
を変更する場合は、いずれかのクラスの save()
メソッドを使用して、その変更内容をデータベースに保存します。上記の手順では、各トランザクションの後で次のように TableDataSet
を保存しました。
tds.save();
手順 7. 変更内容の検証
レコードを 1 つだけ取り出す場合のサンプルを以下に示します。この方法は、1 レコードの変更内容を検証するには、効率的な方法です。このサンプルでは、query-by-example
(QBE
)の句を使用して TableDataSet
から関心のあるレコードだけを取り出しています。
TableDataSet tds2 = new TableDataSet(conn, "empdemo");
tds2.where("empno = 8000")
.fetchRecords();
最後の手順として、各手順の後、および各 save()
メソッドの後に作成した「insert
」、「update
」、および「delete
」の各文字列の後にクエリ結果を表示できます。結果を表示する htmlKona の使用方法については、前のチュートリアルの「コードのまとめ」を参照してください。
DataSet
の操作を終了したら、次のように close()
メソッドを使用して各 DataSet を閉じます。
tds.close();
tds2.close();
コードのまとめ
次に、この節で説明した概念を使用するサンプル コードを示します。
package tutorial.dbkona;
import weblogic.db.jdbc.*;
import java.sql.*;
import java.util.Properties;
public class rowid {
public static void main(String[] argv)
throws Exception
{
Driver myDriver = (Driver)
Class.forName("weblogic.jdbc.oci.Driver").newInstance();
conn =
myDriver.connect("jdbc:weblogic:oracle:DEMO",
"scott",
"tiger");
// ここで、レコードを 100 個挿入する
TableDataSet ts1 = new TableDataSet(conn, "empdemo");
for (int i = 1; i <= 100; i++) {
Record rec = ts1.addRecord();
rec.setValue("empid", i)
.setValue("name", "Person " + i)
.setValue("dept", i);
}
//
新しいレコードを保存する。dbKona
は選択的に保存を行う
//
つまり、TableDataSet
内の変更されたレコードだけを保存し、
//
ネットワーク トラフィックとサーバ呼び出しを削減する
System.out.println("Inserting " + ts1.size() + " records.");
ts1.save();
// 処理が完了したので DataSet を閉じる
ts1.close();
//
更新および削除用のKeyDef
を定義する
//
ROWID
はOracle
固有のフィールドで、更新および削除用の
//
主キーとして機能することができる
KeyDef key = new KeyDef().addAttrib("ROWID");
//
最初に追加した 100 個のレコードを更新する
TableDataSet ts2 =
new TableDataSet(conn, "empdemo", "ROWID, dept", key);
ts2.where("empid <= 100");
ts2.fetchRecords();
for (int i = 1; i <= ts2.size(); i++) {
Record rec = ts2.getRecord(i);
rec.setValue("dept", i + rec.getValue("dept").asInt());
}
// 更新されたレコードを保存する
System.out.println("Update " + ts2.size() + " records.");
ts2.save();
// 同じ 100 個のレコードを削除する
ts2.reset();
ts2.fetchRecords();
for (int i = 0; i < ts2.size(); i++) {
Record rec = ts2.getRecord(i);
rec.markToBeDeleted();
}
// レコードをサーバから削除する
System.out.println("Delete " + ts2.size() + " records.");
ts2.save();
//
DataSet
、ResultSet
、およびStatement
は、
//
操作が終わったら必ず閉じる必要がある
ts2.close();
// 最後に、必ず接続を閉じる
conn.close();
}
}
dbKona での JDBC PreparedStatement の使い方
dbKona では構文的に正しい SQL 文が作成されるため、ベンダ固有の SQL の記述方法について知識がそれほど必要ないという点で便利です。しかし、dbKona で JDBC の PreparedStatement
を使用できる場合もあります。
JDBC PreparedStatement
は、複数回使用される SQL 構文をあらかじめコンパイルする場合に使用されます。PreparedStatement
のパラメータは、PreparedStatement.clearParameters()
を呼び出すことで消去できます。
PreparedStatment
オブジェクトは、JDBC Connection
クラス(これまでのサンプルで conn という名前で使用されていたオブジェクト)の preparedStatement()
メソッドを使用して作成されます。次のサンプルでは、PreparedStatement
を作成してそれをループの中で実行しています。この文には、従業員 ID、名前、および部署という 3 つの入力(IN)パラメータがあります。このサンプルでは、100 人の従業員をテーブルに追加します。
String inssql = "insert into empdemo(empid, " +
"name, dept) values (?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(inssql);
for (int i = 1; i <= 100; i++) {
pstmt.setInt(1, i);
pstmt.setString(2, "Person" + i);
pstmt.setInt(3, i);
pstmt.executeUpdate();
}
pstmt.close();
作業が終了したら、Statement
オブジェクトまたは PreparedStatement
オブジェクトを必ず閉じます。
SQL を意識せずに同じタスクを dbKona で実行することもできます。この場合、KeyDef
を使用して、更新または削除するフィールドを設定します。詳細については、チュートリアルの
KeyDef を使用した DBMS データの変更を参照してください。
dbKona でのストアド プロシージャの使い方
固有のタスク(システムまたはベンダに依存しないタスクである場合が多い)を実行できる、リモート マシンに格納されたプロシージャや関数にアクセスして、dbKona の能力を向上させることができます。ストアド プロシージャおよび関数を使用するには、dbKona の Java アプリケーションとリモート マシンの間でリクエストがどのように受け渡しされるかを理解する必要があります。ストアド プロシージャまたは関数を実行すると、入力されたパラメータの値が変更されます。また、実行が成功したか失敗したかを示す値も返されます。
dbKona アプリケーションでの最初の手順は、DBMS に接続することです。ここで示すサンプルでは、最初のチュートリアルで作成した同じ Connection
オブジェクト conn
を使用します。
手順 1. ストアド プロシージャの作成
DBMS の CREATE
の呼び出しを実行することにより、Statement
オブジェクトを使用してストアド プロシージャを作成します。次の例では、パラメータ「field1
」が integer
型の入出力として宣言されます。
Statement stmtl = conn.createStatement();
stmtl.execute("CREATE OR REPLACE PROCEDURE proc_squareInt " +
"(field1 IN OUT INTEGER, " +
" field2 OUT INTEGER) IS " +
"BEGIN field1 := field1 * field1; " +
"field2 := field1 * 3; " +
"END proc_squareInt;");
stmtl.close();
手順 2. パラメータの設定
JDBC Connection
クラスの prepareCall()
メソッド
次のサンプルでは、setInt()
メソッドを使用して第 1 パラメータに整数「3」を設定しています。第 2 パラメータは、java.sql.Types.INTEGER
型の出力パラメータとして登録します。そして最後にストアド プロシージャを実行しています。
CallableStatement cstmt =
conn.prepareCall("BEGIN proc_squareInt(?, ?): END;");
cstmt.setInt(1, 3);
cstmt.registerOutParameter(2, java.sql.Types.INTEGER);
cstmt.execute();
ネイティブ Oracle では SQL 文中で「?」値のバインディングをサポートしていません。その代わり、「:1」、「:2」などを使用します。dbKona では、SQL でどちらも使用できます。
手順 3. 結果の検査
最も単純なメソッドを使用して結果を画面に出力します。
System.out.println(cstmt.getInt(1));
System.out.println(cstmt.getInt(2));
cstmt.close();
画像およびオーディオ用バイト配列の使い方
サイズの大きいバイナリ オブジェクト ファイルを、バイト配列を使用してデータベースから取り出したりデータベースに保存したりできます。データベースでデータを管理することの多いマルチメディア アプリケーションでは、画像ファイルやサウンド ファイルのようなサイズの大きいデータを処理する必要があります。
ここでは、htmlKona の便利さも理解できます。htmlKona を使用すれば、dbKona を使って取り出したデータベース データを HTML 環境に簡単に統合できます。このチュートリアルで使用するサンプルは、htmlKona に依存しています。
手順 1. 画像データの検索と表示
次のサンプルでは、htmlKona フォームで送信され、Netscape サーバで動作しているサーバサイド Java を使用して、ユーザが表示する画像の名前を取り出しています。その画像名を使って「imagetable
」という名前のデータベース テーブルの内容をクエリし、その結果得られる最初のレコードを取得します。SelectStmt
オブジェクトを使用して QBE
によって SQL クエリを作成しています。
画像レコードを取り出した後、HTML ページのタイプを画像タイプに設定し、それから画像データをバイト配列(byte[]
)として取り出して htmlKona ImagePage
に入れます。これにより、ブラウザに画像が表示されます。
if (iname != null) {
// 画像をデータベースから取り出す
TableDataSet tds = new TableDataSet(conn, "imagetable");
tds.selectStmt().setQbe("name", iname);
tds.fetchRecords();
Record rec = tds.getRecord(0);
this.returnNormalResponse("image/" +
rec.getValue("type").asString());
ImagePage hp = new ImagePage(rec.getValue("data").asBytes());
hp.output(getOutputStream());
}
手順 2. データベースへの画像の挿入
dbKona を使用してデータベースに画像ファイルを挿入することもできます。次に、データベースにタイプ配列オブジェクトとして 2 つの画像を追加するコードの抜粋を示します。この処理は、各画像の Record
を TableDataSet
へ追加し、Record
の Values
を設定して、TableDataSet
を保存することにより行われます。
TableDataSet tds = new TableDataSet(conn, "imagetable");
Record rec = tds.addRecord();
rec.setValue("name", "vars")
.setValue("type", "gif")
.setValue("data", "c:/html/api/images/variables.gif");
rec = tds.addRecord();
rec.setValue("name", "excepts")
.setValue("type", "jpeg")
.setValue("data", "c:/html/api/images/exception-index.jpg");
tds.save();
tds.close();
Oracle シーケンス用の dbKona の使い方
dbKona では、Oracle シーケンスの機能にアクセスするためのラッパー、つまり、Sequence
オブジェクトが用意されています。Oracle シーケンスは、シーケンスに開始番号とインクリメント間隔(増分)を指定することによって dbKona で作成されます。
以下の節では、Oracle シーケンス用の dbKona の使い方について説明します。
手順 1. dbKona Sequence オブジェクトの作成
JDBC Connection と Oracle サーバに既に存在するシーケンスの名前を使用して、Sequence
オブジェクトを作成します。次に例を示します。
Sequence seq = new Sequence(conn, "mysequence");
手順 2. dbKona からの Oracle サーバのシーケンスの作成と破棄
Oracle シーケンスが存在しない場合は、dbKona から Sequence.create()
メソッドを使用して作成できます。このメソッドは、JDBC Connection
、作成するシーケンスの名前、インクリメント間隔、および開始点の 4 つの引数を取ります。次のサンプルでは、開始点が 1000 でインクリメント間隔が 1 の Oracle シーケンス「mysequence」を作成しています。
Sequence.create(conn, "mysequence", 1, 1000);
次のように Oracle シーケンスを dbKona から削除できます。
Sequence.drop(conn, "mysequence");
手順 3. Sequence の使い方
Sequence
オブジェクトを作成したら、このオブジェクトを使用して自動的にインクリメントする int
を生成できます。たとえば、レコードをテーブルに追加するたびに自動的にインクリメントするキーを設定できます。nextValue()
メソッドを使用して、Sequence
の 次のインクリメントである int
を返します。次に例を示します。
TableDataSet tds = new TableDataSet(conn, "empdemo");
for (int i = 1; i <= 10; i++) {
Record rec = tds.addRecord();
rec.setValue("empno", seq.nextValue());
}
currentValue()
メソッドを使用して、Sequence の現在の値を確認できます。ただし、このメソッドは、nextValue()
メソッドを少なくとも一度呼び出した後でなければ呼び出せません。
System.out.println("Records 1000-" + seq.currentValue() + " added.");
コードのまとめ
次に、この節で説明した概念の使い方を示すサンプル コードを示します。最初に、Oracle サーバから「testseq
」という名前のシーケンスを削除して、その名前のシーケンスが既に 1 つ存在している場合に、同じ名前のシーケンスを作成してもエラーが出力されないようにしています。その後、サーバ上にシーケンスを作成し、その名前で dbKona Sequence
オブジェクトを作成しています。
package tutorial.dbkona;
import weblogic.db.jdbc.*;
import weblogic.db.jdbc.oracle.*;
import java.sql.*;
import java.util.Properties;
public class sequences {
public static void main(String[] argv)
throws Exception
{
Connection conn = null;
Driver myDriver = (Driver)
Class.forName("weblogic.jdbc.oci.Driver").newInstance();
conn =
myDriver.connect("jdbc:weblogic:oracle:DEMO",
"scott",
"tiger");
//
シーケンスがサーバ上に既に存在する場合には、それを削除する
try {Sequence.drop(conn, "testseq");} catch (Exception e) {;}
//
新しいシーケンスをサーバ上に作成する
Sequence.create(conn, "testseq", 1, 1);
Sequence seq = new Sequence(conn, "testseq");
//
ループでシーケンス内の次の値を出力する
for (int i = 1; i <= 10; i++) {
System.out.println(seq.nextValue());
}
System.out.println(seq.currentValue());
//
シーケンスをサーバからドロップし、
//
Sequence
オブジェクトを閉じる
Sequence.drop(conn, "testseq");
seq.close();
//
最後に接続を閉じる
conn.close();
}
}
![]() |
![]() |
![]() |