はじめに

本稿はあくまでデータベース共通なので、概念や基本的な意味だけを記すことにし、具体的なSQLなどは載せませんので、あらかじめご了承ください。

不可分操作(アトミック操作)

トランザクション処理

トランザクション

トランザクション(Transaction)とは、データベースの世界において、データベースに対する一連の処理をまとめた処理単位です。元来、Transactionには「取引」という意味があるようですが、これはデータベースのトランザクションの定義からも理にかなった命名でしょう(後述します)。

Transaction = (処理1, 処理2, ..., 処理n) ※処理i=単体実行できない処理

トランザクションの簡単な定義は以下のようになります。

  • それぞれ不可分な処理から構成されている
  • トランザクション処理は内包する操作群の全成功全取消を保証する(アトミック実行)
  • 全ての処理が上手くいけばコミット(Commit)して変更内容を確定させる。また、どれか一つでも途中で処理が失敗したら、ロールバック(Rollback)してデータベースの状態をトランザクション開始時点まで戻す。

さて、これらのことをわきまえた上で、なぜ取引が理にかなっているのか考えましょう。

ここでは「ネットショッピング」を取引の例として考えます。トランザクションとは複数の処理をまとめた処理単位なので、この取引に含まれる処理をすごーく簡略化すると以下のようになります。※代金先払いを仮定しています

  • トランザクション:ネットショッピング
    • 処理1:商品を注文する
    • 処理2:代金を振り込む
    • 処理3:商品が届く

たった3つの処理を抽出しましたが、大体こんなところですかね。

さて、当たり前のことですが、これらの3つの処理が滞りなく全て終わって取引が完了します。どれか一つでも失敗すると、快く取引完了とはなりません。処理1が失敗すると、そもそも注文自体が発生しませんし、処理3の失敗など最悪です・・・

このようにどれか一つでも欠けると全体がダメなり整合性が取れなくなるような処理の集まりがトランザクションなのです。また、それぞれの処理が不可分、つまり単独で実行することが出来ない(出来ても整合性が取れなくなる)ということなのです。

商品を注文するだけで満足する方は恐らくおらず、必ず商品の到着を期待します。また、寄付とちがってネットショッピングにおいてお金だけ振り込む人はいません。ましてや、商品が知らない間にお金も払わず勝手に届くことも普通はないですよね? 注文して代金を払ったのに商品がこなければ、自分の中で整合性が取れなくなります。逆に、振り込んでも無いのに商品が届いても、???っとなりますね。

ロールバック

さあ、では処理が途中でミスった場合はどうするのか考えます。例えば、処理1の商品注文が失敗した状況で処理を継続してはダメですよね?注文失敗により商品自体が確定していないので、代金を請求できるはずもなく振り込めるわけありません。また、処理3が失敗し、代金支払い済みにもかかわらず商品が来なければ、取引は終了にできません。このような場合、現状を取引開始前(商品注文前)に戻すことで整合性が取れるようにします。これをデータベースではロールバックといいます。

ロールバックではある処理が途中で失敗した場合、それ以前の処理を全て取消します。今回の場合は、処理3が失敗したら処理1と2も取消します。このようにすることで、中途半端で整合性がめちゃくちゃな状態なまま放置せずに、トランザクション実行前の正しい状態に戻します。これは、トランザクション定義のところの「全取消を保証する」の部分に該当します。

ちなみに今回の例では、処理2の取消とは返金のことで、処理1の取消とは注文履歴の削除などでしょうか・・・(例なので細かいことはムシムシ)

 セーブポイント

DBMSによって異なりますが、通常ロールバックを行うと、トランザクションの開始時点にまで状態が戻されます。しかしながら、処理の多いトランザクションであれば、完全に開始時点に戻ってしまうのはやや不便です。そこで、セーブポイントを使います。セーブポイントは、トランザクションの要所要所に設定でき、ロールバックの戻り位置とすることが出来ます。例えば、(処理1, 処理2, 処理3, 処理4)というトランザクションあったとします。さて、処理4の実行が失敗してロールバックを行うとどうなるでしょうか?普通なら、処理1の開始前まで戻ってしまいます。しかし処理1が物凄く時間のかかる処理だったら、処理1は成功したにもかかわらず何度も行うのは効率が悪いですね。そこで、次のようにセーブポイントを設定したらどうでしょうか?

(処理1, 処理2, [セーブポイント] 処理3, 処理4)

この場合、処理4が失敗してロールバックを行っても、状態が戻される位置は処理2の終了後(処理3の開始前)です。このように、トランザクション中の要所要所にいくつでもセーブポイントを設定することができ、トランザクション処理を完全に初期化することを防いでくれる仕組みで。

コミット

先ほどのロールバックは、トランザクション処理が途中で失敗したときに、途中まで生じた変更を全て元の状態に戻すことでした。一方、このコミットはトランザクション処理が完了した場合に、その変更を確定させデータベースに反映させることです。

ちなみに、これらのトランザクションという機能ですが、デフォルトで有効になっているOracleや、そもそも使えないDBMS、また明示的に有効化しないといけないものなど多種多様です。よって、Oracleなどではこのコミットをしないと、テーブルへの変更が実際に反映されません。

このコミットですが、データベース変更内容を反映させ永続化をするので、ロールバックで元の状態に戻すことはできません。