ナビゲーションをスキップ

WebLogic JDBC プログラマーズ ガイド

  前 次 前/次ボタンと目次ボタンとの区切り線 目次  

WebLogic Server における RowSet の使い方

この節では、WebLogic Server での JDBC RowSet の使い方に関する以下の情報を示します。

 


RowSet について

RowSet は java.sql.ResultSet インタフェースに対する JDBC 2.0 の拡張機能です。RowSet の WebLogic Server 実装では、切断された RowSet を提供します。このモデルでは、データベースから RowSet オブジェクトを取得すると、データベース カーソルと接続は直ちに解放されます。RowSet はデータベースから切断されており、キャッシュされたデータに対して ResultSet インタフェースを提供します。ユーザはメモリ内の RowSet の読み込み、変更、削除または新しい行の挿入を行うことができます。acceptChanges が呼び出されると、RowSet はメモリ内のすべての更新を取り出してデータベースに書き戻します。

ほとんどの場合、RowSet データの取得とデータベースの更新は別々のトランザクションで発生します。RowSet 実装では、オプティミスティックな同時実行性の制御を使用して、データベースの一貫性を保証します。

WebLogic Server の RowSet 実装では、RowSet を RMI パラメータまたは戻り値として送信できるように、java.io.Serializable を実装および拡張しています。たとえば、EJB メソッドはデータベース クエリから RowSet を取得して、その RowSet をクライアントに返すことができます。

RowSet では、状態とメタデータを XML フォーマットで読み書きすることもできます。RowSet メタデータは XML スキーマ ドキュメントとして記述され、RowSet データはそのスキーマに準拠する XML ドキュメントとして記述されます。RowSet のメタデータやキャッシュされたデータを XML ドキュメントから取得することもできます。

注意 : クライアントサイド アプリケーションで RowSet を使用する際、サーバとクライアントの両方の CLASSPATH に、同一の JDBC ドライバ クラスを指定する必要があります。ドライバ クラスが一致していないと、java.rmi.UnmarshalException 例外が送出される場合があります。

 


RowSet の作成

RowSet はファクトリ インタフェースから作成されます。

import weblogic.jdbc.rowset.RowSetFactory;
import weblogic.jdbc.rowset.WLCachedRowSet;
RowSetFactory factory = RowSetFactory.newInstance();
WLCachedRowSet rowSet = factory.newCachedRowSet();

 


RowSet のデータの操作

以降の節では、RowSet の取得方法、RowSet 内のデータの操作方法、および変更をデータベースにフラッシュする方法について説明します。

注意 : RowSet のカラムまたはテーブルに区切り識別子は使用できません。SQL 文の中では、区切り識別子は二重引用符で囲む必要があります。区切り識別子には、SQL 予約語 (USERDATE など) になっているものや、識別子ではない名前になっているものがあります。有効な識別子は文字で始まり、文字、数字、およびアンダースコアだけを使用する必要があります。

RowSet の取得

RowSet オブジェクトを作成すると、そのキャッシュにデータを格納できます。RowSet を取得すると、RowSet はデータベースからは切断されて、メモリ キャッシュとして機能します。RowSet のキャッシュにデータを格納するための 3 つのメソッド ソースがあります。

既存の ResultSet から RowSet を取得する

RowSet は既存の JDBC ResultSet から取得できます。この方法は、データをストアド プロシージャから読み込む場合、またはデータをロードするための JDBC コードがすでに存在している場合に一般的です。RowSet は populate メソッドを呼び出すことでロードできます。

rowSet.populate(myResultSet);

DataSource およびクエリから RowSet を取得する

データベース接続情報と SQL クエリを提供することで RowSet を取得できます。最初に、JDBC 接続を取得するために必要な情報を CachedRowSet に提供します。これを行うには、javax.sql.DataSource オブジェクト、DataSource JNDI 名、または JDBC ドライバの URL を指定します。JDBC 接続を取得するための標準の JDBC 2.0 メソッドであるため、DataSource API をお勧めします。また、DataSource API で取得した接続だけが XA/2PC トランザクションに参加できます。

rowSet.setDataSourceName("myDataSource");

必要に応じて、setUsername および setPassword メソッドを使用して、WebLogic Server の DataSource にアクセスするために必要な資格を設定できます。

rowSet.setUsername("weblogic");
rowSet.setPassword("weblogic");

