今回はデータベースのトランザクションについてお話しします。
データベースを扱う上で必須の知識となる考え方で、トランザクションを使わないと、途中までデータベースの登録・更新・削除処理の途中で問題が起きた時、途中まで登録・更新・削除が行われた状態でデータベースが更新されてしまいます。
このような登録・更新・削除処理を実装するのは非常にまずいので、通常はトランザクションを使って、登録・更新・削除処理を一つにまとめてしまいます。
今回はトランザクションとはどういうものかを説明したうえで、コミット、ロールバック、ロールフォワードについてお話しします。
トランザクションとは何か?
トランザクションとは、データベースの読み書き削除の処理を1つにまとめた一連の処理のことです。
例えば、銀行のATMから預金を引き出す時の処理を考えて見ましょう。
銀行のATMから預金を引き出す時は以下のような手順で預金を引き出します。
キャッシュカード、もしくは通帳をATMに入れる
↓
暗証番号を入力する
↓
引き出す金額を入力する
↓
通帳をATMに入れた場合、通帳の記入が行われる
↓
取り出し口からお金が出てくる
↓
残高が表示される
↓
手続き終了
これらの一連の処理を1つの処理にまとめたものがトランザクションと考えればイメージしやすいのではないでしょうか?
トランザクションを使ったデータベースの登録更新処理を図で表すと以下のような感じになります。
上の図では、非常にシンプルなトランザクションの例ですが、データベースからデータを読み込み、画面からの入力値などを用いて登録、更新を行い、結果に応じて登録、更新を確定するコミットを行うか、登録、更新を無効にするロールバックを行います。
このように1つの処理にまとめることで、途中まで登録が正常にできていたが途中でデータベースの登録、更新が異常終了した場合にその処理をなかったことにすることが出来、途中までデータが登録されて以降のデータがないというおかしな状態にならずに済みます。
トランザクションを使わないと、途中までのデータが登録されて残った状態になるため、これがプログラムの障害の原因になることがあり、データベースへの登録、更新はすべて完了するか、あるいは登録しない状態に戻るかのどちらかの状態にならなければなりません。
トランザクションのコミット
トランザクションとして1つの処理にまとめた処理がすべて正常に終了したら、コミットを行い、処理を確定します。
例えば、先ほどの例に出したトランザクションで何も問題がなければ、以下のように最後にコミットを行います。
トランザクションを使う場合、コミットをしないとデータベースに反映されません。
なので、正常に処理が終了した場合は、データベースに反映させるために必ずコミットを行う必要があります。
実際にプログラムでトランザクション処理を実装する場合は、try~catch文を使って、tryの中の処理にトランザクション処理を書き、try分の最後でトランザクションをコミットする処理を書くようにした方がいいでしょう。
そうすることで、途中でエラーになった場合にcatchの中でロールバックさせることで、問題なくトランザクションを実行することが出来ます。
トランザクションのロールバック
トランザクションの処理中で異常終了した場合、今までのトランザクションで処理していた内容をなかったことにする必要があります。
例えば、以下のように登録処理後の更新処理で異常が発生した場合、登録処理と途中まで行っていた更新処理を元に戻して、トランザクションを実行する前の状態に戻さなければなりません。
この、登録と更新前の状態に戻す処理がロールバックになります。
ロールバックの実装方法はコミットの説明の時に述べた通り、try~catch文のtryの中にトランザクション処理を書いて、catch文の中にロールバックの処理を書くことです。
そうすることで、トランザクションの処理中に問題が発生した場合にcatch文の中の処理を実行するので、ロールバックが出来てトランザクションにより登録、更新がされていない状態に戻ります。
これも出来れば覚えて欲しい。ロールフォワードとは一体何か?
トランザクションを利用する場合に頭に入れておきたいものとして、ロールフォワードがあります。
ロールフォワードとはデータベース障害の復帰のためにデータベース用のハードディスクとは別のハードディスクに更新前ログと更新後ログを用意し、データベースの障害発生時に更新後ログを用いてデータベースの障害発生の前の状態に戻す動作のことです。
更新前ログにはトランザクションの更新前のデータを、更新後ログにはトランザクションの更新後のデータを書き込みます。
以下のようにトランザクションが実行されたとしましょう。
上の図で丸印がついているものがコミットされた状態になります。
チェックポイントというのはデータベースをメモリ上からハードディスク上に書き込むポイントのことを指します。
データベースの更新処理は実際はメモリ上で更新がされている状態で、ハードディスクには不定期で書き込まれるため、コミットしたすべてのデータが瞬時にハードディスクに書き込まれるわけではありません。
そのため、ハードディスクに書き込まれたタイミングをチェックポイントとして取得できるようにしておきます。
上の図のトランザクション1とトランザクション2はハードディスクに書き込まれた状態なので、データベースの障害発生時に特にトランザクションに関して何かをする必要はありません。
問題は赤い矢印で書かれたトランザクション3で、このトランザクションの結果はハードディスクに書き込まれていないため、データベースの障害を復旧した時にチェックっポイントの状態に戻るとトランザクションのコミットの結果が消えてしまいます。
そこで、更新後ログを利用してトランザクション3が実行された時点のデータを復元します。
これがロールフォワードと呼ばれるものです。
なお、トランザクション4はトランザクションのコミットが完了する前にデータベースの障害が起きています。
トランザクション4については更新前ログを用いてロールバックを行うことで、トランザクション4が実行されていない状態に戻す必要があります。
まとめ
今回は以下のことをお話ししました。
- トランザクションとは複数の処理を一つにまとめたもの
- トランザクションの結果は完全に実行された状態か、実行されなかった状態かのいずれかになる
- コミットとはトランザクションの結果を確定させること
- ロールバックとはトランザクションを実行する前の状態に戻すこと
- ロールフォワードとはデータベースの障害発生時にハードディスクに書き込まれていないトランザクション結果をログを用いて復元すること
トランザクションを用いた開発をする場合はコミットとロールバックを知っておけばいいのですが、データベースの運用や保守を行う場合はデータベース障害発生時のロールフォワードとロールバックの考え方も必要になります。
ロールフォワードについては情報技術者試験で問われることがあるため、情報技術者試験を受ける場合はしっかりと理解して点数を落とさないようにしたいものです。
今回の記事はここまでとなります。
また次の記事でお会いしましょう。