ORACLE JAPAN Server Release 6.1

 

  |  

  WebLogic Server ホーム   |     JDBC プログラミング ガイド   |   前へ   |   次へ   |   目次   |   索引   |   PDF 版

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 クラス(およびそのサブクラス TableDataSetQueryDataSet)のメソッドを使用すると、高レベルで柔軟な方法でクエリ結果を自在に操作できます。TableDataSet の変更内容は、DBMS に保存できます。この場合、dbKona では変更したレコードについての情報が保持され、選択的に保存されます。これにより、ネットワーク トラフィックおよび DBMS のオーバーヘッドが減少します。

また dbKona では、プログラマがベンダ固有の SQL を気にする必要のない、SelectStmtKeyDef などのオブジェクトも使用できます。これらのクラスのメソッドを使用すると、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 つのカテゴリに分けられます。

オブジェクトのこのような大きなカテゴリは、アプリケーションのビルドにおいて相互に依存し合っています。通常は、どのデータ オブジェクトにも、一連の記述オブジェクトが関連付けられています。

dbKona のデータ コンテナ オブジェクト

データ コンテナとして機能する基本的なオブジェクトには 3 種類あります。DataSet、Record、および Value の各オブジェクトです。DataSet(またはそのサブクラスである QueryDataSet あるいは TableDataSet)オブジェクトには Record オブジェクトが含まれ、Record オブジェクトには Value オブジェクトが含まれます。

DataSet

dbKona パッケージでは DataSet の概念を使用して、DBMS サーバから取り出されたレコードをキャッシュできます。この概念は、SQL におけるテーブルとほぼ同じです。DataSet クラスには 2 つのサブクラス、QueryDataSetTableDataSet があります。

WebLogic Server を使用する多層モデルでは、DataSet を WebLogic Server に保存(キャッシュ)できます。

DataSet クラス(weblogic.db.jdbc.DataSet を参照)は、QueryDataSet および TableDataSet の抽象的な親クラスです。

QueryDataSet

QueryDataSet を使用すると、SQL クエリの結果を、インデックス位置(0 が起点)を指定してアクセスする Record のコレクションとして使用できます。TableDataSet とは異なり、QueryDataSet に対して変更および追加した内容はデータベースに保存できません。

QueryDataSetTableDataSet には、機能的な違いが 2 つあります。1 番目の相違点は、TableDataSet の変更内容はデータベースに保存できるという点です。QueryDataSet の Record も変更できますが、その変更内容は保存できません。2 番目の相違点は、QueryDataSet には、複数のテーブルからのデータを取り出せるという点です。

QueryDataSet クラス(weblogic.db.jdbc.QueryDataSet を参照)には、QueryDataSet を作成、保存、および検索するためのメソッドがあります。QueryDataSet には、結合用の SQL など、任意の SQL を指定できます。そのスーパークラスである DataSet には、レコード キャッシュの詳細を管理するためのメソッドが含まれています。

TableDataSet

TableDataSetQueryDataSet の機能的な違いは、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 データベースを使用している場合は、TableDataSetKeyDef を「ROWID」に設定できます。「ROWID」は、各テーブルのユニークなキーです。その後、「ROWID」を含む一連の属性を使用して、TableDataSet を作成します。

TableDataSet クラス(weblogic.db.jdbc.TableDataSet を参照)には、次のメソッドがあります。

そのスーパークラスである DataSet には、レコード キャッシュを管理するためのメソッドが含まれています。

EventfulTableDataSet(非推奨)

WebLogic 内部で使用するための EventfulTableDataSet は、データがローカルまたは DBMS で更新されたときに、イベントを送信および受信する TableDataSet です。EventfulTableDataSet は、WebLogic Event のすべての Action クラスによって実装されるインタフェースである weblogic.event.actions.ActionDef を実装しています。EventfulTableDataSetaction() メソッドは、DBMS を更新し、同じ DBMS テーブルに関する他のすべての EventfulTableDataSet にその変更を通知します(WebLogic Event(非推奨)に関する詳細については、ホワイトペーパーおよび WebLogic Events の開発者ガイドを参照してください)。

EventfulTableDataSetEventfulRecord が変更されると、WebLogic Server に ParamSet を持つ EventMessage が送信されます。ParamSet には、変更されたデータと行が含まれます。このとき、そのトピックは、WEBLOGIC.[tablename] になります。ここで tablename には EventfulTableDataSet に関連付けられたテーブルの名前が入ります。EventfulTableDataSet は、受信し、評価されたイベントに基づいて動作し、変更されたレコードの独自のコピーを更新します。

