トランザクションと排他制御
処理を途中で止めないしくみと、同時に触られたときの守り方を、振込の例から説明できるようになります。
ねらい
複数の処理をまとめて安全に行うしくみを学びます。このレッスンを終えると、途中で失敗したときにデータが壊れない理由と、同時に触られたときの守り方を説明できるようになります。
途中で止まると困る処理があります
銀行の振込を考えます。この処理は2つの操作からできています。
- Aさんの口座から1万円を引く。
- Bさんの口座に1万円を足す。
1が終わった直後に障害が起きたらどうなるでしょうか。Aさんのお金は減り、Bさんのお金は増えていません。1万円が消えます。
そこで、この2つをひとまとまりの処理として扱います。このまとまりをトランザクションといいます。
結果は2つに1つです。
- 両方とも成功する… 変更を確定します(コミット)。
- どちらかが失敗する… 両方とも無かったことにします(ロールバック)。
「半分だけ実行された状態」を作らないのが、トランザクションの役目です。
同時に触られたときの守り方
複数の人が同時に同じデータを更新すると、変更が失われることがあります。
たとえば在庫が10個あり、2人が同時に「残りを確認して3個減らす」処理を始めたとします。どちらも「10個ある」と読んでから、それぞれ7個と書き込めば、6個減ったはずなのに7個のままになります。
これを防ぐのが排他制御です。あるデータを更新している間、他の処理からは触らせません。
- ロック… 使用中の印を付けます。
- 共有ロック… 読むだけなら、複数が同時に持てます。
- 専有ロック… 書くときは、1つだけ。他は待ちます。
ポイント
読むだけなら同時でよく、書くときは1つだけ。この使い分けで、安全を保ちつつ待ち時間を減らせます。全部を1つずつにすると安全ですが、遅くなります。
デッドロックは、互いに相手が持っているものを待ち合って、どちらも進めなくなる状態です。AがXを押さえてYを待ち、BがYを押さえてXを待つと起こります。DBMSは、これを検出して片方を取り消すことで解消します。
壊れたときに戻すしくみ
障害が起きても復旧できるように、備えがあります。
- ログ(ジャーナル)… いつ何をどう変えたかの記録です。
- バックアップ… ある時点のデータの複製です。
- ロールフォワード… バックアップの時点から、ログを使って障害の直前まで進め直します。
- ロールバック… 処理を始める前の状態へ戻します。
進めるのがロールフォワード、戻すのがロールバックです。媒体が壊れたときは進め直し、処理が途中で失敗したときは戻す、という使い分けになります。
まとめ
トランザクションは、複数の操作をひとまとまりとして扱い、全部成功か全部取り消しかにするしくみです。半分だけ実行された状態を作りません。同時更新には排他制御で備え、読むだけなら共有、書くときは専有とします。障害からの復旧は、進め直すロールフォワードと、戻すロールバックを使い分けます。
理解の確認
商品の在庫数が10個のとき、2人の担当者がほぼ同時に「在庫を確認して3個減らす」処理を行いました。排他制御が無い場合に何が起こり得るか、具体的な数値で説明してください。
答え: 本来は4個になるべきところ、7個のまま残ることが起こり得ます。
担当者Aが在庫を読み、10個であることを確認します。ほぼ同時に担当者Bも在庫を読み、やはり10個と確認します。この時点で、2人とも「10個ある」という同じ値を持っています。次にAが「10−3」を計算して7を書き込み、続いてBも「10−3」を計算して7を書き込みます。
結果、合計6個減ったはずなのに、在庫は7個と記録されます。Aの更新がBの更新に上書きされて失われたためです。
排他制御があれば、Aが更新を終えるまでBは待たされ、Bは更新後の7個を読んでから「7−3」で4を書き込むため、正しい結果になります。
分からなかった点・気になった点
読み込み中です。