.NETエンタープライズ
Webアプリケーション開発技術大全

接続型データアクセスと短時間トランザクション

マイクロソフト コンサルティング本部 赤間 信幸
2005/03/15


3.3 マニュアルトランザクション

 引き続き、短時間トランザクション制御方式の1つであるマニュアルトランザクションについて説明する。

 マニュアルトランザクションとは、SqlConnectionオブジェクトが備えるトランザクション制御機能を利用して、中間層からの一連のSQL処理を1つのトランザクションに束ねるというものである(図3-5)。

図3-5 マニュアルトランザクション

 マニュアルトランザクションでは、主にADO.NETの接続型データアクセス方式が利用される※6。実装方法について以下に説明する。

※6 非接続型データアクセス方式(DataAdapterとDataSetを利用する方式)でもマニュアルトランザクションを利用できるが、そのためにはDataAdapterによるデータ更新メカニズムを正しく理解しておく必要がある。詳細は本書「第8章 対話型トランザクション処理の設計方法」の「8.3 楽観同時実行制御による対話型トランザクション処理の設計方法」を参照のこと。

3.3.1 実装方法

 マニュアルトランザクションは、SqlConnectionオブジェクトからSqlTransactionオブジェクトを生成し、各SqlCommandオブジェクトをこのトランザクションオブジェクトに参加させることによって行う。

A. マニュアルトランザクションのコード例

 リスト3-3がそのサンプルコードである。トランザクション分離レベルを指定しながらBeginTransaction( )命令を発行し、各SQL文を実行したのちにコミットまたはロールバックを行う※7

