データベース千夜一夜第25回

トランザクションの管理(1)~トランザクションの基礎 長谷川裕行
有限会社 手國堂

処理の競合とタイミングの問題

単純な処理でも、ネットワークが絡むと様々な問題を引き起こす可能性をはらんできます。典型的な例で説明しましょう。


- 1人独占なら問題はない -

1人のユーザーが、1つのアプリケーションから1つのデータベースを(ユーザー的にもプログラム的にも)独占して操作できるのであれば、特にトランザクションを管理する必要はありません。

操作を間違えたなら、それを取り消す処理を実行すればよいだけです。例えば商品の販売個数を間違えて入力したなら、その受注を一旦取り消して正しい個数のデータを再入力すればよいでしょう。3個が正当なところを5個と入力したら、いわゆる赤字処理で間違った入力を「-5」として取り消し、新たに「3」と入力し直せば済んでしまいます。

アプリケーションのバグやコンピュータの故障などが原因だったら、別途クエリを発行して正しい状態に書き換えることもできます。とにかく1人でデータベースを占有しているのですから、操作した順に処理が実行されるだけです。


- タイミングの『ズレ』が問題 -

しかし実務では、データベースはネットワークを介してたくさんのユーザーに共有されています。同じアプリケーションが複数のクライアントマシン上で動いていて、それらが1つのデータベースを同時にアクセスしていることもあるでしょう。また、異なるアプリケーションがそれぞれ随時に1つのデータベースをアクセスする場合もあります※2

例えば、このコラムで例にとっている販売・受注管理システムなら、たくさんの端末から同時に複数の受注情報が記録されるのが普通です。また、それと同時に在庫管理システムが商品の在庫情報を書き換えるでしょうし、商品管理システムが商品マスターそのものを(例えば、価格変更や仕様変更などの事由で)書き換えることもあり得ます。

「同時に」という表現を使いましたが、実際には同じタイミングで1つのデータベースを異なる端末からアクセスすることはできません。わずかなタイミングの『ズレ』が生じます。すると、どちらの端末が先にアクセスしたのか──という状態によって、結果が異なることになります。

※2 先に触れた赤字処理にしても、複数の端末で1つのデータベースを共有する場合には、トランザクションを管理して矛盾をなくす仕組みが取り入れられています


- 2件の更新処理 -

商品管理を例にとりましょう。

a)商品管理部門で単価を見直した結果、全商品の販売単価を10%増しすることになりました。
  UPDATE 商品_mr
  SET 販売単価=販売単価*1.1

b)販売部門で特別キャンペーンを実施し、「商品ID=550501/ティーポット」の販売単価を100円引きすることになりました。
  UPDATE 商品_mr
  SET 販売単価=販売単価-100
  WHERE 商品ID = 550501

「ティーポット」の元の販売単価は2,500円ですから、a)を適用すればそれが2,750円になります。その後b)を適用して、最終的な販売単価は《2,650円》ということになるはずです。が、もし販売部門のb)の操作の方が先に実行されたとすると、まず100円引きで2,400円となった後にa)が適用され、最終的に《2,640円》になります。

2つの処理の実行順が変わると、このように10円の差が生じます。こういった時差による問題は、至る所で発生する可能性があります。極端な場合、「ある商品が販売されて在庫が0になった」→「在庫情報がテーブルに反映される直前に、もう1件同じ商品が販売された」という形で在庫がマイナス(負の値)となることもあるでしょう。


- 内部の処理順が問題を引き起こす -

実際の業務処理では、書き換えたいデータを先にまとめて入力しておき、バッチ処理で一気にテーブルを更新するのが普通です。従って、更新データを作成する前に部署同士で調整を図り、先に(上の例なら、全体の10%増しか個別商品の100円引きか)どちらを優先して更新するのかを決めておくことになるでしょう。

そういったユーザー側のやりくりによってすべての矛盾を回避できればよいのですが、現実はそう単純ではありません。

もし、トランザクションの管理機能を持っていないDBMSでこの2つの処理を続けて行った場合、a)の一括更新で「ティーポット」の販売単価が更新される前にb)の100円引きの処理が実行されてしまうこともあり得るのです。



- トランザクション管理で解決! -

DBMSがトランザクションを管理していれば、このような競合や時差によって発生するデータの矛盾や予想外の結果を防ぐことができます。先述したように、トランザクションとはデータベース・エンジンがデータベースに対して実行する一連の変更処理のことで、最終的にトランザクションを確定することで一連の処理が確定し、データベースの変更も確定します。

データベース・エンジンには、複数の端末からたくさんの処理命令が届きます。たとえ1件のUPDATE命令でも、実際には細かな複数の処理の連続です。そしてデータベース・エンジンは、そういった命令群を次々と処理していきます。

トランザクションを管理すると、それら多数の命令群を受け取るたびに逐一実行するのでなく、一旦蓄積しておいて、結果に矛盾を生じさせないよう整理してから実行するようになります。

こうすることで、例えば先の『10%増し/100円引き』処理ならば、まず全体の更新処理a)が終わるまで同じテーブルに対する処理b)を行わないで待機させ、競合による矛盾の発生を防ぎます。


ユーザー側で競合を防ぐ知恵

ネットワーク環境では、データベース処理の競合を防ぐことが重要な課題となります。トランザクション管理をうまく使うことはもちろん大切なテクニックですが、トランザクションはあくまでDBMS内部の機能であり、それだけですべての問題が解決できる訳ではありません。可能な限り『競合を回避できるシステム設計』を目指す必要があります。

ここで言うシステムは、単に「アプリケーションの集合」という意味だけではなく、ハードウェアやネットワーク環境、さらにそれらを操作する人間(ユーザー)や関連部署同士の連携まで含めた『総合的な意味でのシステム』です。

特に商品や社員などの情報を記録したマスターテーブルの保守作業は、アプリケーションレベル、あるいはDBMSレベルでの競合回避策を練る以前に、通常業務(受注・仕入・勤怠・入出金などなど)に支障が出ないよう配慮すべきです。

まず、1つのマスターに対して複数の部署が同時に保守を行うような作業形態は御法度だと捉えておきましょう。本文で例に出したような商品の販売価格変更作業は、通常ではあってはならないことです(あくまで、競合を説明するための一例です)。

商品は在庫管理担当、顧客は営業担当……などと専任部署または担当者を決め、他部署と関連するような変更を行う場合は事前に変更内容を確認して、実際の操作は専任者が行う──という形にします。

また、通常業務が平日(月~金)の日中(9:00~17:00)行われるのであれば、マスターの保守はそれ以外の日時に行うのが一番安全です。多くの場合、変更内容は事前に用意したデータを読み込ませて一括処理するのが普通なので、大きな手間はかかりません。勤務時間をシフトすれば、超過勤務の必要もないでしょう。


トップページ
トランザクションとその管理
処理の競合とタイミングの問題
1人独占なら問題はない
タイミングの『ズレ』が問題
2件の更新処理
内部の処理順が問題を引き起こす
トランザクション管理で解決!
トランザクション管理の実際
トランザクション管理を試す
あとがき
Copyright © MESCIUS inc. All rights reserved.