EventfulTableDataSet は、java.sql.Connection オブジェクトのコンテキスト内で作成されます(Connection オブジェクトを引数としてコンストラクタに渡します)。また、t3 Client オブジェクト、挿入、更新、削除に使用される KeyDef オブジェクト、および DBMS のテーブル名も指定する必要があります。

たとえば、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 クラス(weblogic.db.jdbc.Record を参照)には、次のメソッドがあります。

Value

Value オブジェクトには、親の DataSetSchema によって定義される内部データ型があります。Value オブジェクトには、有効な割り当てであればその内部データ型以外のデータ型の値を割り当てることができます。また、Value オブジェクトには、有効なリクエストであればその内部データ型以外のデータ型の値を返すこともできます。

Value オブジェクトでは、アプリケーションでベンダ固有のデータ型を操作しなくてもいいようになっています。Value オブジェクトはそのデータ型を「知っています」が、すべての Value オブジェクトはその内部データ型に関係なく同じメソッドを使用して Java アプリケーション内で操作できます。

これらのデータ型は、java.sql.Types に表示されている JDBC のタイプに対応しています。

Value クラス(weblogic.db.jdbc.Value を参照)には、Value オブジェクトのデータおよびデータ型を取得および設定するためのメソッドがあります。

dbKona のデータ記述オブジェクト

データ記述オブジェクトには、メタデータが含まれます。メタデータとは、データ構造、DBMS へのデータの格納方法や DBMS からのデータの取り出し方法、データの更新方法などに関する情報のことです。dbKona で使用されるデータ記述オブジェクトの中には、JDBC インタフェースの実装であるオブジェクトもあります。ここでは、以下のデータ記述オブジェクトの概要とその使用法について説明します。

Schema

DataSet をインスタンス化すると、それを記述する Schema が暗黙に作成されます。そしてその Record を取り出すと、その Schema が更新されます。

Schema クラス(weblogic.db.jdbc.Schema を参照)には、次のメソッドがあります。

Column

Schema が作成されます。

Column クラス(weblogic.db.jdbc.Column を参照)には、次のメソッドがあります。

KeyDef

"特定のデータベース レコードをユニークなものとして識別し操作するための「WHERE attribute1 = value1 and attribute2 = value2」などのパターンです。KeyDef の属性は、データベース テーブルのユニークなキーに対応させる必要があります。

属性のない KeyDef オブジェクトは、KeyDef クラスで作成されます。addAttrib() メソッドを使用して、KeyDef の属性を作成してから、KeyDefTableDataSet 用のコンストラクタで引数として使用します。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 を継承します。

DataSetExceptionLicenseException などのほとんどの 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.serverweblogic.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 ドライバの URLjava.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 への接続の詳細については、使用しているドライバの開発者ガイドを参照してください。

ConnectionsDataSets(使用している場合は JDBC ResultSets)、および Statements は、それらの操作を終了するときに close() メソッドで閉じる必要があります。サンプルでは、この方法に従って、それらが明示的に閉じられています。

注意: java.sql.Connection のデフォルト モードでは、autoCommit が true に設定されています。Oracle の場合は、上記のサンプルのように autoCommitfalse に設定するとパフォーマンスが向上します。

注意: 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 文の特定の部分を設定するメソッドを使用する必要があります。DataSetTableDataSet または 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 は既に作成済みです。ここでは TableDataSetSelectStmt にアクセスする方法を示します。

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 つの TableDataSetds2 および 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 を使用します。また、使用するデータベース テーブルは、empnoenamejob、および 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 UPDATEINSERTDELETE の各操作に設定された制限)に基づいて、データベースのデータを変更します。このサンプルでは、属性は従業員番号("empno")です。

Oracle データベースを使用し、属性 ROWIDKeyDef に追加した場合は、次のように挿入および削除用の 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-exampleQBE)の句を使用して 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 を定義する
// ROWIDOracle 固有のフィールドで、更新および削除用の
// 主キーとして機能することができる
  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();
 
// DataSetResultSet、および 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 つの画像を追加するコードの抜粋を示します。この処理は、各画像の RecordTableDataSet へ追加し、RecordValues を設定して、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();
}
}

 

back to top previous page next page