前号: No 329 / 次号: No 331 / 一覧(note.com)へ / ブログページに戻る
前回は、2023年10月10日から11日にかけて発生した全銀ネットのトラブルについてお話しました。 本件には行政側からも指導があったようで、11月末までに事故報告書を作成して公開することになっているようです。 その時点で改めて解説をしようと考えています。 さて、前回は軽くお話した「トランザクション処理」をもう少し詳しくお話します。1. トランザクション処理とは?
前回のおさらいとなりますが、トランザクション処理というのは、処理結果に矛盾がないように制御する手法を言います。 一つの取引が完了した時点では、以下のいずれかになるはずですよね。 1. 依頼内容が全て処理が完了した 2. 依頼内容は全て元通りに戻した ですが、普通にプログラムを組んでいるとこうはいかない事情がたくさんあります。 その難しさを示す典型例が銀行の振込などの送金処理です。 同じ銀行に口座を持っているAさんからBさんに3万円を振込むとします。 この実現には次の二つの処理が必要です。 1. Aさんの口座から3万円を減算する 2. Bさんの口座に3万円を加算する この通りに処理を淡々と行うわけですが、途中でエラーが発生するといきなり問題が難しくなります。 エラーといっても、プログラムで把握できるエラーならいいのです。 例えば、支払い元(Aさん)側の残高不足、口座凍結、受取り側(Bさん)の口座番号間違いなどは最初から処理に着手しませんから、問題は起きません。 問題になるのは、途中でエラーが発生した時です。 特にAさんの口座からの減算後にエラーが発生すると非常にやっかいなことになります。 例えば、バグでプログラムが異常終了したらどうなるでしょうか? Aさんの口座は減ったままで、Bさんへの入金が行われません。 お金がどこかに消えてしまいます。 AさんとBさんへの処理順序を入れ換えても同様ですよね。 今度はどこからともなく、お金が生まれたことになります。 これが致命的なのはわかりきった話です。 このような矛盾を残さないために「トランザクション処理」があるのです。 でも、プログラムが落ちたりした時にどうするのよ?って思いますよね。 その話をご理解いただくため、少しトランザクション処理の内側に踏み込みましょう。2. トランザクション処理の実際
トランザクション処理は、データベース内の矛盾を避けるためによく利用されます。 上述の送金処理などがその代表的なものです。 データベースは通常、専用のソフト(データベースソフト)で管理を行います。 データベース内のデータを更新する時は、依頼元(プログラム)がデータベースソフトに「○○を更新してください」と依頼するわけです。 ですが、データベース側は同時に1つの更新しかできない制約があります。(厳密にはいろいろありますが、ここでは単純化のために省略します) そのため、Aさんの口座からの減算の依頼と、Bさんの口座への加算の依頼は、依頼元(プログラム)から、二回に分けて依頼することになります。 つまり、データベース側には「今から二回に分けて依頼するけど、これはワンセットだよ。失敗したら両方とも元に戻してね」と伝えておかなければなりません。 そのため、依頼元(プログラム)は処理の依頼前には「トランザクション開始」を、処理の依頼後には「トランザクション完了」をデータベースに伝える必要があります。 つまり、こんな形で依頼を送ることになります。 1. トランザクション開始を宣言する 2. Aさんの口座から3万円を減算する 3. Bさんの口座に3万円を加算する 4. トランザクション完了(コミット)を宣言する 処理中にエラーが発生した場合には巻戻し(ロールバック)を宣言します。 ロールバックが行われると、データベースソフトは必ず開始宣言前の状態に戻してくれます。(データベースソフトが落ちようと、電源が落ちようと、です) 実にシンプルな仕組みですが、トランザクション処理によってデータの整合性を確実に保つことができます。 トランザクション処理はデータが矛盾しないことを保証してくれるとても重要な機構なのです。 さて、冒頭に書いたようにプログラムが落ちた場合は誰もロールバックなどしてくれません。 この場合は、データベース側は接続先からの反応が一定時間ないことから「落ちたな」と判断し、自動的にロールバックをすることになっています。 これもまた、トランザクション処理が実現してくれる大切な機構です。3. さらにやっかいな同時処理
トランザクション処理は、さらにやっかいな同時処理の問題にも対応ができます。 上述のAさんからBさんへの送金に加えて、CさんからAさんへの送金がほぼ同時に行われたとします。 手続きとしては、以下の二つです。 1. AさんからBさんに3万円の送金 2. CさんからAさんに5万円の送金 この処理を行った結果、次の残高になるのが期待値です。 Aさん:10万円 → −3万円+5万円=12万円 Bさん:10万円 → +3万円 =13万円 Cさん:10万円 → −5万円=5万円 当然ながら、全員の残高を合計すると処理前も処理後も30万円で変化ありません。 (手数料は考えません) この場合、以下の4つの処理が行われます。 1. Aさんの口座から3万円を減算する(→7万円に更新) 2. Bさんの口座に3万円を加算する(→13万円に更新) 3. Cさんの口座から5万円を減算する(→5万円に更新) 4. Aさんの口座に5万円を加算する(→12万円に更新) さて、この処理には残高異常の可能性があるのですが、お気付きでしょうか? AさんからBさんへの送金と、CさんからAさんの送金タイミングがほぼ同時だと計算結果が期待通りにならない場合があります。 ここで、上述の1. と 4. の処理をさらに詳細化しておきます。 ○1. Aさんの口座から3万円を減算する(→7万円に更新) 1-1)Aさんの残高(10万円)をデータベースから取得 1-2)10万円−3万円=7万円を計算 1-3)7万円でデータベースを更新 ○4. Aさんの口座に5万円を加算する(→12万円に更新) 4-1)Aさんの残高(7万円)をデータベースから取得 4-2)7万円+5万円=12万円を計算 4-3)12万円でデータベースを更新 問題は、4.の開始タイミングです。 例えば、これが上で書いた通りに行われた場合は問題にはなりません。 1-1)Aさんの残高(10万円)をデータベースから取得 1-2)10万円−3万円=7万円を計算 1-3)7万円でデータベースを更新 4-1)Aさんの現在の残高(7万円)をデータベースから取得 4-2)7万円+5万円=12万円を計算 4-3)12万円でデータベースを更新 また、先に4.の処理を行った場合も途中の計算は違いますが、問題ありません。 4-1)Aさんの現在の残高(10万円)をデータベースから取得 4-2)10万円+5万円=15万円を計算 4-3)15万円でデータベースを更新 1-1)Aさんの残高(15万円)をデータベースから取得 1-2)15万円−3万円=12万円を計算 1-3)12万円でデータベースを更新 ところが、4-1〜4-3の処理が1-1〜1-4の途中にはさまると問題になります。 1-1)Aさんの残高(10万円)をデータベースから取得 4-1)Aさんの現在の残高(10万円)をデータベースから取得 4-2)10万円+5万円=15万円を計算 4-3)15万円でデータベースを更新 1-2)10万円−3万円=7万円を計算 1-3)7万円でデータベースを更新 なんと、残高が7万円になってしまいます。 また、次のパターンでもおかしくなります 1-1)Aさんの残高(10万円)をデータベースから取得 4-1)Aさんの現在の残高(10万円)をデータベースから取得 1-2)10万円−3万円=7万円を計算 1-3)7万円でデータベースを更新 4-2)10万円+5万円=15万円を計算 4-3)15万円でデータベースを更新 今度は残高が15万円になってしまいます。 個々の処理は間違っていないのに全体としては間違った結果になってしまいます。 このような事象が生じるのは残高の取得と更新が同時に行えないためです。 要は、残高の取得から更新までにタイムラグがあることが問題なのです。 トランザクション処理はこのようなタイムラグが問題となるケースにも威力を発揮します。 トランザクションの開始後から完了宣言(コミット)までの間に来た依頼(他の処理)は待ってもらえば、このタイムラグは気にしなくてよくなります。 例えば次のようになります。(さらに手順が複雑になりますが...) 1-1)Aさんの残高(10万円)をデータベースから取得 4-1-1)Aさんの現在の残高を取得(待たされる) 1-2)10万円−3万円=7万円を計算 1-3)7万円でデータベースを更新 4-1-2)ここでようやく残高(7万円)が取得できる 4-2)7万円+5万円=12万円を計算 4-3)12万円でデータベースを更新 こうすれば、4.の処理(Aさん口座の加算処理)は1.の処理(Aさん口座の減算処理)が完了してから動きますから、矛盾が生じないわけですね。4. まとめ
トランザクション処理というのは、処理エラーの発生やタイミングによるデータベースの矛盾を予防する仕組みです。 これは銀行のような金銭を扱う業務だけではありません。 在庫量の計算、生産実績の更新、保有ポイントの計算など数値の更新が必要なケースでは頻繁に利用されています。 システム開発者がデータベースソフトを採用する理由として「トランザクション機能」はかなり上位に出てきますし、トランザクション処理のないデータベースソフトはなかなか一人前扱いされません。 もっとも、トランザクション処理はできなくても、やたら高速、めっちゃコンパクトといったデータベースソフトもありますので、どちらがエラいという話ではありません。 今回は、トランザクション処理機能についてのお話でした。 次回もお楽しみに。
前号: No 329 / 次号: No 331 / 一覧(note.com)へ / ブログページに戻る