我有多个控制台应用程序,但他们会读取并插入更新相同的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);
}
}
答案 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
另一个是你遵循异常的建议,在捕获异常的代码块上再次重新运行该函数,直到它通过而没有另一个程序副本阻止它。