EOOLProcess
2007/03/30 (Fri) 22:07:46 JST
ロックの動作
ロックの動作を具体的に整理します。
- オブジェクトをフェッチする。 このとき、データ行がスナップショットとして登録される。
- オブジェクトの内容を変更する。
- オブジェクトを保存するようEOEditingContext.saveChanges()を実行する。
- WHERE句にロック指定の属性を含めたUPDATE文を発行する
- UPDATE文によって更新されたデータ行が1行であればコミット、2行以上あるか更新が失敗したらロールバックする
動作確認のテストに次のようなコードを書きました (?EOConflicts) 。
- 異なる2つのEOEditingContextを準備する
- 両方のEOEditingContextで同じデータを1つフェッチする (このオブジェクトのtitle属性値は "EOF Next Generation")
- 1つ目のEOEditingContextの持つオブジェクトのtitle属性を "?UpdatedByEditingContext1"に変更する
- 1つ目のEOEditingContextの変更を保存する
- 2つ目のEOEditingContextの持つオブジェクトのtitle属性を "?UpdatedByEditingContext2"に変更する
- 2つ目のEOEditingContextの変更を保存する
次が更新時のログです(実際はSQL文の値がバインド変数としてログに出力されますが、見やすいようにSQL文内に書き直しています)。 Movieエンティティのすべての属性をロックするよう指定した結果、UPDATE文のWHERE句にすべての属性値が含まれています。
=== Commit Internal Transaction === Begin Internal Transaction evaluateExpression: "UPDATE MOVIE SET TITLE = "UpdatedByEditingContext1" WHERE ( MOVIE_ID = 205 AND TITLE = "EOF Next Generation" AND DATE_RELEASED = 1996-01-25 05:00:00 AND CATEGORY = "Surreal" AND REVENUE = 600000.00 AND STUDIO_ID = 52 AND POSTER_NAME is NULL AND TRAILER_NAME is NULL AND RATED = "G")" === Commit Internal Transaction === Begin Internal Transaction evaluateExpression: "UPDATE MOVIE SET TITLE = "UpdatedByEditingContext2" WHERE ( MOVIE_ID = 205 AND TITLE = "UpdatedByEditingContext1" AND DATE_RELEASED = 1996-01-25 05:00:00 AND CATEGORY = "Surreal" AND REVENUE = 600000.00 AND STUDIO_ID = 52 AND POSTER_NAME is NULL AND TRAILER_NAME is NULL AND RATED = "G")" === Commit Internal Transaction
さて、後半のトランザクションを見るとWHERE句のTITLEが "?UpdatedByEditingContext1" になっています。 オブジェクトは別々のEOEditingContextを使って操作しているので、 もしEOFのオプティミスティックロックが「同一インスタンス上の更新の競合を検出する」ならば、ここには元の値である"EOF Next Generation"が入るはずです。
そこで1つ目のオブジェクトを更新した直後の2つ目のオブジェクトを調べたところ、オブジェクトがフォールトになっていました。 1つ目のオブジェクトを更新すると同時にスナップショットが更新され、そのオブジェクトと同じグローバルIDを持つオブジェクトがすべて破棄されたのです。 このフォールトは2つ目のオブジェクトのtitle属性を変更したときに充填され、データベースとの同期が完了します。 SQL文には最新のスナップショットが使われますから、先程のWHERE句のTITLEが1つ目のオブジェクトの内容になっているのは当然の動作だったのです。 よって、EOFのオプティミスティックロックは「同一インスタンス上の更新の競合を検出しない」ことになります。
図:更新時のデータ同期
ちなみに次のような順番でオブジェクトを変更すると2つ目のオブジェクトがフォールトになることはありませんが、発行されるSQL文は上記と同じ結果になります。
- 異なる2つのEOEditingContextを準備する
- 両方のEOEditingContextで同じデータを1つフェッチする
- 1つ目のEOEditingContextの持つオブジェクトのtitle属性を "?UpdatedByEditingContext1"に変更する
- 2つ目のEOEditingContextの持つオブジェクトのtitle属性を "?UpdatedByEditingContext2"に変更する
- 1つ目のEOEditingContextの変更を保存する
- 2つ目のEOEditingContextの変更を保存する
Inverse Pages: オプティミスティックロック