次に、データベースのロードに使用する SQL クエリを指定します。たとえば、次のクエリでは給与が 50000 以上のすべての従業員が含まれる RowSet を取得します。

rowSet.setCommand("select e_name, e_id from employees WHERE e_salary > ?");
rowSet.setInt(1, 50000);

最後に、指定されたクエリを実行してデータを含む RowSet をロードする execute メソッドを実行します。execute メソッドは JDBC 接続を閉じます。RowSet はオープン カーソルまたはデータベースへの接続を保持しません。

rowSet.execute();

RowSet からのデータの取得

RowSet は ResultSet インタフェースを拡張しているので、データを取得するためのすべての ResultSet メソッドを継承しています。ResultSet と同じように、next() メソッドを使用して RowSet で処理を繰り返すことができます。RowSet からデータを読み込むには getXXX メソッドを使用できます。

while(rowSet.next()) {
String name = rowSet.getString("e_name");
int id = rowSet.getInt("e_id");
System.out.println("Read name: "+name+ " id: "+id);
}
while(rowSet.next()) {
String name = rowSet.getString("e_name");
int id = rowSet.getInt("e_id");
  System.out.println("Read name: "+name+ " id: "+id);
}

RowSet のデータの更新

RowSet ではデータを更新するために ResultSet updateXXX メソッドを使用します。

RowSet の更新はメモリのみに保持されることを理解しておくことが重要です。更新は acceptChanges メソッドを呼び出すときにだけデータベースに書き戻されます。

// rowSet の最初に戻る
rowSet.beforeFirst();
while(rowSet.next()) {
String name = rowSet.getString("e_name");
// 大文字に変換する
name = name.toUpper();
rowSet.updateString("e_name", name);
rowSet.updateRow();
}
// acceptChanges を呼び出して、メモリ内のすべての更新をデータベースに書き込む
rowSet.acceptChanges();

注意 : next メソッドで RowSet のカーソルを移動する前に、RowSet.updateRow または RowSet.cancelRowUpdates を呼び出す必要があります。

RowSet からのデータの削除

行の削除は行の更新と非常に似ています。deleteRow() メソッドは削除する行にマークを付けます。acceptChanges メソッドを呼び出すと、RowSet は適切な SQL を呼び出して選択された行を削除します。

// rowSet の最初に戻る
rowSet.beforeFirst();
while(rowSet.next()) {
  String name = rowSet.getString("e_name");
  if ("Rob".equals(name)) {
rowSet.deleteRow();
}
}
// acceptChanges を呼び出すと、メモリ内のすべての削除が
// データベースに書き込まれる
rowSet.acceptChanges();

RowSet へのデータの挿入

ResultSet のように、RowSet には行の挿入に関する特別な概念があります。データを挿入するには、moveToInsertRow を呼び出してから、行内の値を更新します。更新が行われたことを示すために insertRow メソッドが呼び出されます。別の行を挿入することも、moveToCurrentRow を呼び出して読み込みデータに戻ることもできます。acceptChanges を呼び出すと、挿入されたすべての行がデータベースに送信されます。

rowSet.moveToInsertRow();
rowSet.updateString("e_name", "Seth");
rowSet.updateInt("e_id", 2);
rowSet.insertRow();
rowSet.updateString("e_name", "Matt");
rowSet.updateInt("e_id", 3);
rowSet.insertRow();
rowSet.moveToCurrentRow();
// データベースに SQL INSERT を発行する
rowSet.acceptChanges();

データベースへの変更のフラッシュ

RowSet はデータベース キャッシュのように機能し、RowSet のすべての更新はメモリ内で発生します。これらの変更をデータベースにフラッシュするには、acceptChanges メソッドを呼び出します。

RowSet の acceptChanges メソッドは、DataSource または接続情報を使用してデータベース接続を取得します。次に、メモリ内で行われたすべての INSERT、UPDATE、または DELETE 文をデータベースに対して発行します。

RowSet はデータベースから切断されていて、ロックしたりデータベース リソースを保持したりしていないため、RowSet の取得以降の変更を、データベース内の基底のデータに対して行うことができます。RowSet 実装では、古いデータがないかチェックするために、UPDATE 文および DELETE 文に対してオプティミスティックな同時実行性制御を使用します。詳細については、「オプティミスティックな同時実行性ポリシー」を参照してください。

 


RowSet メタ データ

