前置き
下記のようなシチュエーションのテストを行いたいとなりました。
ユーザAが任意のデータの編集画面を開く
⇒ユーザBが同一データの編集画面を開き更新する
⇒ユーザAがデータを更新する
上記を自分は「排他制御のテスト」と呼んでいたのですが、意味が通じるのか気になり調べました。
調べた結果を関連する内容も含めて纏めます。
そもそも「排他制御(Exclusive Control)」とは?
排他制御とは、複数のユーザーやプログラムが同じデータに対して同時に読み書き・更新を行おうとした際に、データがおかしくならないように順序立てて管理(コントロール)する仕組みのことです。
システム上のデータベースやファイルは「同時に何人でもアクセスできてしまう」という性質を持っています。そのため、システム側で明示的にアクセスをコントロール(制御)してあげないと、データに矛盾が生じてしまいます。
なぜ排他制御が必要なのか?(具体例)
もし排他制御がなかった場合にどんなトラブルが起きるのか、具体的なシチュエーションを2つ紹介します。
例1:ECサイトの在庫管理(データ不整合)
1つしか残っていない限定商品を、ユーザーAとユーザーBが「まったく同じタイミング」で購入ボタンを押した場合:
【排他制御なし】
ユーザーA:残り1個の在庫を確認 ➔ 購入処理開始
ユーザーB:残り1個の在庫を確認 ➔ 購入処理開始
ユーザーA:在庫を「0個」にして注文完了
ユーザーB:在庫を「0個」にして注文完了
➔ 結果:在庫1個に対して2人の注文が確定してしまう
排他制御を入れることで、「先に処理を開始したユーザーAの完了を待ち、ユーザーBには『在庫切れです』と正しく伝える」ことができるようになります。
例2:Web画面での編集の打ち消し(ロストアップデート)
同じデータをユーザーAとユーザーBが同時に編集しようとした場合:
【排他制御なし】
1. ユーザーAが編集画面を開く(内容:バージョン1)
2. ユーザーBが編集画面を開く(内容:バージョン1)
3. ユーザーBが内容を変更して【保存】(内容:バージョン2に更新)
4. ユーザーAが内容を変更して【保存】(内容:バージョン3に更新)
➔ 結果:ユーザーBがせっかく更新した内容が、後から保存したAによって消えてしまう
このように、「せっかく更新したデータが消える(失われる)現象」をロストアップデート(更新喪失)と呼びます。これ防ぐのも排他制御の重要な役割です。
主な排他制御のアプローチ(楽観と悲観)
排他制御には楽観排他と悲観排他という2種類のアプローチがあります。
どちらかが正しいというわけではなく、用途に応じて使い分けられています。テストを行う場合は仕様を把握する必要があります。
| 種類 | 楽観的排他制御(楽観ロック) | 悲観的排他制御(悲観ロック) |
| 考え方 | 「めったに衝突しないだろう」と楽観的に考える | 「絶対に衝突するだろう」と悲観的に考える |
| 仕組み | 保存する瞬間に「自分が開いた時からデータが変更されていないか」を確認する | 画面を開いた(あるいは処理を開始した)瞬間にデータに鍵をかける |
| 失敗時の挙動 | 後から保存しようとした人に「他の人に更新されました」とエラーを出す | 後から開こうとした人に「他の人が編集中です」と開かせない |
| 主な用途 | 現代のWebシステム全般(SNS、ブログ、業務管理画面など) | チケット予約、銀行の口座取引など絶対に重複が許されない処理 |
冒頭の話に戻る
確認した結果、「排他制御のテスト」だとテストの目的としては正しいですが、事象やテストパターンを指す呼称であれば
- ロストアップデート(Lost Update / 更新喪失)の確認テスト
- 楽観的ロック(楽観排他)の検証テスト
などがありました。よりフランクな表現としては
- 同時更新(ダブル更新)テスト
- 競合(コンフリクト)テスト
- 割り込み更新テスト
などもありました。現場で伝わる表現にしていこうと感じました。
余談:冒頭シチュエーションの期待結果について
冒頭のように操作をしたときの期待結果について、今の現場でよく見る制御としては
- 楽観排他
- 制御しない
のどちらかが多いです。
「制御しない」のは「発生しても影響が少ないから」「運用上発生しないから」「開発コストを抑えたいから」等によって発生することがあります。
制御しない仕様であっても「エラーとならず想定通り上書きされるか」など試験を行うかは、コストと相談しつつ検討・実施します。





