2017-06-23 15 views
0

私は教育の仕事をしており、私のコードで何が間違っているのか分かりません。私は、DBテーブルを更新し、トランザクションでこのロジックを分離しようとしています。最後に、私はデッドロックを取得します。私が間違っていることを誰かに説明することはできますか?
ここに私のスレッドの作成ロジック:EF:複数のスレッドで同じDBテーブルの行を更新します。

for (int i = 0; i < 10; i++) 
{ 
    var thread = new Thread(() => UpdateOrder(orderId)); 
    threadList.Add(thread); 
    thread.Start(); 
} 
foreach (var t in threadList) 
{ 
    t.Join(); 
} 
//Display sum by order items amount and amount property from order entity 
WriteAmount(orderId); 

そしてUpdateOrder方法

public static void UpdateOrder(int orderId) 
{ 
    using (var db = new OrderContext() 
    { 
     using (var transactionScope = new TransactionScope(TransactionScopeOption.RequiresNew 
      ,new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead })) 
     { 
      var o1 = new OrderItem { Title = "title", Amount = 50, Count = 1, OrderId = orderId }; 
      db.OrderItems.Add(o1); 
      var order = db.Orders.Find(orderId); //Include(o => o.Items).Single(o => o.Id == orderId); 
      order.Amount += 50; //order.Items.Sum(oi => oi.Amount); 
      db.SaveChanges(); 
      transactionScope.Complete(); 
     } 
    } 
} 

私は、スレッドごとに独自のコンテキストを作成しました。私のDBがデッドロックを検出するのはなぜですか?
これは例外メッセージです:"トランザクション(プロセスID 51)が別のプロセスでロックリソースにデッドロックされ、デッドロックの対象として選択されました。トランザクションを再実行してください。
ありがとうございます!

+0

おそらく、すべてのコンテキストとトランザクションでOrderItemsテーブルで書き込みロックが必要で、読み取り操作が完了するまでロックが解除されないためです。この結果、9つのコンテキストのデッドロックが発生します.2PLでは動作しません。また、DbContextはスレッドセーフではないことに注意してください。マルチスレッド環境で使用する場合、DbContextが完璧に動作することは期待できません。 – DevilSuichiro

答えて

1

データベース側で問題があります。 IsolationLevel.RepeatableReadトランザクションタイプを使用したのはなぜですか?これが原因だとします。 異なる分離レベルについては、https://docs.microsoft.com/en-us/sql/t-sql/statements/set-transaction-isolation-level-transact-sqlをご覧ください。

1.隔離レベルをデフォルトのREAD COMMITTED に変更します。2. order.Amount += 50;を削除します。代わりに、OrderItems表のINSERT/UPDATE/DELETEイベントを処理し、Orders表を変更するためにデータベース側にトリガーを作成します。

+0

'IsolationLevel.RepeatableRead'を設定した場合、注文アイテムによる最終的な' Sum'は 'Order'の' Amount'プロパティと等しくありません。 – user3818229

+1

もちろん。これは、並列トランザクションから計算しようとしているために発生しています。したがって、並列スレッドから同じデータを同時に変更しようとしています。あなたが運が良ければ、データベースからトランザクションのデッドロックを取得しなくても、間違ったデータで更新されます。注文総額を読み、この番号をデータベースに書き込む(2つの連続したコード行であっても)、注文項目の数を変更することができるので、確実にするにはトリガーが必要です。これらは、データの一貫性を維持するためにDBMSで設計されています。 – Kantora

+0

データベースツールだけを使用してマルチスレッドの問題を修正する別の方法はありません。私はテーブルでいくつかの行をロックすることができますか? – user3818229

関連する問題