RowSet API には、関連付けられた javax.sql.RowSetMetaData オブジェクトにアクセスするための getMetaData メソッドがあります。WLCachedRowSet 実装では、標準の RowSetMetaData を追加機能によって拡張した WLRowSetMetaData インタフェースを提供します。

次のようにメタデータにアクセスできます。

WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();

 


オプティミスティックな同時実行性ポリシー

ほとんどの場合、データを含む RowSet の取得とデータベースの更新は別々のトランザクションで発生します。データベース内の基底のデータは 2 つのトランザクションの間に変更できます。WebLogic Server RowSet 実装では、オプティミスティックな同時実行性の制御を使用して、データベースの一貫性を保証します。

オプティミスティックな同時実行性の場合、RowSet は複数のユーザが同じデータを同時に変更する可能性は低いという前提で動作します。そのため、切断された RowSet モデルの一環として、RowSet はデータベース リソースをロックしません。ただし、データベースに変更を書き込む前に、RowSet はデータベース内の変更予定のデータが、そのデータを RowSet に読み込んで以来、変更されていないことを確認する必要があります。

RowSet が発行する UPDATE 文と DELETE 文には、データベース内のデータを、RowSet の取得時に読み込まれたデータに対して検証するための WHERE 句が含まれています。RowSet はデータベース内の基底のデータが変更されたことを検出すると OptimisticConflictException を発行します。アプリケーションはこの例外を捕捉して処理方法を決定することができます。一般に、アプリケーションは変更されたデータを更新してユーザに再度提示します。

WLCachedRowSet 実装には複数のオプティミスティックな同時実行性ポリシーが用意されています。このポリシーによって、基底のデータベース データを検証するために RowSet が発行する SQL が決まります。

これらのポリシーの違いを例示するために、以下のような内容の例を使用します。

以下に示すオプティミスティックな同時実行性ポリシーのそれぞれの例では、RowSet は従業員テーブルからこの行を読み込んで、John Smith の給与を 20000 に設定します。次に、オプティミスティックな同時実行性ポリシーが RowSet によって発行される SQL コードにどのように影響するかを示します。

VERIFY_READ_COLUMNS

デフォルトでは、RowSet のオプティミスティックな同時実行性制御ポリシーは VERIFY_READ_COLUMNS です。RowSet が UPDATE または DELETE を発行するときに、データベースから読み込まれたすべてのカラムが WHERE 句に含まれます。この場合、RowSet に最初に読み込まれたすべてのカラムの値が変更されてないことを検証します。

例では、RowSet は次のように発行します。

UPDATE employees SET e_salary = 20000 
  WHERE e_id = 1 AND e_salary=10000 AND e_name = 'John Smith';

VERIFY_MODIFIED_COLUMNS

VERIFY_MODIFIED_COLUMNS ポリシーでは、主キー カラムと更新されるカラムのみが WHERE 句に含まれます。更新されるカラムの一貫性だけをアプリケーションが考慮する場合に便利です。データを読み込んだ後に更新の対象外のカラムが変更されていても、この更新はコミットすることができます。

例では、RowSet は次のように発行します。

UPDATE employees SET e_salary = 20000 
WHERE e_id = 1 AND e_salary=10000

e_id カラムは主キー カラムなので含まれています。e_salary カラムは更新されるカラムなので、同様に含まれています。e_name カラムは読み込まれただけなので、検証されません。

VERIFY_SELECTED_COLUMNS

VERIFY_SELECTED_COLUMNS では、主キー カラムと指定するカラムが WHERE 句に含まれます。

WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();
metaData.setOptimisticPolicy(WLRowSetMetaData.VERIFY_SELECTED_COLUMNS);
// e_salary カラムのみを検証する
metaData.setVerifySelectedColumn("e_salary", true);
metaData.acceptChanges();

例では、RowSet は次のように発行します。

UPDATE employees SET e_salary = 20000 
WHERE e_id = 1 AND e_salary=10000

e_id カラムは主キー カラムなので含まれています。e_salary カラムは選択されたカラムなので、同様に含まれています。

VERIFY_NONE

VERIFY_NONE ポリシーでは、主キー カラムのみが WHERE 句に含まれます。データベース データに対して追加の検証は行われません。

例では、RowSet は次のように発行します。

UPDATE employees SET e_salary = 20000 WHERE e_id = 1

