行単位の排他を使用する場合は、そのトランザクションがアクセスしていない行は占有しません。競合する別のトランザクションでは、最初のトランザクションがアクセスしていない行を更新したり、新たな行を追加したりすることができます。このため、以下のような現象が起こることがあります。構築する業務において、この現象が発生すると不都合な場合は、行単位の排他を使用しないでください。
同一トランザクション内で、同一のSQL文を繰り返し実行した場合に、異なる集合が検索されることがあります。例えば、
カーソルで検索する行が増えることがあります。
一度目は成功した単一行SELECT文が、例外(基数違反)となることがあります。
集合関数の結果が変化することがあります。
探索条件に副問合せを指定した問合せの検索結果が変化することがあります。
行単位の排他では、INSERT文は他のトランザクションの終了を待たずに実行できます。このため、あるトランザクションで行を削除して、新たな行を挿入する操作を行っているとき、競合する別のトランザクションでは、まれに削除された行も挿入された行も参照できない場合があります。
利用者AがT1の全レコードを検索します。これと同時に、利用者Bが、C1が40であるレコードを削除して、C1が25であるレコードを挿入します。
図I.15 SQL文のデータ操作文に関する注意事例
行単位の排他を使用して更新系の処理を行うトランザクションに対し、同じ資源を参照するSQL文を排他なしで実行した場合、以下の現象が発生する場合があります。排他なしとは、独立性水準にREAD UNCOMMITTEDを指定したトランザクション、または、占有モードにNO LOCKを指定したSQL文を指します。
UPDATE文を実行中に排他なしでデータ操作のSQL文を実行した場合
データ操作のSQL文は、更新前の行も更新後の行も参照できない場合があります。
ROLLBACK文を実行中に排他なしでデータ操作のSQL文を実行した場合
データ操作のSQL文は、更新前の行も更新後の行も参照できない場合があります。
以下のSQL文は、独立性水準がREAD COMMITTEDであるか、または、占有モードをFREE LOCKにした場合には、各行の読み込み時の最新のコミット済みデータを参照します。
単一行SELECT文
更新可能性句に、FOR READ ONLYを指定したカーソル、または更新可能性句を省略したカーソルのOPEN文
このため、上記のSQL文実行中に更新業務がコミットした場合、次に示すような現象が起こることがあります。
SQL文の検索結果に、ある行については更新業務が更新する前の行、別の行については更新業務が更新した後の行が含まれる場合があります。
SQL文の検索結果に、ある行の更新前後の行がともに含まれる場合や、いずれも含まれない場合があります。
また、上記の事象にともなって、以下のようにデータの整合性がとれなくなります。
他のトランザクションが更新した行を上書きにより更新してしまう場合がある。
他のトランザクションが削除した行についてUPDATE文:位置づけやDELETE文:位置づけを行うと、対象行が存在しないのでエラーになる。
他のトランザクションが削除した行についてUPDATE文:探索やDELETE文:探索を行うと、対象行が存在しないのでデータなしになる。
このような場合には、更新トランザクションについて、以下に示す対処を行ってください。
カーソルの更新可能性句にFOR UPDATEを指定する。
占有モード指定にSHARE LOCK、またはEXCLUSIVE LOCKを指定する。
更新系の処理を行う場合、内部的に更新対象行を特定するための検索処理が行われるため、占有モードが下記のとおり推移します。
更新対象行の検索時
検索する範囲を共有モードで占有
更新対象行(検索結果)のデータの更新時
更新対象行を非共有モードで占有
このため、更新対象行のデータを更新する際に、更新対象行が別のトランザクションから共有モードで占有され、データ更新できないといった事象が発生する場合があります。この場合には、占有モードを以下のように指定することで、この現象を回避することが可能です。
動作環境ファイルのパラメタの設定やイルシデーションロックを用いて、内部的な検索を行うときから非共有モードでの占有とする。
SELECT文によって更新する行を検索し、その後、データを更新する場合には、SELECT文にFOR UPDATE句を指定し、あらかじめ、非共有モードでの占有とする。
占有モードを指定する方法は、“I.7.1 排他の属性と選択方法”を参照してください。
行単位の排他では、トランザクション中に行った更新内容はCOMMIT文実行時にまとめてインデックスへ反映します。このため、トランザクション中に行った挿入、インデックスキー値更新および削除の件数に比例してCOMMIT文の処理時間も長くなります。
COMMIT文実行時に、以下のエラーが発生する可能性があるため、COMMIT文もエラー処理の対象としてください。
テンポラリログ領域不足
インデックスの容量不足
デッドロック
行単位の排他を使用する場合、DELETE文またはUPDATE文を実行することによって発生する削除領域は、トランザクション完了後に再利用されます。そのため、同一トランザクション内で大量の件数を削除し、続いて挿入を行うような場合は、削除後に一度COMMIT文を実行してトランザクションを区切ることで、領域を有効に使用することができます。