他からの読取りも書込みも禁じる更新用のロック。
専有ロック(排他ロック、X(eXclusive)ロック)とは、他からの読み取りも書き込みもすべて禁止する、更新(書き込み)用のロックのことです。あるデータに専有ロックを掛けられるトランザクションは、同時に1つだけです。
身近な例で考えると、個室トイレを使うのに似ています。中に入って鍵をかければ、その間は誰も入れませんし、中をのぞくこともできません。1人が使い終わって鍵を開けるまで、次の人はずっと待つしかありません。
上のツールで▶ボタンを押すと、T1が専有ロック(X)を取って在庫数を更新する間、T2は読み取りすらできず待たされ、解放後に最新の値を読む様子を確認できます。
専有ロックによる「他をすべて締め出す」制御を排他制御といいます。排他とは「他をしりぞけて独占する」という意味です。専有ロックは次のどのロックとも両立できません。
・専有(X)+ 共有(S):両立できない(読み取りも待たせる)
・専有(X)+ 専有(X):両立できない(書き込みは1人だけ)
なぜここまで厳しく締め出すのでしょうか。それは、更新の途中の中途半端な値を他から読まれると、矛盾したデータが広まってしまうからです。たとえば在庫を120から100に書き換える途中の不正な値(例: 一瞬だけ0)を読まれては困ります。専有ロックは更新が完全に終わるまでデータを丸ごと隠すことで、これを防ぎます。
共有ロックと専有ロックは、目的も挙動も対照的です。共有ロックは「読み取り用」で複数人が同時に取れますが、専有ロックは「更新用」で1人しか取れません。
| 項目 | 共有ロック(S) | 専有ロック(X) |
|---|---|---|
| 用途 | 読み取り | 書き込み(更新) |
| 他の読み取り | 許す(同時に読める) | 禁止(待たせる) |
| 他の書き込み | 禁止 | 禁止 |
| 同時取得 | 複数OK | 1つだけ |
ひとことで言えば、共有ロックは「みんなで読める鍵」、専有ロックは「ひとりで独占する鍵」です。読むだけなら共有ロックで並行を許し、更新するときだけ専有ロックで完全に独占する、という使い分けによって、安全さと処理効率のバランスをとっています。
「あるロックとあるロックが同時に取れるか」を一覧にした表をロックの相性表(適合性マトリクス)といいます。専有ロックの視点から整理すると、次のとおりです。
・共有(S) × 共有(S):唯一両立できる組み合わせ。読み取り同士は共存してよい。
・共有(S) × 専有(X):待ち。誰かが読んでいる間は書き込めない。
・専有(X) × 共有(S):待ち。書き込み中は読み取りも禁止。
・専有(X) × 専有(X):待ち。書き込み同士は絶対に同時にできない。
この表から分かるのは、専有ロック(X)は何と組み合わせても待ちになるということです。書き込みは「完全に独占しないと安全でない」ので、どんな相手もブロックします。専有ロックが名前どおり「排他的に独占する」ロックである理由がここにあります。
専有ロックがないと「更新の失われ問題」(ロストアップデート)が起きます。これは、2つのトランザクションが同時に同じデータを読んで書き込んだとき、一方の更新がもう一方に上書きされて消えてしまう問題です。
具体例で考えます。在庫数が120のとき:
・T1が120を読み、在庫を10個出庫するため「120 − 10 = 110」を書こうとする。
・T2も120を読み(T1がまだ書いていないため)、在庫を30個出庫するため「120 − 30 = 90」を書く。
・最終的に在庫は90になるが、T1の「−10」の操作が完全に消えてしまっている。本当は120 − 10 − 30 = 80になるべきだった。
専有ロックを使えば、T1が読んで書き終わるまでT2はデータに触れません。T2は必ずT1の書き込み後の値(110)を読むので、正しく110 − 30 = 80が得られます。これが「更新用には専有ロックが必要」な根本的な理由です。上のツールで▶を押すと、T1が書き込みを終えてからT2が正しい値を読む順序を確認できます。