VERIFY_AUTO_VERSION_COLUMNS

VERIFY_AUTO_VERSION_COLUMNS では、主キー カラムと、別個のバージョン カラムが WHERE 句に含まれます。RowSet は更新の一環としてバージョン カラムも自動的にインクリメントします。このバージョン カラムのデータ型は integer でなければなりません。データベース スキーマを更新して、別個のバージョン カラム (e_version) を含める必要があります。例では、このカラムの現在の値が 1 であると仮定します。

metaData.setOptimisticPolicy(WLRowSetMetaData.
VERIFY_AUTO_VERSION_COLUMNS);
metaData.setAutoVersionColumn("e_version", true);
metaData.acceptChanges();

例では、RowSet は次のように発行します。

UPDATE employees SET e_salary = 20000, e_version = 2
WHERE e_id = 1 AND e_version = 1

e_version カラムは SET 句で自動的にインクリメントされます。WHERE 句は主キー カラムとバージョン カラムを検証しています。

VERIFY_VERSION_COLUMNS

VERIFY_VERSION_COLUMNS の場合、RowSet は主キー カラムと、別個のバージョン カラムを確認します。RowSet は更新の一環としてバージョン カラムをインクリメントしません。データベース スキーマを更新して、別個のバージョン カラム (e_version) を含める必要があります。例では、このカラムの現在の値が 1 であると仮定します。

metaData.setOptimisticPolicy(WLRowSetMetaData.VERIFY_VERSION_COLUMNS);
metaData.setVersionColumn("e_version", true);
metaData.acceptChanges();

例では、RowSet は次のように発行します。

UPDATE employees SET e_salary = 20000
WHERE e_id = 1 AND e_version = 1

WHERE 句は主キー カラムとバージョン カラムを検証します。RowSet はバージョン カラムをインクリメントしないため、この処理はデータベースが行う必要があります。一部のデータベースでは、行の更新時に自動的にインクリメントするバージョン カラムを提供しています。データベース トリガを使用してこのタイプの更新を処理することもできます。

オプティミスティックな同時実行性制御の制限

オプティミスティックなポリシーでは、変更する行に対する UPDATE 文と DELETE 文のみを検証します。読み込み専用の行はデータベースに対して検証されません。

ほとんどのデータベースでは BLOB または CLOB カラムを WHERE 句で許可していないため、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 更新用の MetaData 設定

データが RowSet に読み込まれるときに、RowSet 実装は ResultSetMetaData インタフェースを使用して、読み込みデータのテーブル名とカラム名を自動的に認識します。ほとんどの場合、RowSet が変更をデータベースに書き戻すために必要な SQL を生成するには、この情報で十分です。ただし、多くの JDBC ドライバでは、特定のカラムのテーブル名を要求されたときに単に空の文字列を返します。テーブル名がない場合、RowSet は読み込み操作でのみ使用できます。テーブル名をプログラム的に指定しないと、RowSet は更新を発行できません。

RowSet 実装では拡張された MetaData インタフェースを提供します。このインタフェースを使用すると、JDBC ドライバからは自動的に識別できないスキーマ情報を指定することができます。WLRowSetMetaData インタフェースを使用してスキーマ情報を設定できます。

executeAndGuessTableName と executeAndGuessTableNameAndPrimaryKeys

SQL クエリを介して RowSet を取得する場合、通常は execute() メソッドを使用してクエリの実行とデータの読み込みを行います。WLCachedRowSet 実装では、関連付けられたテーブルのメタデータも識別するために execute メソッドを拡張した executeAndGuessTableName メソッドと executeAndGuessTableNameAndPrimaryKeys メソッドも提供しています。

executeAndGuessTableName メソッドは、関連付けられた SQL を解析して、すべてのカラムのテーブル名を、SQL キーワード FROM に続く最初の語として設定します。

executeAndGuessTableNameAndPrimaryKeys メソッドは、SQL コマンドを解析してテーブル名を読み取ります。次に java.sql.DatabaseMetaData を使用して、テーブルの主キーを識別します。

MetaData インタフェースを使用したテーブルおよび主キー情報の設定

RowSetMetaData インタフェースを使用してテーブルおよび主キー情報を設定することもできます。

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);

書き込みテーブルの設定

