ロスト アップデートとその解決方法 その 2

前回のロスト アップデートとその解決方法 その 1 では自動トランザクション (TransactionScope) を
利用したコードを示しましたが、今回は手動トランザクションを利用したコードを示します。

ただし、特に説明する部分はないので、ステップ 3 (Read Committed & UPDLOCK) の場合のみ示します。
TransactionScope クラスの代わりに SqlTransaction クラスを利用するだけです。


using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace LostUpdate
{
    class Program
    { 
        private const string NorthwindConnectionString = @"Data Source=.\SQLExpress;Initial Catalog=Northwind;Integrated Security=True"

        private const string SelectCommandText = "select UnitsInStock from Products with (updlock) where ProductID = 1"
        private const string UpdateCommandText = "update Products set UnitsInStock = @UnitsInStock where ProductID = 1";

        static void Main(string[] args) 
        { 
            Parallel.For(0, 100, i => AddUnitsInStock()); 
        } 

        /// <summary>
        /// Northwind データベースの Products テーブルの UnitsInStock の値を 1 だけ増加させます。
        /// </summary>
        private static void AddUnitsInStock() 
        { 
            try
            { 
                short oldValue, newValue; 

                using (var connection = new SqlConnection(NorthwindConnectionString)) 
                { 
                    // データベース接続を開きます。
                    connection.Open(); 

                    // トランザクションを開始します。
                    SqlTransaction transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted); 

                    // 在庫個数を取得します。
                    using (var command = new SqlCommand(SelectCommandText, connection) { Transaction = transaction }) 
                    { 
                        oldValue = (short)command.ExecuteScalar(); 
                    } 

                    // 在庫個数を 1 だけ増加させます。
                    newValue = (short)(oldValue + 1); 

                    // 在庫個数を更新します。
                    using (var command = new SqlCommand(UpdateCommandText, connection) { Transaction = transaction }) 
                    { 
                        command.Parameters.AddWithValue("@UnitsInStock", newValue); 
                        command.ExecuteNonQuery(); 
                    } 

                    // コミットします。
                    transaction.Commit(); 
                } 

                Console.WriteLine("{0} → {1}", oldValue, newValue); 
            } 
            catch (SqlException ex) 
            { 
                Console.WriteLine(ex.Message); 
            } 
        } 
    }
}


バージョン情報
.NET Framework 4
SQL Server 2008, 2008 R2

コメント / トラックバック1件 to “ロスト アップデートとその解決方法 その 2”

  1. ロスト アップデートとその解決方法 その 1 « Do Design Space Says:

    […] ロスト アップデートとその解決方法 その 2 に手動トランザクションを利用したコードを、 ロスト アップデートとその解決方法 その 3 に ADO.NET Entity Framework を利用したコードを載せました。 […]


コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。