RDBMS関係
MySQLの外部キー制約
参照アクション
UPDATE または DELETE 操作が、子テーブルで一致する行を持つ親テーブルのキー値に影響する場合、結果は FOREIGN KEY 句の ON UPDATE および ON DELETE 副次句で指定された参照アクションによって異なります。 参照アクションには次のものがあります:
CASCADE
参照先の親テーブルのレコードが削除されると参照している子テーブルのレコードも削除され、更新されて値が変わると参照元の子テーブルの値も整合性が取れるように更新される。
SET NULL
参照先の親テーブルのレコードが削除や更新されると、そのレコードを参照している子テーブルの外部キーの値がNULLに変更される。(NULLを許容している場合に有効)
RESTRICT
参照先の親テーブルのレコードが削除や更新されることを拒否する。
NO ACTION
親レコードのUPDATEorDELETE時点では何もしないが、コミット時にエラーが発生するため結果的にはRESTRICTと同じ動きをする。
SET DEFAULT
参照先の親テーブルのレコードのキーが更新・削除されたときに、子テーブルの外部キーをデフォルト値に設定する(デフォルト値が存在する場合に有効)
用語
トランザクション分離レベル
例えばAというトランザクションと並行してBというトランザクションが動いているとする。
トランザクションで発生しうる問題
ダーティリード (Dirty Read)
あるトランザクションがまだコミットしていない変更を別のトランザクションが読み取ってしまうこと。
ノンリピータブルリード
あるトランザクションが同一トランザクション内で複数同じテーブルを参照しにいくとする。
1回目の取得と2回目の取得の間で別のトランザクションがデータの更新をコミットした場合に、1回目と2回目のトランザクションで参照される値が変わってしまう。
ファントムリード
あるトランザクションの実行中に、別のトランザクションによってデータが追加されて想定される結果と異なる結果が出てしまうこと。
分離レベル
READ UNCOMMITED
コミットされていない変更まで読み取れてしまうのでダーティリードの可能性があり、もちろんノンリピータブルリード・ファントムリードの可能性もある。
READ COMMITED
コミットされたデータのみ読み取ることを保証する。
具体的な戦略としては、読み取りのたびにスナップショットを作成し走査したインデックスレコードのみロックする。都度スナップショットを作るため読み取るデータに一貫性がなく、ノンリピータブルリードの可能性がある。また、ギャップロックやネクストキーロックもないため、新しいレコードの追加を制御しておらず、ファントムおよびファントムリードの可能性も発生する。
REPEATABLE READ
同じトランザクション内で参照系のクエリを複数回実行しても、そのトランザクションが終わるまで他のトランザクションで行った変更が反映されないことを保証する。
具体的な戦略としてトランザクション開始後の最初の読み取りでスナップショットを取得し、同一トランザクション内ではそちらを参照するようにする。
トランザクション開始時に存在している行は一貫した状態で読み取れ、他のトランザクションがそれらを更新した場合でも、更新が反映されない。これにより、リピータブルリード(同じ行を複数回読んでも同じ結果が得られる)という性質が保たれる。
ただし、一般的にREPETABLE READを実現する機構としては「スナップショットによる分離」なので、同じものが読み取れること(ファントムリードが起きないこと)自体は保証するが、他トランザクションによる行の追加自体は起こりうる。個人的には「ファントムリードは防げるが、ファントム(裏側で新しい行が追加されていること)自体はSERIALIZEでないと防げない」というのでピンと来た。
MySQL(InnoDB)についてはギャップロックとネクストキーロックによって、そのトランザクションが完了するまで他のトランザクションから変更も追加もできないようになっている。
ただし、これまたややこしいがInnoDBのトランザクション分離レベルがREPEATABLE READの場合に、通常セレクトではファントムが起きないことが保証されるが、SELECT FOR UPDATEのようなロックをかける読み取りの場合だとファントムが発生しうるとのこと。
これは通常の読み取りの場合はスナップショットを参照するが、innoDBの場合のロッキングリードはREAD COMMITEDのように常に最新を見にいくかららしい。
参考