多个控制台应用程序使用EF objectcontext更新相同的sql表格
问题描述:
我有多个控制台应用程序,但他们会读取和插入更新相同的sql表。我使用了transactionscope,但是我收到了这个错误 “事务(进程ID)与另一个进程在锁资源上死锁,并且被选为死锁受害者,重新运行事务。多个控制台应用程序使用EF objectcontext更新相同的sql表格
我在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);
}
}
答
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
另外就是你按照异常的建议,这引起你重新运行异常再次功能,直到它获得通过没有计划阻止它的另一个副本的代码块。
感谢您的回复。我将IsolationLevel更改为Serializable,但这也没有帮助。这是我得到的错误,从商店提供商的数据阅读器读取时发生错误。有关详细信息,请参阅内部异常。在System.Data.Common.Internal.Materialization.Shaper'1.StoreRead()。我在互联网上检查确实是同样的错误。只是FYI我的SQL表只有4列一个是ID是IDENTITY(1,1)的主键,其他三个是bigint类型。 – user1955255
您需要查看内部异常以找出错误的原因。 –
正如我所说的那样,error.System.Data.SqlClient.SqlException(0x80131904)。事务(进程ID 293)在另一个进程的锁资源上死锁,并被选为死锁受害者。重新运行交易。 – user1955255