WLRowSetMetaData インタフェースには、更新または削除するテーブルだけを指定するための setWriteTableName メソッドがあります。このメソッドは通常、RowSet が複数のテーブルの結合から取得されたものの、1 つのテーブルだけを更新する場合に使用します。書き込みテーブルに属さないカラムは読み込み専用としてマークされます。

たとえば、RowSet に「注文」と「顧客」の結合が含まれるとします。書き込みテーブルを「注文」に設定します。deleteRow を呼び出すと、「注文」の行は削除されますが、「顧客」の行は削除されません。

 


RowSet とトランザクション

ほとんどのデータベースや JDBC アプリケーションではトランザクションを使用します。RowSet は JTA トランザクションを含むトランザクションをサポートしています。一般的な使用例は次のとおりです。トランザクション 1 で RowSet を取得します。トランザクション 1 がコミットされます。基底のデータに対して、データベースやアプリケーション サーバによるロックはありません。RowSet はメモリ内にデータを保持します。データを変更したり、ネットワーク経由でクライアントに提供したりできます。アプリケーションはデータベースに対する変更をコミットする場合、トランザクション 2 を開始して、RowSet の acceptChanges メソッドを呼び出します。その後トランザクション 2 がコミットされます。

JTA グローバル トランザクションとの統合

EJB コンテナと UserTransaction インタフェースは JTA トランザクション マネージャを使用してトランザクションを開始します。RowSet の操作はこのトランザクションに参加することができます。JTA トランザクションに参加するには、RowSet はトランザクション対応の DataSource (TxDataSource) を使用する必要があります。DataSource は WebLogic Server コンソールでコンフィグレーションできます。

acceptChanges でオプティミスティックな衝突や他の例外が発生した場合、RowSet はグローバル JTA トランザクションを中止します。アプリケーションは通常データを再び読み込んで、新しいトランザクションで更新を再び処理します。

グローバル トランザクションを使用する RowSet の動作

障害またはロールバックが発生した場合、データはデータベースからロールバックされます。RowSet からはロールバックされません。処理を続行する前に、次のいずれかを行う必要があります。

ローカル トランザクションの使用

JTA グローバル トランザクションを使用しない場合、RowSet はローカル トランザクションを使用します。最初に接続に対する setAutoCommit(false) を呼び出します。次に SQL 文をすべて発行して、最後に connection.commit() を呼び出します。これでローカル トランザクションをコミットしようとします。EJB または JMS コンテナによって開始された JTA トランザクションと統合する場合は、このメソッドは使用しないでください。

acceptChanges でオプティミスティックな衝突や他の例外が発生した場合、RowSet はローカル トランザクションをロールバックします。この場合、acceptChanges で発行された SQL は、いずれもデータベースにコミットされません。

ローカル トランザクションを使用する RowSet の動作

この節では、ローカル トランザクションが失敗した場合の RowSet の動作について説明します。RowSet の動作は、接続オブジェクトの種類によって次のように異なります。

connection.commit の呼び出し

この場合、接続オブジェクトは RowSet によっては作成されず、connection.commit を呼び出すことでローカル トランザクションを開始します。トランザクションが失敗するか、または接続が connection.rollback を呼び出した場合、データはデータベースからロールバックされます。RowSet からはロールバックされません。処理を続行する前に、次のいずれかを行う必要があります。

acceptChanges の呼び出し

この場合、RowSet は独自の接続オブジェクトを作成し、このオブジェクトを使用して acceptChanges を呼び出すことで RowSet のデータを更新します。障害が発生するか、または RowSet が connection.rollback を呼び出した場合、データは RowSet とデータベースからロールバックされます。

 


パフォーマンスのオプション

RowSet を使用する場合は以下のパフォーマンス オプションを検討してください。

JDBC のバッチ処理

RowSet 実装には JDBC 2.0 のバッチ処理のサポートが含まれています。各 SQL 文を JDBC ドライバに個々に送信する代わりに、バッチ処理では文の集合を 1 つの一括処理として JDBC ドライバに送信します。バッチ処理はデフォルトで無効になっていますが、一般に 1 つのトランザクションで多数の更新が発生する場合にパフォーマンスが向上します。アプリケーションとデータベースに対してこのオプションを有効および無効に設定して、ベンチマークを実行してみるとよいでしょう。

WLCachedRowSet インタフェースには、INSERT、DELETE、および UPDATE 文のバッチ処理を制御するための setBatchInserts(boolean)setBatchDeletes(boolean)、および setBatchUpdates(boolean) メソッドがあります。

