WebLogic JDBC プログラマーズ ガイド
![]() |
![]() |
![]() |
![]() |
以下の節では、WebLogic RowSet の特徴と使い方について説明します。
WebLogic Server には、JSR-114 の仕様に準拠した Java RowSet が実装されています。この仕様の詳細については、Sun の Web サイト (http://java.sun.com/products/jdbc/download.html) を参照してください。WebLogic の RowSet 実装には、RowSet 仕様の拡張も含まれています。こうした拡張を使用すると、アプリケーションで RowSet をより有効に活用できます。
RowSet は Java ResultSet の拡張です。ResultSet と同様、RowSet も表形式のデータを保持する Java オブジェクトです。ただし、RowSet では ResultSet 機能に大幅な柔軟性が加えられていて、ResultSet の持つ制限の一部が緩和されたり削減されたりしています。
WebLogic Server の RowSet 実装には、以下のような種類とユーティリティがあります。
WebLogic Server の RowSet 実装は、ユーザが以下の手順で RowSet を扱うことを想定して設計されています。
変更を同期した後には、アプリケーションの設計に応じて手順 2 または手順 3 から繰り返し処理を行えます。「トランザクション完了後の WebLogic RowSet の再利用」を参照してください。
WebLogic の RowSet 実装にはライフサイクルのフレームワークがあり、これによって RowSet オブジェクトが異常な状態にならないようにしています。WebLogic Server では、上記の処理段階に応じて、内部的に RowSet に対しライフサイクルのステージが設定されます。データが失われるリスクを減らすため、ライフサイクルのステージに応じて RowSet に実施できる操作が制限されます。たとえば RowSet のステージが「Updating」 (更新) の場合、RowSet に対して呼び出せるのは updateXXX()
メソッド (updateString()
、updateInt()
など) のみです。この制限は、updateRow()
を呼び出して更新のフェーズが完了するまで適用されます。
注意 : クライアントサイド アプリケーションで RowSet を使用する際は、サーバとクライアントの両方の CLASSPATH
に、同一の JDBC ドライバ クラスを指定する必要があります。ドライバ クラスが同じでないと、java.rmi.UnmarshalException
例外が送出される場合があります。
RowSet の作成時からデータ変更がデータベースとの間で同期されるまでの RowSet のライフサイクルのステージの実例については、コード リスト 6-1 のコメントを参照してください。
以下の節では、WebLogic Server における標準の CachedRowSet の使い方について説明します。
また、標準の CachedRowSet オブジェクトの WebLogic 拡張の使用方法については、「WLCachedRowSet」を参照してください。
CachedRowSet は接続されていない ResultSet
オブジェクトです。CachedRowSet のデータはメモリに格納されます。WebLogic Server 実装の CachedRowSet には以下の特性があります。
アプリケーションの設計時には、次のことを考慮するようにします。
CachedRowSet ではデータベースへの接続が保持されないので、すべてのクエリの結果は必ずメモリに格納されます。クエリの結果が非常に大きいと、メモリ不足エラーによりパフォーマンスが低下することがあります。大きなデータ セットの場合、ResultSet を使用する方が適していることもあります。ResultSet ではデータベースへの接続が保持されるため、クエリ結果の一部をメモリに保持してから必要に応じてデータベースに戻り、さらに行を取得できるためです。
CachedRowSet は、RowSet への入力から RowSet 内のデータ変更がデータベースとの間で同期されるまでの間に、別のプロセスで更新されることがあまりないようなデータに使用するのがもっとも適しています。この期間にデータベースが変更されるとデータの競合が発生します。データの競合を検出して処理する方法については、「SyncResolver を使用した SyncProviderException の処理」を参照してください。
コード リスト 6-1 に CachedRowSet の基本的なワークフローを示します。このコード リストでは、主要な各操作と対応する RowSet のライフサイクルのステージについてコメントを使って説明します。このコード サンプルの後で、サンプルの主要な各セクションについてさらに詳細に説明します。
コード リスト 6-1 CachedRowSet のコード サンプル
import javax.sql.rowset.CachedRowSet;
import weblogic.jdbc.rowset.RowSetFactory;
public class CachedRowSetDemo {
public static void main (String[] args) {
//「DESIGNING」 (設計) ライフサイクル ステージ - RowSet を作成してプロパティを設定する
try {
//RowSetFactory インスタンスを作成する
RowSetFactory rsfact = RowSetFactory.newInstance();
CachedRowSet rs = rsfact.newCachedRowSet();
//DataSource を通じたデータベース アクセスを設定する
rs.setDataSourceName(examples-dataSource-demoPool);
//詳細については「データベース接続のオプション」を参照。
//クエリ コマンドを設定する
rs.setCommand("SELECT ID, FIRST_NAME, MIDDLE_NAME, LAST_NAME,
PHONE, EMAIL FROM PHYSICIAN WHERE ID>?");
//「CONFIGURE QUERY」 (クエリのコンフィグレーション) ライフサイクル操作
rs.setInt(1, 0);
//「POPULATING」 (入力) ライフサイクル ステージ - RowSet に入力するためのコマンドを実行する
rs.execute();
}
//「CONFIGURING METADATA」 (メタデータのコンフィグレーション) - メタデータを入力してから設定する。
//これには KeyColumn を含む
rs.setKeyColumns(new int[] { 1 });
while (rs.next ()) //「NAVIGATING」 (案内) ライフサイクル ステージ
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
}
}
//データを操作する
//RowSet の行を削除する
try {
//「MANIPULATING」 (操作) ライフサイクル ステージ - 行に移動する
//(カーソルを手動で移動する)
rs.last();
rs.deleteRow();
//データベースはまだ更新されていないことに注意
}
//RowSet の行を更新する
try {
//「MANIPULATING」 (操作) ライフサイクル ステージ - 行に移動する
//(カーソルを手動で移動する)
rs.first();
//「UPDATING」 (更新) ライフサイクル ステージ - update() メソッドを呼び出す
rs.updateString(4, "Francis");
//「MANIPULATING」 (操作) ライフサイクル ステージ - 更新を完了する
rs.updateRow();
//データベースはまだ更新されていないことに注意
}
//「INSERTING」 (挿入) ライフサイクル ステージ - RowSet に行を挿入する
try {
rs.moveToInsertRow();
rs.updateInt(1, 104);
rs.updateString("FIRST_NAME", "Yuri");
rs.updateString("MIDDLE_NAME", "M");
rs.updateString("LAST_NAME", "Zhivago");
rs.updateString("PHONE", "1234567812");
rs.updateString("EMAIL", "Yuri@poet.com");
rs.insertRow(); //「更新の完了」アクション
//「MANIPULATING」 (操作) ライフサイクル ステージ - 行に移動する
rs.moveToCurrentRow();
//データベースはまだ更新されていないことに注意
}
//すべての変更 (削除、更新、挿入) をデータベースに送信する。
//「DESIGNING」 (設計) または「POPULATING」 (入力) ライフサイクル ステージ - データベースとの間で変更を同期した後は
//他の環境設定に応じたライフサイクル ステージになる。
//「トランザクション完了後の WebLogic RowSet の再利用」を参照
try {
rs.acceptChanges();
rs.close();
}
}
標準の RowSet を使用するには、次のクラスをインポートする必要があります。
javax.sql.rowset.CachedRowSet;
weblogic.jdbc.rowset.RowSetFactory;
RowSet はファクトリ インタフェースから作成されます。WebLogic Server で RowSet を作成するには、主に以下の手順に従います。
RowSetFactory rsfact = RowSetFactory.newInstance();
javax.sql.rowset.CachedRowSet
オブジェクト型にキャストします。デフォルトでは WebLogic newCachedRowSet()
RowSetFactory メソッドで WLCachedRowSet
オブジェクトが作成されます。このオブジェクトをそのまま使用することもできますが、標準の CachedRowSet
オブジェクトを使用する場合は、WLCachedRowSet オブジェクトを CachedRowSet オブジェクトにキャストできます。
CachedRowSet rs = rsfact.newCachedRowSet();
RowSet には、同時方式の種類、データ ソースの名前、トランザクション アイソレーション レベルなど数多くのプロパティがあります。これらのプロパティを設定して RowSet の動作を決定できます。RowSet の特定の用途に応じて必要なプロパティのみを設定する必要があります。利用可能なプロパティについては、javax.sql.rowset.BaseRowSet クラスの Javadoc を参照してください。
ほとんどのアプリケーションでは、データベースからのデータを RowSet に入力します。RowSet とデータベースとの接続は、以下のいずれかの方法で設定します。
setDataSourceName()
メソッドを使用して、JDBC データ ソースの JNDI 名を指定できます。execute()
および acceptChanges()
を呼び出すと、RowSet でデータ ソースからのデータベース接続が取得され、それが使用されて、データ ソースの接続のプールに戻されます。これは、推奨される方法です。
rs.setDataSourceName(examples-dataSource-demoPool);
execute()
メソッドおよび acceptChanges()
メソッドのパラメータとして渡します。必要に応じて接続を閉じる必要もあります。
//DataSource をルックアップして接続を取得する
ctx = new InitialContext(ht);
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup ("myDS");
conn = ds.getConnection();
//接続を RowSet に渡す
rs.execute(conn);
JDBC データ ソースの詳細については、「DataSource オブジェクトからのデータベース接続の取得」を参照してください。
execute()
および acceptChanges()
を呼び出したときにデータベース接続が作成されます。RowSet では接続を使用し終えるとすぐにその接続が閉じられます。RowSet では execute()
メソッド呼び出しと acceptChanges()
メソッド呼び出しの間、接続は保持されません。
Class.forName("com.pointbase.jdbc.jdbcUniversalDriver");
rs.setUrl("jdbc:pointbase:server://localhost/demo");
rs.setUsername("examples");
rs.setPassword("examples");
rs.execute();
setDataSource()
メソッドで RowSetFactory のデータ ソースのプロパティを設定するのが、推奨される方法です。
//DataSource をルックアップして接続を取得する
ctx = new InitialContext(ht);
javax.sql.DataSource ds = (javax.sql.DataSource) ctx.lookup ("myDS");
//RowSetFactory にデータ ソースのプロパティを設定する
rsfact.setDataSource(ds);
RowSet への「Populating」 (入力) とは、RowSet にデータの行を格納する作業のことをいいます。通常、このデータの取得元はリレーショナル データベースです。データベースからのデータは、以下のいずれかの方法で RowSet に入力できます。
setCommand()
メソッドで SQL コマンドを設定してから、execute()
メソッドでそのコマンドを実行する。
rs.setCommand("SELECT ID, FIRST_NAME, MIDDLE_NAME, LAST_NAME,
PHONE, EMAIL FROM PHYSICIAN");
rs.execute();
populate()
メソッドを使用して入力する。
rs.populate(resultSet);
注意 : ResultSet.TYPE_FORWARD_ONLY
の結果セットを使用している場合、以下の条件で RowSet に入力しようとすると SQLException が送出されます。
RowSet のデータ変更をデータベースとの間で同期するために、RowSet にメタデータを設定することが必要な場合もあります。詳細については、「RowSet に対するデータベース更新用メタデータの設定」を参照してください。
キャッシュされた RowSet に一連のデータ行を入力した後には、結果セットのデータを扱うのとほとんど同じ方法でそのキャッシュ済みのデータを取り扱えます。ただし、データベースに対して変更を行う前には、acceptChanges()
を明示的に呼び出す必要があります。
注意 : RowSet のカラム名やテーブル名に区切り識別子は使用できません。SQL 文の中では、区切り識別子は二重引用符で囲む必要があります。区切り識別子には、SQL 予約語 (USER
や DATE
など) になっているものや、識別子ではない名前になっているものがあります。有効な識別子は必ず文字で始まり、文字、数字、およびアンダースコアのみを使用できます。
RowSet からデータを取得するには、結果セットの場合と同様に getXXX
メソッドを使用します。次に例を示します。
while (rs.next ())
{
int id = rs.getInt (1);
String fname = rs.getString ("FIRST_NAME");
String mname = rs.getString ("MIDDLE_NAME");
String lname = rs.getString ("LAST_NAME"));
}
操作を完了しても変更はデータベースとの間で同期されないことに注意します。変更は RowSet に対してのみ行われます。acceptChanges()
を呼び出して、明示的に変更を同期させる必要があります。詳細については、下記の「RowSet の変更をデータベースとの間で同期する」を参照してください。
RowSet を操作する際、WebLogic Server では内部的に各操作の後で RowSet にライフサイクルのステージが設定され、その後は現在のライフサイクルのステージに基づいて RowSet に対する以降の操作が制限されます。update メソッド群で行の変更を開始したら、必ず updateRow()
または insertRow()
で操作を完了します。完了してはじめて、別の行の操作 (別の行へのカーソルの移動を含む) ができるようになります。RowSet のライフサイクルのステージと、各ステージで許可される操作の詳細については、「RowSet を使用したプログラミング」を参照してください。
行を更新するには、更新する行にカーソルを移動して、その行の個別のカラムに対して updateXXX
メソッドを呼び出してから、updateRow()
を呼び出して操作を完了します。次に例を示します。
rs.first();
rs.updateString(4, "Francis");
rs.updateRow();
注意 : 複数のテーブルの同名のカラムを更新する場合、カラムの参照には Update 文でカラムのインデックス番号を使用する必要があります。
行を挿入するには、新規の挿入行にカーソルを移動してその行のカラムの値を更新してから、insertRow()
を呼び出して RowSet に行を追加します。次に例を示します。
rs.moveToInsertRow();
rs.updateInt(1, 104);
rs.updateString("FIRST_NAME", "Yuri");
rs.updateString("MIDDLE_NAME", "M");
rs.updateString("LAST_NAME", "Zhivago");
rs.updateString("PHONE", "1234567812");
rs.updateString("EMAIL", "Yuri@poet.com");
rs.insertRow();
rs.moveToCurrentRow();
行を挿入した後には、明示的にカーソルを移動する必要があります。カーソルが暗黙的に移動することはありません。
RowSet の行を削除するには、カーソルをその行に移動して deleteRow()
を呼び出します。次に例を示します。
rs.last();
rs.deleteRow();
RowSet の個別の行を変更した後には、acceptChanges()
を呼び出して変更をデータベースに伝播します。次に例を示します。
rs.acceptChanges();
acceptChanges()
を呼び出すと、RowSet では、すでに RowSet で使用されているデータベース接続情報を使用するか (「データベース接続のオプション」を参照)、acceptChanges(connection)
メソッドで渡された接続オブジェクトを使用して、データベースに接続します。1 つまたは複数の行を変更した後に acceptChanges()
を呼び出せます。RowSet に対してすべての変更を行った後に acceptChanges()
を呼び出すと、RowSet からデータベースへの接続が 1 度だけになるのでより効率的です。
WebLogic Server で RowSet を使用する場合、データベースに対する書き込みと読み取りには weblogic.jdbc.rowset.WLSyncProvider
オブジェクトが内部的に使用されます。WLSyncProvider ではデータベースの変更にオプティミスティックな同時実行方式が使用されます。つまり、RowSet への入力時から RowSet のデータの変更がデータベースに伝播されるまでの間に、データベースのデータが別のプロセスによって変更されないと仮定されます。データベースに変更を書き込む前には、WLSyncProvider によってデータベースのデータと RowSet の元の値 (RowSet の作成時または最後の同期の際に RowSet に読み込まれた値) が比較されます。データベースの値になんらかの変更があった場合には javax.sql.rowset.spi.SyncProviderException
が送出され、データベースにはどの変更も書き込まれません。アプリケーションでこの例外を捕捉して、処理方法を決定できます。詳細については、「SyncResolver を使用した SyncProviderException の処理」を参照してください。
WLCachedRowSet
インタフェースは CachedRowSet
インタフェースの拡張で、このインタフェースでオプティミスティックな同時実行性ポリシーを選択できます。詳細については、「オプティミスティックな同時実行性ポリシー」を参照してください。
変更をデータベースに伝播した後には、アプリケーションの環境に応じて RowSet のライフスタイルのステージが「Designing」 (設計) または「Populating」 (入力) に変わります。「Designing」 (設計) ステージの場合、再び使用する前に RowSet に再入力する必要があります。「Populating」 (入力) ステージの場合、現在のデータを持つ RowSet を使用できます。詳細については、「トランザクション完了後の WebLogic RowSet の再利用」を参照してください。
RowSet を再び使用する予定がない場合は、close()
メソッドで閉じる必要があります。次に例を示します。
rs.close();
SQL クエリで RowSet に入力する場合、WebLogic の RowSet 実装では ResultSetMetaData
インタフェースを使用して、自動的に RowSet 内のデータのテーブル名とカラム名が認識されます。ほとんどの場合、RowSet が変更をデータベースに書き戻すために必要な SQL を生成するには、この情報で十分です。ただし一部の JDBC ドライバでは、このクエリで返される行にテーブルおよびカラムのメタデータが含まれません。RowSet のデータ変更をデータベースとの間で同期しようとすると、次のエラーが表示されます。
java.sql.SQLException: Unable to determine the table name for column:
column_name
.Please ensure that you've called WLRowSetMetaData.setTableName to set a table name for this column.
テーブル名がない場合、RowSet は読み込み操作にのみ使用できます。テーブル名をプログラム的に指定しない限り、RowSet では更新を発行できません。また、setKeyColumns()
メソッドによる主キー カラムの設定が必要な場合もあります。次に例を示します。
rs.setTableName(PHYSICIAN);
rs.setKeyColumns(new int[] { 1 });
詳細については、javax.sql.rowset.CachedRowSet
インタフェースの説明を参照してください。
以下の節では、RowSet に対する適切なメタデータの取得または設定に使用できる WebLogic RowSet 拡張について説明します。
SQL クエリで RowSet に入力する場合、通常は execute()
メソッドを使用してクエリを実行し、データを読み込みます。WLCachedRowSet
実装には、関連付けられたテーブルのメタデータも識別するために execute
メソッドを拡張した executeAndGuessTableName
メソッドおよび executeAndGuessTableNameAndPrimaryKeys
メソッドが用意されています。
executeAndGuessTableName
メソッドでは、関連付けられた SQL を解析して、すべてのカラムのテーブル名を、SQL キーワード FROM
に続く最初の語として設定します。
executeAndGuessTableNameAndPrimaryKeys
メソッドでは、SQL コマンドを解析してテーブル名を読み取ってから、java.sql.DatabaseMetaData
を使用して、テーブルの主キーを識別します。
注意 : これらのメソッドは DBMS または JDBC ドライバのサポートに依存しています。すべての DBMS、すべての JDBC ドライバで機能するとは限りません。
WLRowSetMetaData
インタフェースを使用してテーブルおよび主キー情報を手動で設定することもできます。
WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();
// すべてのカラムに 1 つのテーブル名を設定する
metaData.setTableName("employees");
metaData.setTableName("e_id", "employees");
metaData.setTableName("e_name", "employees");
WLRowSetMetaData
インタフェースを使用して主キー カラムを指定することもできます。
metaData.setPrimaryKeyColumn("e_id", true);
詳細については、weblogic.jdbc.rowset.WLRowSetMetaData の Javadoc を参照してください。
WLRowSetMetaData
インタフェースには、更新または削除するテーブルのみを指定するための setWriteTableName
メソッドがあります。このメソッドは通常、複数のテーブルの結合が入力されている RowSet において、1 つのテーブルのみを更新する場合に使用します。書き込みテーブルに属さないカラムは読み込み専用としてマークされます。
たとえば、RowSet に「注文」と「顧客」の結合が含まれるとします。書き込みテーブルを「注文」に設定します。deleteRow を呼び出すと、「注文」の行は削除されますが、「顧客」の行は削除されません。
多くの場合、RowSet の変更をデータベースとの間で同期した後に、その RowSet を現在入力されているデータのまま使用することが必要になるでしょう。そうすることでデータベースとの往復回数が減るため、アプリケーションのパフォーマンスを向上できます。ただし、RowSet とそのデータを再利用する場合、そのデータにさらに変更を加える前に、その RowSet が参加するトランザクションが必ずすべて完了している必要があります。
ローカル トランザクションで RowSet を使用していて、RowSet データの変更をデータベースとの間で同期する前に、接続オブジェクトに autocommit
=true
と設定されている場合、データの同期後に現在の値のまま RowSet を再利用できます。これは、autocommit の設定によってローカル トランザクションがすぐに強制的に完了するためです。RowSet に以降のどのような変更が行われるよりも前に、ローカル トランザクションが必ず完了します。
以下のいずれかの状況で RowSet を使用している場合、すべてのトランザクションが必ず自動的に完了するとは限りません。
これらのいずれかの場合、現在のデータで RowSet を再利用する前に、acceptChanges()
を呼び出してデータベースとの間で変更を同期した後で、tx.commit()
または java.sql.Connection.commit()
の代わりに javax.sql.rowset.CachedRowSet.commit()
を呼び出してトランザクションをコミットします。CachedRowSet.commit()
メソッドには Connection.commit()
メソッドがラップされています。これを使用すると必ずトランザクションが完了され、その後に RowSet を変更できるようになります。
以下の節では、WebLogic Server における標準の FilteredRowSet の使い方について説明します。
FilteredRowSet を使用するとキャッシュされた行のサブセットを取り扱え、データベースに接続されていない状態で行のサブセットを変更できます。フィルタ処理された RowSet とは、分かりやすく言えば、キャッシュされている RowSet の中で、特定の行のみを閲覧、移動、操作できるものをいいます。FilteredRowSet には以下のような特性があります。
javax.sql.rowset.Predicate
オブジェクトで決定され、setFilter()
メソッドで指定される。 javax.sql.rowset.Predicate
インタフェースを実装する必要がある。Predicate インタフェースには public boolean evaluate(RowSet rs)
メソッドがあり、このメソッドで RowSet の各行を評価します。詳細については「FilteredRowSet に対するフィルタの設定」を参照してください。
weblogic.jdbc.rowset.SQLPredicate
クラスという javax.sql.rowset.Predicate
インタフェースの実装が用意されている。このクラスを使用すると、SQL のような WHERE 句の構文を使用して FilteredRowSet のフィルタを定義できます。「SQLPredicate、SQL 方式の RowSet フィルタ」を参照してください。FilteredRowSet の WebLogic 実装では現在、FilteredRowSet にフィルタを 2 回設定すると古いフィルタが新しいフィルタで置き換えられます。JSR-114 にはこの点についてはっきりとした規定がありません。BEA では上記のような動作を setFilter メソッドを実装する適切な方式と判断しました。Sun の参照実装は、これと同じようには動作しません。Sun の実装では RowSet のフィルタされた行がさらにフィルタされます。この場合 2 回目のフィルタを変更して必要なすべての条件をフィルタするようにすると、同じ効果を得られます。
RowSet フィルタを設定または変更する前に RowSet に保留中の変更がある場合、その変更を受け入れる (acceptChanges()
を呼び出す) か、RowSet のデータを変更前の状態に戻す (restoreOriginal()
を呼び出す) 必要があります。WebLogic Server では行われる可能性のある変更を示せるように RowSet 内の移動が認められており、ユーザは RowSet フィルタを変更する前に上記のどちらかのメソッドを呼び出す必要があります。acceptChanges()
ではデータベースへのアクセスが行われ、restoreOriginal()
では行われません。
以下のサンプルに、キャッシュされた RowSet を作成してから WebLogic Server SQLPredicate を使用してフィルタを適用および変更する方法について示します。
コード リスト 6-2 FilteredRowSet のコード サンプル
import javax.sql.rowset.FilteredRowSet;
import weblogic.jdbc.rowset.RowSetFactory;
import weblogic.jdbc.rowset.SQLPredicate;
public class FilteredRowSetDemo {
public static void main (String[] args) {
//「DESIGNING」 (設計) ライフサイクル ステージ - RowSet を作成してプロパティを設定する
try {
//RowSetFactory インスタンスを作成して、このファクトリから
//WLCachedRowSet を作成し FilteredRowSet にキャストする
RowSetFactory rsfact = RowSetFactory.newInstance();
FilteredRowSet rs = rsfact.newCachedRowSet();
//DataSource を介してデータベース アクセスを設定する。
//他のオプションについては、「データベース接続のオプション」を参照
rs.setDataSourceName(examples-dataSource-demoPool);
rs.setCommand("SELECT ID, FIRST_NAME, MIDDLE_NAME, LAST_NAME,
PHONE, EMAIL FROM PHYSICIAN WHERE ID>?");
//「CONFIGURE QUERY」 (クエリのコンフィグレーション) ライフサイクル操作 - クエリ パラメータに値を設定する
rs.setInt(1, 0);
//「POPULATING」 (入力) ライフサイクル ステージ - RowSet に入力するためのコマンドを実行する
rs.execute();
}
//「CONFIGURING METADATA」 (メタデータのコンフィグレーション) - 初めに入力してから、KeyColumn を含むメタデータを設定する
rs.setKeyColumns(new int[] { 1 });
while (rs.next ())
//「移動」操作により RowSet が「MANIPULATING」 (操作) ライフサイクル ステージになる
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
}
}
//RowSet を「DESIGNING」 (設計) または「POPULATING」 (入力) ステージにするために
//変更を受け入れるか restoreOriginal を呼び出す必要がある。
//移動後に RowSet は「MANIPULATING」 (操作) ステージになり
//このライフサイクル ステージではプロパティは変更できない
rs.restoreOriginal();
//フ ィ ル タ を 設 定
//SQLPredicate クラスを使用して SQLPredicate オブジェクトを作成してから
//そのオブジェクトを setFilter メソッドに渡して RowSet をフィルタ処理する
SQLPredicate filter = new SQLPredicate("ID >= 103");
rs.setFilter(filter);
System.out.println("Filtered data: ");
while (rs.next ())
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
System.out.println (" ");
}
//RowSet を「DESIGNING」 (設計) または「POPULATING」 (入力) ライフサイクル ステージにするために
//変更を受け入れるか restoreOriginal を呼び出す必要がある。
//移動後に RowSet は「MANIPULATING」 (操作) ステージになり
//このライフサイクル ステージではプロパティは変更できない
rs.restoreOriginal();
//フ ィ ル タ を 変 更 す る
SQLPredicate filter2 = new SQLPredicate("ID <= 103");
rs.setFilter(filter2);
System.out.println("Filtered data: ");
while (rs.next ())
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
System.out.println (" ");
}
//RowSet を「DESIGNING」 (設計) または「POPULATING」 (入力) ライフサイクル ステージにするために
//変更を受け入れるか restoreOriginal を呼び出す必要がある。
//移動後に RowSet は「MANIPULATING」 (操作) ステージになり
//このライフサイクル ステージではプロパティは変更できない
rs.restoreOriginal();
//フ ィ ル タ を 削 除 す る
rs.setFilter(null);
while (rs.next ())
{
System.out.println ("ID: " +rs.getInt (1));
System.out.println ("FIRST_NAME: " +rs.getString (2));
System.out.println ("MIDDLE_NAME: " +rs.getString (3));
System.out.println ("LAST_NAME: " +rs.getString (4));
System.out.println ("PHONE: " +rs.getString (5));
System.out.println ("EMAIL: " +rs.getString (6));
System.out.println (" ");
}
rs.close();
}
}
標準の FilteredRowSet を使用するには、次のクラスをインポートする必要があります。
javax.sql.rowset.FilteredRowSet;
weblogic.jdbc.rowset.RowSetFactory;
上記のコード サンプルでは、フィルタの作成に weblogic.jdbc.rowset.SQLPredicate
クラスも使用されています。アプリケーションでは、weblogic.jdbc.rowset.SQLPredicate
クラスを使用することも、独自のフィルタ クラスを作成することも可能です。詳細については「FilteredRowSet に対するフィルタの設定」を参照してください。
RowSet はファクトリ インタフェースから作成されます。WebLogic Server で FilteredRowSet を作成するには、主に以下の手順に従います。
RowSetFactory rsfact = RowSetFactory.newInstance();
javax.sql.rowset.FilteredRowSet
オブジェクト型にキャストします。デフォルトでは WebLogic newCachedRowSet()
RowSetFactory メソッドで WLCachedRowSet
オブジェクトが作成されます。このオブジェクトをそのまま使用することもできますが、標準の FilteredRowSet
オブジェクトを使用する場合は、WLCachedRowSet オブジェクトを FilteredRowSet オブジェクトにキャストできます。次に例を示します。
FilteredRowSet rs = rsfact.newCachedRowSet();
FilteredRowSet のプロパティのオプションは CachedRowSet のオプションと同じです。「CachedRowSet のプロパティの設定」を参照してください。
FilteredRowSet のデータベース接続のオプションは CachedRowSet のオプションと同じです。「データベース接続のオプション」を参照してください。
FilteredRowSet のデータ入力のオプションは CachedRowSet のオプションと同じです。「CachedRowSet への入力」を参照してください。
RowSet のデータ変更をデータベースとの間で同期するために、RowSet にメタデータを設定することが必要な場合もあります。詳細については、「RowSet に対するデータベース更新用メタデータの設定」を参照してください。
FilteredRowSet の行をフィルタするには、setFilter
メソッドを呼び出して、Predicate (フィルタ) オブジェクトをこのメソッドのパラメータとして渡します。Predicate オブジェクトは javax.sql.rowset.Predicate
インタフェースを実装するクラスのインスタンスです。FilteredRowSet の WebLogic 実装では、独自のフィルタを定義することも、weblogic.jdbc.rowset.SQLPredicate
クラスのインスタンスを使用することもできます。
FilteredRowSet 用のフィルタを定義する場合、主に以下の手順に従います。
コード リスト 6-3 に、javax.sql.rowset.Predicate
インタフェースを実装するクラスのサンプルを示します。このサンプルでは、カラムの値の大文字と小文字を区別しないバージョンを評価するフィルタを作成することができるクラスが示されます。コード リスト 6-4 に、フィルタ条件を判断するクラスのインスタンスを作成してから、FilteredRowSet 用のフィルタとしてフィルタ オブジェクトを設定するコードを示します。
コード リスト 6-3 javax.sql.rowset.Predicate を実装するフィルタ クラス
package examples.jdbc.rowsets;
import javax.sql.rowset.Predicate;
import javax.sql.rowset.CachedRowSet;
import javax.sql.RowSet;
import java.sql.SQLException;
public class SearchPredicate implements Predicate, java.io.Serializable {
private boolean DEBUG = false;
private String col = null;
private String criteria = null;
//カラムと値の大文字と小文字を区別しない比較を作成するコンストラクタ
public SearchPredicate(String col, String criteria) {
this.col = col;
this.criteria = criteria;
}
public boolean evaluate(RowSet rs) {
CachedRowSet crs = (CachedRowSet)rs;
boolean bool = false;
try {
debug("evaluate(): "+crs.getString(col).toUpperCase()+" contains "+
criteria.toUpperCase()+" = "+
crs.getString(col).toUpperCase().contains(criteria.toUpperCase()));
if (crs.getString(col).toUpperCase().contains(criteria.toUpperCase()))
bool = true;
} catch(Throwable t) {
t.printStackTrace();
throw new RuntimeException(t.getMessage());
}
return bool;
}
public boolean evaluate(Object o, String s) throws SQLException {
throw new SQLException("String evaluation is not supported.");
}
public boolean evaluate(Object o, int i) throws SQLException {
throw new SQLException("Int evaluation is not supported.");
}
}
コード リスト 6-4 FilteredRowSet 用のフィルタを設定するコード
SearchPredicate pred = new SearchPredicate(ROWSET_LASTNAME, lastName);
rs.setFilter(pred);
Weblogic Server には javax.sql.rowset.Predicate
インタフェースを実装する weblogic.jdbc.rowset.SQLPredicate
クラスが用意されています。SQLPredicate
クラスを使用すると、SQL のような WHERE 句の構文を使用するフィルタを定義して RowSet の行をフィルタできます。次に例を示します。
SQLPredicate filter = new SQLPredicate("ID >= 103");
rs.setFilter(filter);
詳細については、「SQLPredicate、SQL 方式の RowSet フィルタ」を参照してください。
FilteredRowSet のデータの操作は CachedRowSet のデータの操作とほとんど同様です。ただし、行を挿入したり更新したりする場合には、必ずフィルタ条件の範囲内で変更を行って、操作した行が表示される行の集合に残るようにします。たとえば、RowSet のフィルタで ID カラムの値が 105 より小さい行のみを表示できる場合、ID カラムの値が 106 の行を挿入しようとしたり、ID の値を 106 に更新しようとしたりすると、操作は失敗して SQLException が送出されます。
データ操作の詳細については、「CachedRowSet のデータの操作」を参照してください。
WebRowSet は、RowSet を XML フォーマットで読み書きできるキャッシュされた RowSet です。WebRowSet には以下のような特性があります。
readXml(java.io.InputStream iStream)
メソッドを使用して XML ソースから RowSet に入力する。writeXml(java.io.OutputStream oStream)
メソッドを使用してデータおよびメタデータを XML で書き込み、他のアプリケーション コンポーネントで使用できるように、またはリモート クライアントに送信できるようにする。詳細については、Sun の Web サイト (http://java.sun.com/products/jdbc/download.html) および javax.sql.rowset.WebRowSet インタフェースの Javadoc を参照してください。
注意 : WebLogic Server では RowSet について 2 つのスキーマがサポートされています。1 つは標準 WebRowSet 用、もう 1 つは WLCachedRowSet 用です。これは、JSR-114 の最終仕様より前に実装されたものです。
JoinRowSet とは、SQL JOIN によって単一の RowSet に結合された、多数の接続されていない RowSet オブジェクトです。JoinRowSet には以下のような特性があります。
addRowSet(javax.sql.RowSet[] rowset,java.lang.String[] columnName);
CROSS_JOIN
FULL_JOIN
INNER_JOIN
LEFT_OUTER_JOIN
RIGHT_OUTER_JOIN
JoinRowSet の詳細については、javax.sql.rowset.Joinable および JoinRowSet インタフェースの Javadoc を参照してください。
JDBCRowSet は ResultSet オブジェクトのラッパーで、これによって結果セットを JavaBean コンポーネントとして使用できるようになります。JDBCRowSet は、接続されている RowSet です。これ以外の種類の RowSet はすべて接続されていない RowSet です。
詳細については、javax.sql.rowset.JdbcRowSet インタフェースの Javadoc を参照してください。
acceptChanges()
を呼び出して RowSet の変更をデータベースに伝播する場合、WebLogic Server では RowSet の元のデータ (最後の同期以降のデータ) が、データベースのデータとオプティミスティックな同時実行性ポリシーに基づいて比較されます。データの変更が検出されると、javax.sql.rowset.spi.SyncProviderException
が送出されます。デフォルトでは、アプリケーションでは何も行う必要はありませんが、RowSet の変更はデータベースと同期されません。こうした例外を処理してシステムに適した方法でデータ変更を行うように、アプリケーションを設計できます。
注意 : javax.sql.rowset.CachedRowSets
については、RowSet のすべての行にあるすべての元の値が、対応するデータベースの行と比較されます。weblogic.jdbc.rowset.WLCachedRowSet
、または他の WebLogic 拡張の RowSet では、オプティミスティックな同時実行性の設定に基づいてデータが比較されます。詳細については、「オプティミスティックな同時実行性ポリシー」を参照してください。
SyncProviderException
を処理する主な手順は次のとおりです。
nextConflict()
または任意の他の移動用メソッドを使用して、衝突まで移動します。「SyncResolver オブジェクト内の移動」を参照してください。setResolvedValue()
(RowSet に値を設定するメソッド) で設定します。「RowSet データの同期の衝突に対する解決後の値の設定」を参照してください。rowset.acceptChanges()
を呼び出し、新しい解決後の値を使用してデータベースとの間で変更を同期します。「変更の同期」を参照してください。SyncResolver および SyncProviderException
の詳細については、RowSet の仕様または SyncResolver
インタフェースの Javadoc を参照してください。
注意 : SyncProviderException の解決を開始する前に、他のどのプロセスもデータを更新することのないようにします。
表 6-2 に、RowSet からデータベースにデータの変更を同期する際に起こる、衝突状況の種類について示します。
コード リスト 6-5 に、RowSet とデータベースの間で衝突している値を SyncResolver を使って解決する方法についての要約されたサンプルを示します。このサンプルでは、衝突のある SyncResolver の各行について、認識されている名前を持つカラムの値をチェックします。このサンプルの詳細については、サンプルの後の節で説明します。
コード リスト 6-5 SyncResolver の要約済みコード サンプル
try {
rs.acceptChanges();
} catch (SyncProviderException spex) {
SyncResolver syncresolver = spex.getSyncResolver();
while (syncresolver.nextConflict()) {
int status = syncresolver.getStatus();
int rownum = syncresolver.getRow();
rs.absolute(rownum);
//各カラムの null をチェックする。
//衝突を書き出す。
//解決後の値をこのサンプル用のデータベースの値に設定する。
//データベースで削除された行についての例外を処理する
try {
Object idConflictValue = syncresolver.getConflictValue("ID");
if (idConflictValue != null) {
System.out.println("ID value in db: " + idConflictValue);
System.out.println("ID value in rowset: " + rs.getInt("ID"));
syncresolver.setResolvedValue("ID", idConflictValue);
System.out.println("Set resolved value to " + idConflictValue);
}
else {
System.out.println("ID: NULL - no conflict");
}
} catch (RowNotFoundException e) {
System.out.println("An exception was thrown when requesting a ");
System.out.println("value for ID. This row was ");
System.out.println("deleted in the database.");
}
. . .
}
try {
rs.acceptChanges();
} catch (Exception ignore2) {
}
}
SyncProviderException
を処理するために、例外を捕捉してそこから SyncResolver
オブジェクトを取得できます。次に例を示します。
try {
rowset.acceptChanges();
} catch (SyncProviderException spex) {
SyncResolver syncresolver = spex.getSyncResolver();
. . .
}
SyncResolver は、SyncResolver
インタフェースを実装する RowSet です。SyncResolver オブジェクトには、元の RowSet のすべての行に対応する行が含まれます。衝突していない値については、SyncResolver での値は null になります。衝突している値については、データベースの現在の値が値として格納されます。
SyncResolver オブジェクトを使用すると、すべての衝突に移動して、衝突している各値に適切な値を設定できます。SyncResolver インタフェースには nextConflict()
メソッドと previousConflict()
メソッドが含まれており、これらを使用して null
以外の衝突している値を持つ SyncResolver 内で、直接次の行に移動できます。SyncResolver オブジェクトは RowSet なので、SyncResolver の任意の行へのカーソル移動には、すべての RowSet 移動用メソッドも使用できます。ただし、nextConflict()
メソッドおよび previousConflict()
メソッドを使用すると、衝突している値のない行を簡単にスキップできます。
衝突している行にカーソルを移動した後には、各カラムの値を getConflictValue()
メソッドでチェックして、RowSet 内の値と衝突しているデータベース内の値を検索してから、それらの値を比較して衝突の処理方法を決定する必要があります。値が衝突していない行の場合、戻り値として null
が返されます。行がデータベースでは削除されていた場合、戻り値はなく、例外が送出されます。
注意 : WebLogic の RowSet 実装では、データベースの行の任意の値と、RowSet の作成時または最後の同期時に RowSet に読み込まれた値が異なる場合、値の衝突が発生します。
RowSet とデータベースの値を比較するコードのサンプルを以下に示します。
for (int i = 1; i <= colCount; i++) {
if (syncresolver.getConflictValue(i) != null) {
rsValue = rs.getObject(i);
resolverValue = syncresolver.getConflictValue(i);
// RowSet および SyncResolver の値を比較して
// どちらを解決後の値 (永続化する値) とするかを決定する
データベースに永続化するための適切な値を設定するには、setResolvedValue()
を呼び出します。次に例を示します。
syncresolver.setResolvedValue(i, resolvedValue);
setResolvedValue()
メソッドでは以下の変更が行われます。
setResolvedValue()
を呼び出すと、元の値がデータベースの現在の値になります。 SyncResolver で衝突している値を解決した後には、変更をデータベースとの間で同期する必要があります。これを行うには、rowset.acceptChanges()
をもう一度呼び出します。acceptChanges()
呼び出しでは SyncResolver オブジェクトがクローズされ、同期の完了後にデータベースのロックが解放されます。
WLCachedRowSet は CachedRowSet、FilteredRowSet、WebRowSet、および SortedRowSet の拡張です。WLCachedRowSet には以下のような特性があります。
詳細については、weblogic.jdbc.rowset.WLCachedRowSet インタフェースの Javadoc を参照してください。
RowSet は 1 つのスレッドでのみ使用できます。複数のスレッドで共有することはできません。SharedRowSet は CachedRowSet を拡張したもので、元の CachedRowSet のデータに基づいて、他のスレッドで使用する CachedRowSet を追加作成できます。SharedRowSet には以下のような特性があります。
SharedRowSet を作成するには、WLCachedRowSet インタフェースの createShared()
メソッドを使用して、その結果を WLCachedRowSet 型にキャストします。次に例を示します。
WLCachedRowSet sharedrowset = (WLCachedRowSet)rowset.createShared();
SortedRowSet は CachedRowSet を拡張して、CachedRowSet の行をアプリケーションで提供される Comparator オブジェクトに基づいてソートできるようにしたものです。SortedRowSet には以下のような特性があります。
javax.sql.rowset.Predicate
オブジェクトではなく java.util.Comparator
オブジェクトに基づきます。java.util.Comparator
を実装する SQLComparator オブジェクトが用意されている。これを使用して、ソート条件として使うカラムのリストを渡すことで、SortedRowSet の行をソートできます。次に例を示します。
rs.setSorter(new weblogic.jdbc.rowset.SQLComparator("columnA,columnB,columnC"));
詳細については、Javadocs で以下について参照してください。
Weblogic Server には javax.sql.rowset.Predicate
インタフェースの実装である weblogic.jdbc.rowset.SQLPredicate
クラスが用意されています。SQLPredicate
クラスを使用すると、SQL のような WHERE 句の構文を使用して FilteredRowSet のフィルタを定義できます。
SQLPredicate クラスの文法は JMS セレクタの文法から借用されたもので、SQL SELECT 文の WHERE 句の文法とよく似ています。
(colA + ColB) >=100.
//フ ィ ル タ を 設 定
//SQLPredicate クラスを使用して SQLPredicate オブジェクトを作成してから
//そのオブジェクトを setFilter メソッドに渡して RowSet をフィルタ処理する
SQLPredicate filter = new SQLPredicate("ID >= 103");
rs.setFilter(filter);
詳細については、weblogic.jdbc.rowset.SQLPredicate クラスの Javadoc を参照してください。
ほとんどの場合、RowSet へのデータの入力とデータベースの更新は別々のトランザクションで発生します。データベース内の基底のデータは 2 つのトランザクションの間に変更される可能性があります。WebLogic Server の RowSet 実装 (WLCachedRowSet) では、オプティミスティックな同時実行性の制御を使用して、データベースの一貫性を確保します。
オプティミスティックな同時実行性の場合、RowSet は複数のユーザが同じデータを同時に変更する可能性は低いという前提で動作します。そのため、接続されていない RowSet モデルの一端として、RowSet ではデータベース リソースがロックされません。ただし、データベースに変更を書き込む前に、データベース内の変更予定のデータが、そのデータが RowSet に読み込まれたときから変更されていないことを RowSet でチェックする必要があります。
RowSet から発行される UPDATE 文と DELETE 文には、データベース内のデータを、RowSet の入力時に読み込まれたデータに照らして検証するための WHERE 句が含まれます。RowSet ではデータベース内の基底のデータが変更されたことが検出されると OptimisticConflictException
が発行されます。アプリケーションではこの例外を捕捉して処理方法を決定できます。一般的には、アプリケーションで、変更されたデータを更新してユーザに再度提示します。
WLCachedRowSet 実装には複数のオプティミスティックな同時実行性ポリシーが用意されています。これらのポリシーによって、基底のデータベースのデータを検証するために RowSet から発行される SQL が決まります。
これらのポリシーの違いを例示するために、以下のような内容の例を使用します。
CREATE TABLE employees (
e_id integer primary key,
e_salary integer,
e_name varchar(25)
);
e_id = 1, e_salary = 10000, and e_name = 'John Smith'
以下に示すオプティミスティックな同時実行性ポリシーのそれぞれの例では、RowSet に従業員テーブルからこの行が読み込まれ、John Smith の給与が 20000 に設定されます。続いて、オプティミスティックな同時実行性ポリシーが RowSet から発行される SQL コードにどのように影響するかが示されます。
デフォルトでは、RowSet のオプティミスティックな同時実行性制御ポリシーは VERIFY_READ_COLUMNS です。RowSet から UPDATE または DELETE が発行されるときに、データベースから読み込まれたすべてのカラムが WHERE 句に含まれます。これによって、RowSet に最初に読み込まれたすべてのカラムの値について変更されてないかどうかが検証されます。
UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_salary=10000 AND e_name = 'John Smith';
VERIFY_MODIFIED_COLUMNS ポリシーでは、主キー カラムと更新されるカラムのみが WHERE 句に含まれます。アプリケーションで更新されるカラムの一貫性だけを考慮する場合に便利です。データを読み込んだ後に更新の対象外のカラムが変更されていても、この更新をコミットできます。
UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_salary=10000
e_id
カラムは主キー カラムなので含まれています。e_salary
カラムは更新されるカラムなので、同様に含まれています。e_name
カラムは読み込まれただけなので、検証されません。
VERIFY_SELECTED_COLUMNS では、主キー カラムと指定するカラムが WHERE 句に含まれます。
WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();
metaData.setOptimisticPolicy(WLRowSetMetaData.VERIFY_SELECTED_COLUMNS);
// e_salary カラムのみを検証する
metaData.setVerifySelectedColumn("e_salary", true);
metaData.acceptChanges();
UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_salary=10000
e_id
カラムは主キー カラムなので含まれています。e_salary
カラムは選択されたカラムなので、同様に含まれています。
VERIFY_NONE ポリシーでは、主キー カラムのみが WHERE 句に含まれます。データベース データに対して追加で検証は行われません。
UPDATE employees SET e_salary = 20000 WHERE e_id = 1
VERIFY_AUTO_VERSION_COLUMNS では、主キー カラムと、別個のバージョン カラムが WHERE 句に含まれます。RowSet では更新の一環としてバージョン カラムの自動的なインクリメントも行われます。このバージョン カラムのデータ型は integer でなければなりません。データベース スキーマを更新して、別個のバージョン カラム (e_version
) を含める必要があります。例では、このカラムの現在の値が 1 であると仮定します。
metaData.setOptimisticPolicy(WLRowSetMetaData.
VERIFY_AUTO_VERSION_COLUMNS);
metaData.setAutoVersionColumn("e_version", true);
metaData.acceptChanges();
UPDATE employees SET e_salary = 20000, e_version = 2
WHERE e_id = 1 AND e_version = 1
e_version
カラムは SET 句で自動的にインクリメントされます。WHERE 句は主キー カラムとバージョン カラムを検証しています。
VERIFY_VERSION_COLUMNS の場合、RowSet では主キー カラムと、別個のバージョン カラムがチェックされます。RowSet では更新の一環としてバージョン カラムはインクリメントされません。データベース スキーマを更新して、別個のバージョン カラム (e_version
) を含める必要があります。例では、このカラムの現在の値が 1 であると仮定します。
metaData.setOptimisticPolicy(WLRowSetMetaData.VERIFY_VERSION_COLUMNS);
metaData.setVersionColumn("e_version", true);
metaData.acceptChanges();
UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_version = 1
WHERE 句では主キー カラムとバージョン カラムが検証されます。RowSet でバージョン カラムがインクリメントされないため、この処理はデータベースで行う必要があります。一部のデータベースでは、行の更新時に自動的にインクリメントするバージョン カラムを提供しています。データベース トリガを使用してこのタイプの更新を処理することもできます。
オプティミスティックなポリシーでは、変更する行に対する UPDATE 文と DELETE 文のみが検証されます。読み込み専用の行はデータベースに照らして検証されません。
ほとんどのデータベースでは WHERE 句での BLOB または CLOB カラムの使用が許可されていないため、RowSet では BLOB または CLOB カラムの検証はできません。
RowSet に複数のテーブルが含まれる場合、RowSet では更新されたテーブルのみが検証されます。
デフォルトの VERIFY_READ_COLUMNS では、パフォーマンスを多少犠牲にして、強力なレベルの一貫性が提供されます。最初に読み込まれたすべてのカラムをデータベースに送信したり、データベースと比較したりする必要があるため、このポリシーでは多少のオーバーヘッドが追加で発生します。VERIFY_READ_COLUMNS は強力なレベルの一貫性が必要な場合に適しています。バージョン カラムを含めるようにデータベース テーブルを変更することはできません。
VERIFY_SELECTED_COLUMNS は、開発者が検証を完全に制御する必要があり、アプリケーションに固有の知識を使用して SQL を微調整する場合に便利です。
VERIFY_AUTO_VERSION_COLUMNS では、VERIFY_READ_COLUMNS と同じレベルの一貫性が提供されますが、integer 型の 1 つのカラムを比較するだけで済みます。このポリシーではバージョン カラムのインクリメントも行われるため、データベースの設定が若干必要です。
VERIFY_VERSION_COLUMNS は、最高レベルのパフォーマンスと一貫性が必要なプロダクション システムにお勧めします。VERIFY_AUTO_VERSION_COLUMNS と同様に、高いレベルの一貫性が提供されますが、データベースで 1 つのカラムの比較が行われるだけです。VERIFY_VERSION_COLUMNS では、データベースでバージョン カラムのインクリメントを行う必要があります。一部のデータベースでは、更新時に自動的にインクリメントするカラム タイプを提供していますが、この動作はデータベース トリガを使用して実装することもできます。
VERIFY_MODIFIED_COLUMNS と VERIFY_NONE では一貫性が確保される程度は低下しますが、オプティミスティックな衝突が起きる可能性も少なくなります。高レベルなデータの一貫性の必要性よりも、パフォーマンスや衝突の回避の方が重要な場合は、これらのポリシーを検討します。
RowSet を使用する場合は以下のパフォーマンス オプションを検討します。
RowSet 実装では JDBC のバッチ処理もサポートされています。各 SQL 文を JDBC ドライバに個々に送信する代わりに、バッチ処理では文の集合を 1 つの一括処理として JDBC ドライバに送信します。バッチ処理はデフォルトで無効になっていますが、一般に 1 つのトランザクションで多数の更新が発生する場合にパフォーマンスが向上します。アプリケーションとデータベースに対してこのオプションを有効および無効に設定して、ベンチマークを実行してみるとよいでしょう。
WLCachedRowSet インタフェースには、INSERT、DELETE、および UPDATE 文のバッチ処理を制御するための setBatchInserts(boolean)
、setBatchDeletes(boolean)
、および setBatchUpdates(boolean)
メソッドがあります。
注意 : setBatchInserts
、setBatchDeletes
、setBatchUpdates
メソッドは、acceptChanges
メソッドを呼び出す前に呼び出す必要があります。
WLCachedRowSet はオプティミスティックな同時実行性制御に依存しているため、更新または削除コマンドが成功したか、オプティミスティックな衝突が発生したかを判別する必要があります。WLCachedRowSet 実装では、文によって更新された行の数についての JDBC ドライバの報告に基づいて、衝突が発生したかどうかを判別します。更新された行が 0 の場合、WLCachedRowSet では衝突が発生したと認識されます。
Oracle JDBC ドライバではバッチ更新が実行されると java.sql.Statement.SUCCESS_NO_INFO
が返されるため、RowSet 実装では衝突が発生したかどうかを判別するために戻り値を使用できません。
バッチ処理が Oracle データベースで使用されることが RowSet で検出された場合、バッチ処理の動作は自動的に変更されます。
バッチ更新は正常に実行されますが、RowSet では特別な SELECT クエリが発行され、バッチ更新でオプティミスティックな衝突が発生したかどうかがチェックされます。
SELECT 検証クエリの後でバッチ削除を実行するよりも効率的なため、バッチ削除ではグループ削除が使用されます。
複数の行を削除する場合、RowSet では通常、削除する行ごとに DELETE 文が発行されます。グループ削除を有効にした場合、RowSet では削除する行を含む WHERE 句が指定された DELETE 文が 1 つだけ発行されます。
たとえば、テーブルから 3 人の従業員を削除する場合、通常であれば RowSet から次のように発行されます。
DELETE FROM employees WHERE e_id = 3 AND e_version = 1;
DELETE FROM employees WHERE e_id = 4 AND e_version = 3;
DELETE FROM employees WHERE e_id = 5 AND e_version = 10;
グループ削除を有効にした場合、RowSet から次のように発行されます。
DELETE FROM employees
WHERE e_id = 3 AND e_version = 1 OR
e_id = 4 AND e_version = 3 OR
e_id = 5 AND e_version = 10;
WLRowSetMetaData.setGroupDeleteSize
を使用すると、1 つの DELETE 文に含まれる行の数を決定できます。デフォルト値は 50 です。
![]() ![]() |
![]() |
![]() |