多个控制台应用程序使用EF objectcontext

时间:2015-11-04 12:46:23

标签: c# sql entity-framework objectcontext

我有多个控制台应用程序,但他们会读取并插入更新相同的sql表。我使用了transactioncope但是我收到了这个错误 “事务(进程ID)在锁资源上与另一个进程陷入僵局,并被选为死锁受害者。重新运行该事务。”

我在catch块中遇到异常。我怎么能避免这个? 我知道问题是什么,但我不确定应该是什么解决方案。我在不同的论坛上看到了很多问题,但没有一个真正帮助过我。

我的代码中的一切都很好吗?

bool isMaster = false;
tourneyInstanceTrackerId = 0;
using (JG_RummyEntities dbContext = new JG_RummyEntities())
{
try
{
using (TransactionScope transaction = new    TransactionScope(TransactionScopeOption.Required,new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead }))
                {
bool isAnyMaster = dbContext.TourneyInstanceTrackers.Any(t => t.IsMaster & t.TournamentId == tournamentId);
TourneyInstanceTracker tourneyInstanceTracker = new TourneyInstanceTracker
                    {
                        TournamentId = tournamentId,
                        IsMaster = !isAnyMaster,
                        CreateDate = DateTime.Now
                    };
                       dbContext.AddToTourneyInstanceTrackers(tourneyInstanceTracker);
dbContext.SaveChanges();
                    var result = dbContext.TourneyInstanceTrackers.Where(t => t.TournamentId == tournamentId)
                            .OrderByDescending(t => t.CreateDate)
                            .Select(t => new { t.IsMaster, t.Id })
                            .FirstOrDefault();
                    if (result != null)
                    {
                        isMaster = result.IsMaster;
                        tourneyInstanceTrackerId = result.Id;
                    }
                    transaction.Complete();
                }
            }
            catch (Exception ex)
            {
                Logger.Log("Got exception in SetTournamentInTourneyInstanceTracker : " + ex.Message + ", " + ex.StackTrace + ", "+ tournamentId);
            }
        }

1 个答案:

答案 0 :(得分:2)

IsolationLevel.RepeatableRead的作用类似于ReaderWriterLockSlim,许多线程可以同时读取记录但是只要有人想写,你就必须等待所有读者完成然后对其进行独占锁定。直到你完成写作为止。

所以想象你有一个程序,它读取对象“A”等待一点然后写入对象“A”。现在让我们看一下程序的两个副本运行时会发生什么。

Program 1     Program 2
---------     ---------
Begin Trans   Not Started
Read A        Begin Trans
Wait          Read A
Try Write A   Wait
Try Write A   Try Write A
Try Write A   Try Write A
Try Write A   Try Write A

您可以看到程序1正在等待程序2释放其读锁定,但是程序2在程序1释放其读锁定之前无法释放其读锁定。这两种情况等待另一方完成的情况称为死锁

有两种解决方法,一种是你可以使用限制性更强的IsolationLevel.Serializable,这会阻止其他读者,直到交易结束。

Program 1     Program 2
---------     ---------
Begin Trans   Not Started
Read A        Begin Trans
Wait          Try Read A
Write A       Try Read A
End Trans     Read A
              Wait
              Write A
              End Trans

另一个是你遵循异常的建议,在捕获异常的代码块上再次重新运行该函数,直到它通过而没有另一个程序副本阻止它。