注意 : setBatchInsertssetBatchDeletes、または setBatchUpdates メソッドは、acceptChanges メソッドを呼び出す前に呼び出す必要があります。

Oracle のバッチ処理の制限

WLCachedRowSet はオプティミスティックな同時実行性制御に依存しているため、更新または削除コマンドが成功したか、またはオプティミスティックな衝突が発生したかを判別する必要があります。WLCachedRowSet 実装では、文によって更新された行の数を JDBC ドライバが報告するのに基づいて、衝突が発生したかどうかを判別します。更新された行が 0 の場合、WLCachedRowSet は衝突が発生したと認識します。

Oracle JDBC ドライバはバッチ更新が実行されると java.sql.Statement.SUCCESS_NO_INFO を返すため、RowSet 実装はその戻り値を使用して衝突が発生したかどうかを判別することができません。

RowSet はバッチ処理が Oracle データベースで使用されることを検出した場合、バッチ処理の動作を自動的に変更します。

バッチ挿入は検証されないため、普通に実行されます。

バッチ更新は普通に実行されますが、RowSet は特別な SELECT クエリを発行して、バッチ更新でオプティミスティックな衝突が発生したかどうかをチェックします。

SELECT 検証クエリの後でバッチ削除を実行するよりも効率的なため、バッチ削除ではグループ削除を使用します。

グループ削除

複数の行を削除する場合、RowSet は通常、削除される行ごとに DELETE 文を発行します。グループ削除を有効にした場合、RowSet は削除される行を含む WHERE 句を指定した 1 つの DELETE 文を発行します。

たとえば、テーブルから 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 です。

 


RowSet と XML

WLCachedRowSet 実装では、メタデータを XML スキーマとして記述し、データをそのスキーマに準拠する XML ドキュメントとして記述することができます。WLCachedRowSet は既存の XML スキーマと XML ドキュメントからインスタンスとメタデータを取得することもできます。

たとえば、RowSet を XML に変換して、別のプロセスに XML メッセージとして送信できます。他のプロセスでは、RowSet インスタンスをメモリ内で再作成し、データの読み込みや更新を行ってから、別の XML メッセージとして応答を送信します。最後に、元のサーバは XML メッセージを RowSet に再び変換して、データベースを更新できます。

RowSet インスタンスの XML としての記述

WLRowSetMetaData インタフェースは、RowSetMetaData を XML スキーマ ドキュメントとして記述するための writeXMLSchema メソッドを備えています。WLRowSetMetaData インタフェースには、RowSet のデータを XML インスタンス ドキュメントに変換するための writeXML メソッドがあります。

  XMLOutputStreamFactory xoFactory = 
XMLOutputStreamFactory.newInstance();
  WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();
  XMLOutputStream xos = null;
  // XSD スキーマを記述する
