そもそもロックとは何か
- 複数の人が同じデータを同時に更新したときの矛盾を避けるために対象レコードをロック(触れなくする)こと
楽観ロックとは何か
- 「ロックしない」ロック
- レコードのバージョンを保持しておき、更新時にバージョンを条件に加える
- 更新対象がないと「ロック失敗」とみなす
SQL ServerのRowVersion型
- 楽観ロック用のデータ型
- 内部的には
timestamp型。なんでやねん - 行に更新が入ったら自動的にカウントアップされる
一般的な使い方
- 複数の人が同時期に更新をかける恐れがある場合に使う
- 後勝ちで良いときは不要
- 画面側でSELECT時のバージョンを保持
- 更新をリクエストするときにバージョンも送る
- DB内のバージョンをずれがある場合はロックに失敗したとみなす
- Entity Frameworkの場合、DbUpdateConcurrencyExceptionがスローされる
エンティティクラスの定義
- 対象のプロパティをbyte[]型で宣言し、
[Timestamp]を付与するだけ
public class Person
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[Timestamp]
public byte[] Version { get; set; }
}
悲観ロックとは
- いわゆる行ロックなど
- レコード(あるいはテーブルやDB)に排他をかけ、更新処理中に他のトランザクションから隔離する
- 設計をミスると深刻なレスポンス低下に繋がる
- Webアプリでは禁忌・・・
閑話休題
- 「他のトランザクションから隔離する」と言うが、その手法は様々
- OracleはREADにロックを書けない
- 他のDBMSは選べるのが普通
- DBMS毎のデフォルトの挙動を把握しておくのが大事
ロックの解像度を上げる
- 悲観ロックがWebアプリで禁忌となる理由
- リクエストを跨いだロックが危険だから
- 2つ目のリクエストが来るとは限らない!
- 同じトランザクション(≒リクエスト)の中なら、悲観ロックを使うのが現実的
- 厳密なロックが必要な場合に使うのは適切
- レスポンス低下を頭に入れておくことは必要
最後に
- DBMS毎の挙動を知っておこう
- 悲観ロックと楽観ロックの使いどころを押さえておこう
- DBを知らずにEFを使うことなかれ!