※7 なお、サンプルプログラム中ではパラメタライズドクエリを利用しているが、これはセキュリティ面だけでなく性能面からも非常に有利であるため、積極的に利用することをお薦めする。パラメタライズドクエリを利用しない場合、トラフィックの多いシステムではクエリのリコンパイルが多発してDBサーバのCPUを浪費してしまう恐れがある。SQL Server 2000以降には自動パラメタライズ機能が備わっているものの、必ずしもこれが働くとは限らない。クエリプランのキャッシュ動作や自動パラメタライズの動作条件に関しては、以下のホワイトペーパを参照のこと。"Batch Compilation, Recompilation, and Plan Caching Issues in SQL Server 2005" (http://www.microsoft.com/technet/prodtechnol/sql/2005/recomp.mspx)
 
C#の場合

SqlConnection sqlcon = new SqlConnection("server=localhost;database=pubs;user
id=sa;password=p&ssw0rd;");

SqlCommand sqlcmd1 = new SqlCommand("SELECT price FROM titles WITH (UPDLOCK) WHERE title_id=@title_id", sqlcon);
SqlCommand sqlcmd2 = new SqlCommand("UPDATE titles SET price = @val WHERE title_id=@title_id", sqlcon);

string title_id = "PS2106";

sqlcmd1.Parameters.Add("@title_id", title_id);
sqlcmd2.Parameters.Add("@title_id", title_id);
try
{
   sqlcon.Open();
   SqlTransaction sqltx = sqlcon.BeginTransaction(IsolationLevel.Serializable);
   sqlcmd1.Transaction = sqltx;
   sqlcmd2.Transaction = sqltx;

   SqlDataReader sqldr = sqlcmd1.ExecuteReader();
   if (sqldr.Read() == false)
   {
      sqldr.Close();
      sqltx.Rollback();
      Console.WriteLine("当該IDは存在しません。");
      return;
   }
   Decimal val = (Decimal)sqldr["price"];
   sqldr.Close();

   val = val + 1;
   sqlcmd2.Parameters.Add("@val", val);
   sqlcmd2.ExecuteNonQuery();

   sqltx.Commit();
}
finally
{
   sqlcon.Close();
}
VB.NETの場合

Dim sqlcon As SqlConnection = New SqlConnection("server=localhost;database=pubs;user
id=sa;password=p&ssw0rd;")

Dim sqlcmd1 As SqlCommand = New SqlCommand("SELECT price FROM titles WITH (UPDLOCK) WHERE title_id=@title_id", sqlcon)
Dim sqlcmd2 As SqlCommand = New SqlCommand("UPDATE titles SET price = @val WHERE title_id=@title_id", sqlcon)

Dim title_id As String = "PS2106"
sqlcmd1.Parameters.Add("@title_id", title_id)
sqlcmd2.Parameters.Add("@title_id", title_id)

Try
    sqlcon.Open()
    Dim sqltx As SqlTransaction =
sqlcon.BeginTransaction(IsolationLevel.Serializable)
    sqlcmd1.Transaction = sqltx
    sqlcmd2.Transaction = sqltx

    Dim sqldr As SqlDataReader = sqlcmd1.ExecuteReader()
    If sqldr.Read() = False Then
        sqldr.Close()
        sqltx.Rollback()
        Console.WriteLine("当該IDは存在しません。")
        Return
    End If
    Dim val As Decimal = CType(sqldr("price"), Decimal)
    sqldr.Close()

    val = val + 1
    sqlcmd2.Parameters.Add("@val", val)
    sqlcmd2.ExecuteNonQuery()

    sqltx.Commit()
Finally
    sqlcon.Close()
End Try
リスト3-3 .NETアプリケーションからのマニュアルトランザクションの実施

B. マニュアルトランザクションとデータベースの同時実行制御機能との関係

 リスト3-3のプログラムを実行しつつ、これをSQL Serverの管理ツールの1つであるSQLプロファイラによってモニタリングしてみよう。このようにすると、BeginTransaction( )命令などによって実際にライブラリ内からSQL Serverに発行されたSQL文をキャプチャすることができる。図3-6はその様子を示したものである。

図3-6 リスト3-3によってSQL Serverに送信されたSQL文の内容

 図3-6の実験結果からも明らかなように、マニュアルトランザクションは、先に解説したデータベーストランザクションと同じ操作を、.NETアプリケーションから遠隔操作しているものだということが分かる。つまり、マニュアルトランザクションにおける実際の同時実行制御は、データベースシステムの持つ同時実行制御機能(SQL Serverであればロック機能)によって行われるわけである。異なるのは、遠隔操作によりラウンドトリップ回数が増える点である。

C. ADO.NETにおけるトランザクションプログラミングモデルの注意点

 マニュアルトランザクションは、ADO.NETに限らずほぼすべてのデータアクセステクノロジで用意されているものである。こうしたデータアクセステクノロジの多くでは(例えばADOやJDBC)、コネクションオブジェクトに対してマニュアルトランザクションの開始と終了を宣言するようなプログラミングモデルが採られている。しかしADO.NETの場合には、コネクションオブジェクトから取り出したトランザクションオブジェクトを操作するというプログラミングモデルを採っている。従来とは多少異なるコーディングが必要なため、注意して頂きたい※8(図3-7)。

※8 ADO.NETがこのようなプログラミングモデルを採っているのは、(理論上は)コネクションとトランザクションは一対一に紐づかなくてもよいためである。例えば、1つのコネクションを通して、1人のユーザが複数のトランザクション処理を同時に並列処理することも考えられるが、コネクションとトランザクションが一対一に紐付けられたオブジェクトモデルでは、このような作業は決して実現できない。ただし実際には、SQL Serverを利用する場合でも、1つのコネクション上では1つのトランザクションしか取り扱うことができない。このため、ADO.NET上で1つのコネクションオブジェクトから複数のトランザクションオブジェクトを同時に生成しようとすると、例外が発生する。
  • まず、コネクションオブジェクトに対してトランザクション開始を宣言し、トランザクションオブジェクトを生成する。

  • トランザクションに参加させたいSQL処理を、トランザクションオブジェクトに紐付けた上で実行する。

  • トランザクションオブジェクトに対して、コミットを指示する。

図3-7 ADO.NETにおけるマニュアルトランザクションのプログラミングモデル

3.3.2 メリットとデメリット

 先に述べたデータベーストランザクションとは異なり、このマニュアルトランザクション制御方式を使うと、C#やVB .NETなどのアプリケーションプログラム内から自在にトランザクション制御をかけることができる。パフォーマンスも比較的よく、また後述する自動トランザクションに比べると取り扱いも容易である。このため、このトランザクション制御方式は多くの業務アプリケーションで利用されている。この方式の主なメリットとデメリットは以下の通りである。

A. 主なメリット

 1つのメソッド内で行われる複数のSQL文の処理を手軽に1トランザクション化することができる。また、同時実行制御にはデータベースシステムが持つ機能が直接利用されるため、後述する自動トランザクションに比べて性能がよいというメリットがある※9

※9 ただしストアドプロシージャを用いたデータベーストランザクションとは異なり、ネットワークラウンドトリップが発生するため、データベースとの通信回数がむやみに増えないように注意して設計する必要がある。

B. 主なデメリット

 まず、複数のクラスやメソッドにまたがる処理を1トランザクション化することが困難である。例えば図3-8のように、(再利用性を意識して)分離して設計されたクラスやメソッドの処理を呼び出しつつ、これらを1つのトランザクションに束ねることは困難である。

 もちろん原理的には、呼び出し元となるクラス(図3-8の例では振り込み処理クラス)でコネクションオブジェクトを生成し、これをメソッドパラメータとして下位クラスのメソッドに渡して処理させる、という設計も考えられる。しかしこのような設計は、ビジネスコンポーネント(BC)がデータベース接続の管理責任を担うことを意味するため、データアクセスコンポーネント(DAC)によってデータベースの位置情報などを隠蔽するという、レイヤ構造原則の破損に繋がる恐れがある※10

※10 コネクションオブジェクトの引き回しによるレイヤ構造破損の危険性については、本シリーズ第3巻「ASP.NET応用編」の「2.5.2 HttpContextオブジェクト」の項でも解説しているので、参照のこと。

 あるいは複数のデータベースにまたがる処理や、MSMQ(Microsoft Message Queue)に対するキューイング処理を間に含んだ処理は、マニュアルトランザクションでは1トランザクション化することが物理的に不可能である。

図3-8 マニュアルトランザクションでは制御が困難なケース

 以上のような理由から、マニュアルトランザクションによる短時間トランザクション制御は、以下のような特性を持つアプリケーションに適していると言える。

  • 複雑なクラス分割やレイヤ構造設計を行わないようなアプリケーション

  • データベースアクセス処理を一つのクラス、または一つのメソッド内に局所化できるようなアプリケーション


 INDEX
  .NETエンタープライズWebアプリケーション 開発技術大全
  接続型データアクセスと短時間トランザクション
    1.業務的なトランザクション制御
    2.データベーストランザクション
  3.マニュアルトランザクション
    4.自動トランザクション
    5.短時間トランザクション処理の3つの制御方式の比較
 
インデックス・ページヘ  「.NETエンタープライズWebアプリケーション開発技術大全」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間