try {
xos = xoFactory.newDebugOutputStream(new
FileOutputStream("rowset.xsd");
metaData.writeXMLSchema(xos);
} finally {
if (xos != null) xos.close();
}
  // XML インスタンス データを記述する
try {
xos = xoFactory.newDebugOutputStream(new
FileOutputStream("rowset.xml");
rowSet.writeXML(xos);
} finally {
if (xos != null) xos.close();
}

XML ドキュメントからの RowSet の取得

WLRowSetMetaData インタフェースは、RowSetMetaData を XML スキーマ ドキュメントからロードするための loadXMLSchema メソッドを備えています。WLRowSetMetaData インタフェースには、XML インスタンス ドキュメントから取得するための loadXML メソッドがあります。

  XMLInputStreamFactory xiFactory =
XMLInputStreamFactory.newInstance();
XMLInputStream xis = null;
WLCachedRowSet rowSet = factory.newCachedRowSet();
WLRowSetMetaData metaData = (WLRowSetMetaData) rowSet.getMetaData();
// XSD を読み込む
try {
xis = xiFactory.newInputStream(new FileInputStream("rowset.xsd"));
metaData.loadXMLSchema(xis);
  } finally {
if (xis != null) xis.close();
}
  // XML を読み込む
  try {
xis = xiFactory.newInputStream(new FileInputStream("rowset.xml"));
rs.loadXML(xis);
  } finally {
if (xis != null) xis.close();
}

JDBC のデータ型から XML スキーマのデータ型へのマッピング

表 6-1 JDBC のデータ型から XML スキーマのデータ型へのマッピング

JDBC のデータ型

XML スキーマのデータ型

BIGINT

xsd:long

BINARY

xsd:base64Binary

BIT

xsd:boolean

BLOB

xsd:base64Binary

BOOLEAN

xsd:boolean

CHAR

xsd:string

DATE

xsd:dateTime

DECIMAL

xsd:decimal

DOUBLE

xsd:decimal

FLOAT

xsd:float

INTEGER

xsd:int

LONGVARBINARY

xsd:base64Binary

LONGVARCHAR

xsd:string

NUMERIC

xsd:integer

REAL

xsd:double

SMALLINT

xsd:short

TIME

xsd:dateTime

TIMESTAMP

xsd:dateTime

TINYINT

xsd:byte

VARBINARY

xsd:base64Binary

VARCHAR

xsd:string


 

XML スキーマのデータ型から JDBC のデータ型へのマッピング

表 6-2 XML スキーマのデータ型から JDBC のデータ型へのマッピング

XML スキーマのデータ型

JDBC のデータ型

base64Binary

BINARY

boolean

BOOLEAN

byte

SMALLINT

dateTime

DATE

decimal

DECIMAL

double

DOUBLE

float

FLOAT

hexBinary

BINARY

int

INTEGER

integer

NUMERIC

long

BIGINT

short

SMALLINT

string

VARCHAR


 

複数テーブルの RowSet のマッピング

RowSet は、複数のテーブルのカラムを返す SQL クエリから取得することができます。複数のテーブルを扱い、複数テーブルのシナリオで RowSet が発行する SQL を処理する場合は、RowSet のセマンティクスを理解しておくことが重要です。

RowSet のオプティミスティックな同時実行性制御ポリシーでは、更新されたテーブルのみを検証します。RowSet をテーブル t1 および t2 のカラムから取得して、テーブル t1 のカラム C を更新した場合、t2 から読み込まれた値を検証する SQL UPDATE または SELECT はありません。

RowSet は外部キーやテーブル間のその他の制約を認識しません。そのため、複数のテーブルを更新する場合は、テーブル間の整合性の制約が原因となって RowSet の更新が失敗する可能性があります。

複数テーブルの RowSet は、RowSet が N 個のテーブルと 1 個の書き込みテーブルの結合である場合に適切に機能します。たとえば、クエリで複数のテーブルを結合するものの、更新は従業員テーブルだけで行う場合があります。この場合、更新と削除が書き込みテーブルだけに適用されるように、setWriteTableName を呼び出す必要があります。

複数テーブルのもう 1 つの一般的なシナリオは、同じ主キー領域を共有する複数のテーブルです。これは、データベース内の複数の物理的なテーブルに分割された 1 つの論理的なテーブルのことです。このシナリオでは、RowSet は複数のテーブルを更新できます。

複数テーブルの RowSet では複雑な更新のセマンティクスを使用できるため、書き込みテーブル名を設定して 1 つのテーブルだけを更新することをお勧めします。

複数テーブルの RowSet の例

顧客テーブルと注文テーブルがある簡単な受注システムを考えてみます。

CREATE TABLE customer (
id integer primary key,
name varchar(200),
email varchar(200)
);
CREATE TABLE order (
id integer primary key,
sku integer,
quantity integer,
customer_id integer,
foreign key customer_id references customer(id)
);

この例では、各顧客が多数の注文を行う 1 対多の関係を示しています。

顧客ポータル アプリケーションは、次のような SQL を使用して、顧客の現在の注文と顧客に関する情報をロードするクエリを発行します。

SELECT o.id, o.sku, o.quantity, c.name, c.email 
FROM order o, customer c
WHERE c.id = o.customer_id

このデータは、SQL の結合から、一致する注文と顧客のカラムが含まれる 1 つの行と共に RowSet に読み込まれます。

このような場合は、「多」の側 (注文) を書き込みテーブルとして設定することをお勧めします。こうすると、「1」の側 (顧客) は読み込み専用になります。その結果、ユーザは注文の詳細は更新できますが、顧客の記録を変更することはできなくなります。deleteRow を呼び出すと、注文記録は削除されますが顧客は削除されないため、この方法は削除の場合に特に便利です。

 

フッタのナビゲーションのスキップ  ページの先頭 前 次