Repeatable Readの追加調査 その2

要点だけ簡単に言うと,

InnoDBでは分離レベルに関わらず,Update対象はテーブルの実体の行.
ロールバックセグメントにある参照用の行ではない)

・Update t1 set c2=c2+100 where c1=1 といったような形で,更新を行うと,演算に用いられるのはテーブルの実体の行の値.
( Read Committed のような動作を行う)

・Select * from t1 where c1=1 for update といった参照を行うと,得られるのは,Repeatable Read によるロールバックセグメントの行の値ではなく,テーブルの実体の行の値.
( Read Committed のような動作を行う)

・ロストアップデートと分離レベルは関係が無い.以前に読み込んだ データを元に新しい更新値をアプリケーション側で作成した場合,Select for update を使わない限り,分離レベルに関わらずロストアップデートは起こる可能性がある.
( Serializable は除く)

という感じです.

重要なポイントは,マルチバージョニングとは過去のデータを参照することによってリードロックその他発生して欲しくない現象を回避する,ということ.要するに,そもそも処理の順位制は保証されていないってこと.

それに対して,読み込みを行ってそれを元に書き込み用の値を作成して書き込みを行うまでが一連のアトミックな処理であって欲しい場合,その間は処理の順位制を保証する必要がある,という要望が時として存在する.ごく自然な話だ.

そのための方法として,MySQLには3つの段階の方法が提供されている.

1.Update t1 set c2=c2+100 where c1=1 のようにUpdate文そのものが読み込み+書き込みの形を取る.

2.特定の行に対してSelect for Update をしてから Update文を発行する.

3.Serializable モードにして完全に直列的に処理を行う.

下に行くほど強力で守備範囲が大きい.だけどその分,ロック待ちやデッドロックが発生しやすくなる.上から順に検討し,最小限の手立てに留めるのが良い,といったところか.

ちなみにOracleでは 2.Select for Update しか用意されていない.そして古いデータを参照していたトランザクションがどんな値であれ更新しようとすると,エラーを返すという仕様になっている.