EOOLProcess

2007/03/30 (Fri) 22:07:46 JST

ロックの動作

ロックの動作を具体的に整理します。

  1. オブジェクトをフェッチする。 このとき、データ行がスナップショットとして登録される。
  2. オブジェクトの内容を変更する。
  3. オブジェクトを保存するようEOEditingContext.saveChanges()を実行する。
  4. WHERE句にロック指定の属性を含めたUPDATE文を発行する
  5. UPDATE文によって更新されたデータ行が1行であればコミット、2行以上あるか更新が失敗したらロールバックする

動作確認のテストに次のようなコードを書きました (?EOConflicts) 。

次が更新時のログです(実際は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文は上記と同じ結果になります。


Inverse Pages: オプティミスティックロック