「更新処理とトランザクション編」では,データベースの更新処理とトランザクション処理が行われる時のRDBMSの動作について説明しました。その時の説明は,あくまでも1つのトランザクションが実行される時のものでした。でも,実際にアプリケーションが完成し動作する時には,複数のトランザクションが同時に実行されることになります。

 アプリケーション開発者は,個々のトランザクションを実現することはもちろんのこと,それらのトランザクションが同時に実行されることも意識する必要があります。

 データベース・アプリケーションを開発していて,「単体トランザクションを動作させている時は何の問題も無かったが,ほかのトランザクションを同時に動作させたら問題が発生してしまった」といった経験はありませんか。あるトランザクションがほかのトランザクションの影響を受けてしまう。これはよくあることです。このような時のために,RDBMSはそれぞれのトランザクションの独立性(どの程度ほかのトランザクションから影響を受けてもよいか)を保つための機能を備えています。

 トランザクションが複数同時に実行される時,RDBMSはどのような仕組みで,それぞれのトランザクションの独立性を保つのかを説明します。これを理解することにより,さらに良いトランザクション処理のアプリケーションを開発することができるようになります。

 今回使用するサンプル・データベースには,2つのテーブルがあります(図1)。1つは商品テーブルで,もう1つは販売実績テーブルです。販売実績テーブルにはすでに100件のレコードが存在しています。この2つのデータベースを使用する,2つのトランザクション処理が実行されるものとします。

図1●サンプル・データベース
図1●サンプル・データベース

 1つめのトランザクションは,商品に関するものです。商品テーブルに含まれている商品AとBの価格には関連があり,商品Bの価格は商品Aの価格の2割と決まっているとします。現在は,商品Aの価格が3000円で,商品Bの価格はその2割の600円となっています。

 ここで,商品の値上げを考えます。商品Aを4000円にすることになりました。すると,商品Bは800円にしなければなりません。アプリケーションが実現するトランザクションは,『商品Aの価格を4000円に変更しそれに伴って商品Bの価格を800円に変更する』です。

 このトランザクションを実現するための更新処理には以下の2つのSQL文の実行が必要です。これを,トランザクション1とします(図2の上)。

 2つめのトランザクションは,商品の販売に関するものです。商品AとBは,必ずセットで販売されるという業務ルールがあるとします。そこでアプリケーションは,以下のトランザクションを実現するものとします。『2008年3月10日に顧客番号「1001」の顧客に商品Aと商品Bを販売した』です。

 このトランザクションを実現するには以下の4つのSQL文の実行が必要です。これを,トランザクション2とします(図2の下)。

■トランザクション1
[SQL文1] 商品Aの価格を更新する
UPDATE 商品テーブル SET 価格 = 4000 WHERE 商品番号 = 100;
[SQL文2] 商品Bの価格を更新する
UPDATE 商品テーブル SET 価格 = 4000×0.2 WHERE 商品番号 = 200;

■トランザクション2
[SQL文1] 商品Aの価格を取得する
SELECT 価格 FROM 商品テーブル WHERE 商品番号 = 100;
[SQL文2] 商品Aの販売実績を挿入する
INSERT INTO 販売実績 VALUES (‘20080310’,100,1001,取得した金額);
[SQL文3]  商品Bの価格を取得する
SELECT 価格 FROM 商品テーブル WHERE 商品番号 = 200;
[SQL文4]  商品Bの販売実績を挿入する
INSERT INTO 販売実績 VALUES (‘20080310’,200,1001,取得した金額);
図2●サンプル・トランザクション

同じタイミングで実行するとどうなるか

 では,このトランザクション1とトランザクション2が同時に実行されたらどうなるでしょうか。もちろん,同時といってもRDBMSが要求を受け付け,トランザクションを開始するのは必ずどちらかが先でどちらかが後になります。時間にすれば数ミリ秒の差かもしれませんが,人間の感覚としてはまさに同時です。こうしたケースでは,一方のトランザクションの終了を待って次のトランザクションを開始する,といったことにはなりません。たとえRDBMSがSQL文を一つひとつ処理したとしても,トランザクションに複数のSQL文が含まれていれば,2つのトランザクションは同時に処理させることになります。ここでは,図3のように実行されたとします。

図3●複数のトランザクションの同時実行
図3●複数のトランザクションの同時実行
[画像のクリックで拡大表示]

 注目したいのは,トランザクション1のSQL文2です。商品テーブルにある商品番号200の価格を更新しています。その価格はトランザクション2で取得しますが,その時,取得した価格はいくらになるのでしょうか。トランザクション2が始まる前は600円ですが,トランザクション1のSQL文2が実行された後では800円です。このケースでは600円であるべきでしょうが,RDBMSの設定によっては800円になることもあります。ほかのトランザクションの影響を受けるとは,例えばこういうことを指しています。

 大抵のRDBMSは,ほかのトランザクションからの影響を制御する機能を備えています。それを,「トランザクションの分離レベル」と呼びます。このトランザクションの分離レベルには4種類あります。

・リードアンコミッティド 1番ゆるい分離レベル
・リードコミッティド 2番目にゆるい分離レベル
・リピータブルリード 3番目にゆるい分離レベル
・シリアライザブル 1番きつい分離レベル

 「ゆるい」「きつい」とは分離度合いを指しており,言い換えれば,ほかのトランザクションからの影響の受け入れ度合いのことです。ゆるい=受け入れる,きつい=受け入れない,という意味になります。

 RDBMSによっては,4つの分離レベルのすべてを備えていないものもあります。分離レベルという言葉を,英字表記でアイソレーション・レベル(Isolation Level)と記載されているドキュメントもあります。

 複数のトランザクションを同時に実行する場合は,この4種類の分離レベルのどれかを選択して設定する必要があります。複数のトランザクションが同時に実行される状況下では,どの分離レベルを設定するかによって,処理結果に影響が出ることもあります。次回以降,それぞれの分離レベルの内容や,処理例を解説します。


藤塚 勤也(ふじづか きんや)
NTTデータ 基盤システム事業本部
オープンソース開発センタ 技術開発担当
シニアスペシャリスト
 沖電気工業,タンデムコンピューターズ(現日本HP)を経て,2003年より株式会社 NTTデータに勤務。現在は,オープンソース・ソフトウエアを活用したエンタープライズ・システム向けの技術開発・技術支援に従事しており,特にシステムの中核であるRDBMSに注力している。「RDBMS解剖学」(翔泳社)を共著