17 結果セット
Java Development Kit(JDK)の標準Java Database Connectivity(JDBC)機能には、結果セット機能の拡張が含まれています。拡張には、前方または後方への処理、相対的または絶対的な位置指定、内部または外部で生じたデータベースに対する変更の参照、および結果セット・データの更新と更新による変更内容のデータベースへのコピーがあります。
この章では、以下のトピックについて説明します。
17.1 結果セットのサポートのOracle JDBC実装概要
この項では、スクロール可能性(クライアント側キャッシュを使用)および更新可能性(ROWID
を使用)を実現する結果セットのサポートのOracle JDBC実装に関する主要な視点について説明します。
ユーザーは、独自のクライアント側キャッシュ・メカニズムを実装できます。そのためのインタフェースが提供されています。
結果セットのスクロール可能性のためのOracle JDBC実装
基礎となるサーバーでスクロール可能なカーソルがサポートされないため、Oracle JDBCが、別々のレイヤーでスクロール可能性を実装する必要があります。
この機能は、スクロール可能な結果セットの行をクライアント側のメモリー・キャッシュに格納することにより、実現されていることに注意してください。
ノート:
あらゆるスクロール可能な結果セットのすべての行がクライアント側キャッシュに格納されるため、結果セットに多くの行、多くの列または非常に大きな列が含まれる場合、クライアント側Java仮想マシン(JVM)に障害が発生する原因になる可能性があります。大きな結果セットに対してはスクロール可能性を指定しないでください。
結果セットの更新可能性のためのOracle JDBC実装
更新可能性をサポートするために、Oracle JDBCはROWID
を使用して、結果セットに出現するデータベース行を一意に識別します。更新可能な結果セットに問い合せるたびに、選択された列とともに、Oracle JDBCドライバによって自動的にROWID
が取り出されます。
ノート:
更新可能性そのものは、クライアント側のキャッシュを必要としません。特に、forward-only更新可能結果セットは、クライアント側のキャッシュを必要としません。
17.2 結果セットの制限事項およびダウングレード・ルール
一部の結果セット型は、ある種類の問合せには不適切です。実行する問合せに対して不適切な結果セット型または同時実行性型が指定されている場合、JDBCドライバは次のルール・セットに従い、かわりに使用する最適な型を判断します。
指定された結果セット型または同時実行性型が不適切な場合、実際の結果セット型と同時実行性型は、文が実行されるときに、文オブジェクト上で SQLWarning
を発行しているドライバを使用して決定されます。SQLWarning
オブジェクトには、要求した型が不適切だった理由が含まれます。要求した結果セットの型を受け取ったかどうか確認するには、警告を確認してください。
結果セットの制限
拡張された結果セットの問合せには、次の制限事項が適用されます。次の指針に当てはまらない場合、JDBCドライバによって、代替の結果セット型または同時実行性型が選択されます。
更新可能な結果セットを作成するには、次の制限事項を考慮します。
-
問合せによって選択できるのは、単一の表のみです。結合操作を含めることはできません。
さらに、挿入するためには、NULL化可能でない列およびデフォルト値が設定されていない列をすべて、問合せによって選択する必要があります。
-
問合せでは
SELECT *
を使用できません。ただし、回避方法があります。
-
問合せで選択できるのは、表列のみです。
導出列や、列の集合の
SUM
またはMAX
など、集合体を選択できません。
scroll-sensitive結果セットを作成するには、次の制限事項を考慮します。
-
問合せでは
SELECT *
を使用できません。ただし、回避方法があります。
-
問合せによって選択できるのは、単一の表のみです。
スクロール可能結果セットおよび更新可能結果セットでは、Stream
などの列を使用できません。サーバーでStream
列をフェッチする必要がある場合は、フェッチ・サイズを1に減らし、Stream
列の読込みが終了するまで、Stream
列に続くすべての列をブロックします。このため、列を一括でフェッチし、スクロールすることはできません。
回避策
SELECT *
の制限事項を回避するには、次の例のように、表の別名を使用します。
SELECT t.* FROM TABLE t ...
ノート:
ある問合せから、scroll-sensitiveまたは更新可能な結果セットを作成できるかどうかを判断する簡単な方法があります。ROWID
列を問合せリストに追加できる場合は、その問合せからscroll-sensitiveまたは更新可能な結果セットを作成できます。
結果セットのダウングレード・ルール
指定された結果セット型または同時実行性型が不適切な場合、Oracle JDBCドライバは次のルールを使用して、代替型を選択します。
-
指定した結果セット型が
TYPE_SCROLL_SENSITIVE
であるにもかかわらず、JDBCドライバがその要求を完全には満たせない場合、JDBCドライバはTYPE_SCROLL_INSENSITIVE
にダウングレードしようとします。 -
指定した結果セット型またはダウングレード後の結果セット型が
TYPE_SCROLL_INSENSITIVE
であるにもかかわらず、JDBCドライバがその要求を完全には満たせない場合、JDBCドライバはTYPE_FORWARD_ONLY
にダウングレードしようとします。 -
指定した同時実行性型が
CONCUR_UPDATABLE
であるにもかかわらず、JDBCドライバがその要求を完全には満たせない場合、JDBCドライバはCONCUR_READ_ONLY
にダウングレードしようとします。
ノート:
JDBCドライバによる結果セット型および同時実行性型の操作は、それぞれ独立しています。
結果セット型および同時実行性型の検証
問合せを実行した後、結果セット・オブジェクトのメソッドをコールすることにより、JDBCドライバが実際に使用した結果セット型と同時実行性型を検証できます。
-
int getType() throws SQLException
このメソッドは、問合せに対して使用された結果セット型の
int
値を戻します。ResultSet.TYPE_FORWARD_ONLY
、ResultSet.TYPE_SCROLL_SENSITIVE
またはResultSet.TYPE_SCROLL_INSENSITIVE
という値が戻されます。 -
int getConcurrency() throws SQLException
このメソッドは、問合せに対して使用された同時実行性型の
int
値を戻します。ResultSet.CONCUR_READ_ONLY
またはResultSet.CONCUR_UPDATABLE
という値が戻されます。
17.3 更新の競合回避について
JDBCドライバで使用される更新可能な結果セットに関しては、次の事項に注意してください。
-
ドライバは、更新可能な結果セットに対する書込みロックを施行しません。
-
ドライバは、結果セットの
DELETE
またはUPDATE
操作の競合をチェックしません。
DELETE
またはUPDATE
操作を、コミットされた別のトランザクションによって更新された行に対して実行すると、競合が発生します。
Oracle JDBCドライバは、ROWID
を使用し、データベース表の行を一意に識別します。ドライバがUPDATE
またはDELETE
操作をデータベースに送信しようとしたとき、ROWID
が有効であれば、操作は実行されます。
コミットされた別のトランザクションによる変更は、レポートされません。競合は警告なしに無視され、新しい変更によって前の変更は上書きされます。
競合を回避するには、結果セットを作成する問合せを実行するときに、OracleのFOR UPDATE
機能を使用します。これにより、競合を回避できますが、データへの同時アクセスも禁止されます。データ項目に同時に設定できる書込みロックは1つのみです。
17.4 行フェッチ・サイズ
デフォルトでは、Oracle JDBCは問合せを実行するとき、データベース・カーソルから一度に10行の結果セットを受け取ります。これが、デフォルトのOracle行フェッチ・サイズ値です。データベース・カーソルへの1回のラウンドトリップで取り出される行の数を変更するには、行フェッチ・サイズ値を変更します。
標準JDBCでは、1つの問合せの1回のデータベース・ラウンドトリップでフェッチされる行の数を指定することもできます。この数はフェッチ・サイズと呼ばれます。Oracle JDBCでは、行プリフェッチ値が、文オブジェクトのデフォルト・フェッチ・サイズとして使用されます。フェッチ・サイズを設定すると、行プリフェッチ設定より優先され、その文オブジェクトを介して実行される後続の問合せに適用されます。
フェッチ・サイズは、結果セットでも使用されます。文オブジェクトが問合せを実行するとき、文オブジェクトのフェッチ・サイズが、その問合せで作成される結果セット・オブジェクトに渡されます。ただし、結果セット・オブジェクトでフェッチ・サイズを設定して、渡された文フェッチ・サイズをオーバーライドすることもできます。
ノート:
結果セットが作成された後で文オブジェクトのフェッチ・サイズを変更しても、結果セットには影響を与えません。
明示的に設定された場合でも、渡された文フェッチ・サイズと等しいデフォルトでも、結果セット・フェッチ・サイズによって、その結果セットでの後続のデータベースへのラウンドトリップで取り出される行の数が判断されます。このラウンドトリップには、元の問合せを完了するために必要なラウンドトリップと、結果セットへのデータの再フェッチに必要なラウンドトリップが含まれます。scroll-sensitiveまたはscroll-insensitive/更新可能な結果セットを更新するために、データは明示的または暗黙的に再フェッチされる可能性があります。
17.4.1 フェッチ・サイズの設定
Statement
、PreparedStatement
、CallableStatement
およびResultSet
オブジェクトのすべてで、フェッチ・サイズを設定および取り出す次のメソッドが使用可能です。
-
void setFetchSize(int rows) throws SQLException
-
int getFetchSize() throws SQLException
問合せのフェッチ・サイズを設定するには、問合せを実行する前に文オブジェクトのsetFetchSize
をコールします。フェッチ・サイズをNに設定すると、1回のデータベースへのラウンドトリップで、N行がフェッチされます。
問合せを実行した後、結果セット・オブジェクト上でsetFetchSize
をコールすることで、渡された文オブジェクト・フェッチ・サイズをオーバーライドすることができます。これは、元の問合せに応じてさらに行を取得するための後続のアクセスすべてと、それ以降の、行の再フェッチすべてに適用されます。
17.4.2 フェッチ方向のプリセット
標準JDBCでは、結果セットの処理に使用するために、フェッチ方向と呼ばれる方向を事前に指定できます。これにより、JDBCドライバの処理を最適化できます。次の結果セット・メソッドが指定されます。
-
void setFetchDirection(int direction) throws SQLException
-
int getFetchDirection() throws SQLException
Oracle JDBCドライバは前方へのプリセット値のみをサポートします。これは、ResultSet.FETCH_FORWARD
静的定数値を入力することにより、指定できます。
ResultSet.FETCH_REVERSE
およびResultSet.FETCH_UNKNOWN
という値はサポートされていません。指定しようとすると、SQL警告が発生し、設定は無視されます。
17.5 行の再フェッチについて
結果セットのrefreshRow
メソッドは、一部の種類の結果セットで、データを再フェッチするためにサポートされています。具体的には、データベースに戻って、結果セットの現在の行からのn行に対応するデータベース行を再取得します。ここで、nはフェッチ・サイズです。これを使用すると、周囲のトランザクションの分離レベルに応じて、結果セットの外部で行われたデータベースの最新の更新を参照できます。
再フェッチすると、すでに結果セットにある行に対応する行のみを再取得します。元の問合せ以降にデータベースで挿入や削除が行われた行については何もしません。挿入された行は無視されます。また、対応する行がデータベースから削除された後も、結果セットの行はそのまま残ります。データベースで削除された行を再フェッチしようとした場合、それに対応する結果セットの行は、元の値を維持します。
ノート:
いくつかの基準を持つ問合せに基づいてTYPE_SCROLL_SENSITIVE
結果セットを宣言してから、列の値が問合せの基準に一致しなくなるように外部的に行を更新すると、ドライバは、行がデータベースから削除され、送信された問合せでは取り出せないかのように動作します。このため、refreshRow
メソッドをコールしても個別行の更新は確認できません。
refreshRow
メソッドのシグネチャを示します。
void refreshRow() throws SQLException
このメソッドをコールするときは、行境界の外側や挿入行ではなく、有効な現在行に位置指定しておく必要があります。
次の結果セットのカテゴリで、refreshRow
メソッドがサポートされています。
-
scroll-sensitive/読取り専用
-
scroll-sensitive/更新可能
-
scroll-insensitive/更新可能
ノート:
Scroll-Sensitive結果セット機能は、refreshRow
の暗黙的なコールによって実装されます。
17.6 内部的および外部的に加えられたデータベース変更の参照について
この項では、次の事項を参照する結果セットの機能について説明します。
ノート:
標準JDBCの仕様では、外部変更は「他からの変更」と呼ばれています。
この項の内容は次のとおりです。
17.6.1 外部変更の可視性と検出
外部ソースによって基礎となるデータベースに加えられる変更に関して、2つの概念があります。これらは似ていますが、ローカルな結果セットからの変更の可視性という観点から見ると異なります。
-
変更の可視性
-
変更の検出
「可視である」変更とは、結果セットの行を見たとき、外部ソースによってデータベースの対応する行に加えられた変更からの新しいデータ値を参照できるという意味です。
一方、「検出される」変更とは、結果セットに最初に値が移入されて以降の新しい値であることを、結果セットが認識するという意味です。
Oracle結果セットでは、新しいデータを参照したときでも(scroll-sensitive結果セットでの外部UPDATE
のように)、このデータが結果セットへの移入後に変更されたことは認識されません。このような変更は、検出されません。
17.6.2 内部変更および外部変更の可視性の概要
表17-1では、Oracle JDBC実装の結果セット・オブジェクトが、結果セット自体が内部的に実行した変更および基礎となるデータベースに対してユーザー自身のトランザクション、またはその他のコミットされたトランザクションから外部的に実行された変更を参照できるかどうかについての状況を要約します。
表17-1 Oracle JDBCでの内部変更および外部変更の可視性
結果セット型 | 内部的なDELETEの参照が可能か | 内部的なUPDATEの参照が可能か | 内部的なINSERTの参照が可能か | 外部的なDELETEの参照が可能か | 外部的なUPDATEの参照が可能か | 外部的なINSERTの参照が可能か |
---|---|---|---|---|---|---|
forward-only |
不可 |
可 |
不可 |
不可 |
不可 |
不可 |
scroll-sensitive |
可 |
可 |
不可 |
不可 |
可 |
不可 |
scroll-insensitive |
可 |
可 |
不可 |
不可 |
不可 |
不可 |
ノート:
-
refreshRow
メソッドの明示的な使用は、外部変更の可視性の概念とは別です。 -
scroll-sensitive結果セットを基礎とする
UPDATE
操作のように、外部変更が可視であるときでも、これらは検出されません。結果セットのrowDeleted
、rowUpdated
およびrowInserted
メソッドは常にfalse
を戻します。
17.6.3 Scroll-Sensitive結果セットのOracle実装
scroll-sensitive結果セットのOracle実装にはウィンドウの概念があり、フェッチ・サイズに基づくウィンドウ・サイズを持ちます。ウィンドウ・サイズは、結果セット内で行が更新される頻度に影響を及ぼします。
指定された行へ移動することによって現在の行を確定した場合、ウィンドウは結果セットのその行から始まるn行です。ここで、nは、結果セットによって使用されているフェッチ・サイズです。結果セットが先に作成された場合、現在の行がなく、したがってウィンドウもない点に注意してください。デフォルトの位置は最初の行の前です。これは有効な現在の行ではありません。
行を移動するとき、現在行がウィンドウ内にある間は、ウィンドウは変更されません。しかし、ウィンドウの外にある新しい現在行に移動すると、新しい現在行から始まるN行のウィンドウが再定義されます。
ウィンドウが再定義されると、refreshRow
メソッドが暗黙的にコールされ、新しいウィンドウの行に対応するデータベースのN行が自動的に再フェッチされます。これにより、新しいウィンドウのデータが更新されます。
そのため、外部更新は、scroll-sensitive結果セットですぐには参照できません。前述のように、自動再フェッチの後で参照できるようになります。
ノート:
この種の再フェッチは、高度に効率的または最適化されている方法論ではなく、パフォーマンスについては無視できない不安があります。現在実装されているようなscroll-sensitive結果セットを使用する場合は、あらかじめ慎重に検討してください。sensitivityとパフォーマンスの間にも重大なトレードオフがあります。最もsensitiveな結果セットはフェッチ・サイズが1であるものです。この場合、行を移動するたびに新しい現在の行が再フェッチされます。ただし、これはアプリケーションのパフォーマンスに重大な影響を及ぼします。