この記事ではトランザクション処理と排他制御についてIT初心者にも分かりやすく解説します。
トランザクション処理
- データベースに対してまとめて処理する必要がある操作を一括りにした処理。
- ACID特性はトランザクション処理が満たす必要がある4つの特性。
排他制御
- 排他制御とは、トランザクション処理を実行している間は別のトランザクション処理が実行できないようにデータベースをロックする処理。
- 専有ロック中、他ユーザはデータの変更も読取も出来ない。
- 共有ロック中、他ユーザはデータの変更は出来ないが、読取は出来る。
- デッドロックとは、お互いがアクセスしたいデータをロックしてしまうことで、永遠にロック解除を待ち続ける状態。
応用情報ではトランザクション処理と排他制御に関する問題が出題されます。是非最後までご覧ください。
トランザクション処理
トランザクション処理とは、データベースに対してまとめて行う必要がある操作を一括りにした処理のことです。トランザクション処理は全てを完全に行うか、全く行わないかのどちらかです。
トランザクション処理の例は銀行の振込処理です。
振込処理は以下の4つの処理から成り立ち、中断することは許されません。
- Aさん(送金する人)の口座残高を確認する
- Aさんの口座から残高を減らす
- Bさん(入金される人)の口座残高を確認する
- Bさんの口座残高から残高を増やす
トランザクション処理が途中で終了した場合を考えてみましょう。例えば、送金口座から残高を減らした後、システム障害が起きて入金口座の残高を増やす処理が行われなかったとします。Aさん送金口座からお金は減ったのに、Bさんの入金口座の残高が増えないことになり、凄く困ったことになります。
なので、処理を行う時は4つ全て行う必要があり、途中で失敗した時は一番最初の状態に戻す必要があります。このように、一連で行う必要がある操作の一括りをトランザクション処理と言います。
ACID特性
トランザクション処理はACID特性という4つの特徴を満たす必要があります。
原子性(Atomicity)
トランザクション処理は全て完了するか、全く実行されないかのどちらかで終了する必要があります。
一貫性(Consistency)
トランザクション処理の前後でデータ不整合が生じないようにする必要があります。例えば、残高が100円しかないのに1000円の振込を実行したら、残高が-900円になり、おかしなデータが生じてしまいますよね。このような不整合を起こさないようにするのが一貫性です。
独立性(Isolation)
複数のトランザクション処理を実行しても、他のトランザクション処理の影響を受けずに実行できるようにする必要があります。例えば、残高が1000円あるときに、100円の銀行引き落としと200円の銀行引き落としが同時に実行されたとします。
この時、1000円-100円=900円の処理と900円-200円=700円の処理がそれぞれ独立して行われる必要があります。つまり残高は700円になるということですね。
同時に行われたから、1000円-100円=900円、1000円-200円=800円で計算して残高が800円になりました。では困りますよね。
トランザクション処理は1つずつ完了させる必要があるという性質が独立性になります。
耐久性(Durability)
トランザクション処理が完了した後は、データベースに障害が発生しても結果を保存する必要があります。銀行のシステムに障害が発生してよく分からなくなったので残高を0円にします、だと困りますよね。例え、障害が発生してもデータは保存しておく必要があります。
排他制御
トランザクション処理ではおかしなデータを作成しないように独立性を満たす必要があります。そのために、トランザクション処理を行っている時は別のトランザクション処理が実行出来ないようにデータベースをロックします。これを排他制御と言います。
排他制御をしないとどうなるのか
排他制御を行わずに、複数のトランザクション処理を行うとどうなるのでしょうか。ATMからお金を引き出すトランザクションを同時に行った場合を考えてみます。
ATMからお金を引き出すトランザクションでは以下3つの処理を行います。
- 口座残高を確認する
- 口座残高からお金を減らす
- ATMからお金を出金する
今、残高が100万円の口座から1万円を引き出す操作を同時に行ってみます。
- トランザクション①が残高を確認する:残高100万円であると確認
- トランザクション②が残高を確認する:残高100万円であると確認
- トランザクション①で残高を1万円減らす:100万円から1万円減らして99万円にする
- トランザクション②で残高を1万円減らす:100万円から1万円減らして99万円にする
- トランザクション①で1万円を出金
- トランザクション②で1万円を出金
トランザクション①と②で合計2万円出金しているのに銀行の残高は99万円と、おかしなデータが発生しています。
排他制御をするとどうなるか
排他制御を行うと、トランザクション実行中はデータベースをロックして別のトランザクションがアクセス出来ないようにします。
- トランザクション①が残高を確認する:残高100万円であると確認
- トランザクション①で残高を1万円減らす:100万円から1万円減らして99万円にする
- トランザクション①で1万円を出金
- トランザクション②が残高を確認する:残高99万円であると確認
- トランザクション②で残高を1万円減らす:99万円から1万円減らして98万円にする
- トランザクション②で1万円を出金
トランザクション①実行中はデータベースをロックしているので、トランザクション②はデータベースにアクセス出来ません。そのため、トランザクション①→トランザクション②の順番で実行することになり、データの整合性が保たれます。
専有ロックと共有ロック
データベースにおかしなデータを生み出さないためには排他制御をする必要があることが分かりました。では、排他制御の際、どのようにデータベースをロックするのでしょうか。
2種類のトランザクション処理
トランザクション処理には大きく分けて2種類あります。
- 登録・更新・削除など、データを変更する処理
- データを変更せずに読み取るだけの処理
口座への入金や出金はデータを変更する処理ですが、残高や取引履歴を確認するのは読み取り処理になります。
トランザクション処理の種類によって、排他制御のロックの仕方が変わります。
専有ロック
データを変更する処理の場合は専有ロックを行います。
専有ロックを行うと、後続のトランザクションはデータを変更する処理もデータを読み取る処理も行えません。
データ変更中に別のトランザクション処理がデータを変更するとおかしなデータが出来てしまいます。また、データを読取っても変更中のデータを読取ることになるので誤解を生む可能性があります。なので、専有ロック中は変更も読取も不可になります。
共有ロック
データを読取る処理の場合は共有ロックを行います。
共有ロックを行うと、後続のトランザクションはデータを変更する処理は出来ませんが、データを読み取る処理は行えます。
データ読取中に別のトランザクション処理がデータを変更すると、変更中のおかしなデータを見ることになってしまいます。しかし、データ読取中に別のトランザクションがデータを読取る分にはデータの不整合は発生しないので問題ありません。なので、共有ロック中は変更不可で読取可能になります。
デッドロック
デッドロックとは、複数のトランザクション処理が同じデータベースを使用する場合に、お互いに相手がアクセスしたいデータベースをロックしてしまい、永遠に待ち状態になってしまう状態のことです。
下の例では、トランザクション①がテーブルA→テーブルBの順番で、トランザクション②がテーブルB→テーブルAの順番で編集しようとしているため、お互いがお互いロックしているテーブルの解放待ちになってしまい、次のステップに進めなくなっています。この状態がデッドロックです。
アクセスする順番が逆のトランザクション処理が存在すると、デッドロックが発生する可能性があるため、複数のトランザクション処理を実行する場合は同じ順番でアクセスするように設計します。
応用情報技術者試験での出題例
令和4年度秋期問30
応用情報技術者
午前試験 令和4年度秋期問27
ACID特性の四つの性質に含まれないものはどれか。
ア 一貫性 イ 可用性 ウ 原子性 エ 耐久性
正解は”イ”
ACID特性は原子性・一貫性・独立性・耐久性の4つです。