多个控制台应用程序使用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 

另外就是你按照异常的建议,这引起你重新运行异常再次功能,直到它获得通过没有计划阻止它的另一个副本的代码块。

+0

感谢您的回复。我将IsolationLevel更改为Serializable,但这也没有帮助。这是我得到的错误,从商店提供商的数据阅读器读取时发生错误。有关详细信息,请参阅内部异常。在System.Data.Common.Internal.Materialization.Shaper'1.StoreRead()。我在互联网上检查确实是同样的错误。只是FYI我的SQL表只有4列一个是ID是IDENTITY(1,1)的主键,其他三个是bigint类型。 – user1955255

+0

您需要查看内部异常以找出错误的原因。 –

+0

正如我所说的那样,error.System.Data.SqlClient.SqlException(0x80131904)。事务(进程ID 293)在另一个进程的锁资源上死锁,并被选为死锁受害者。重新运行交易。 – user1955255