【问题标题】:Multiple console applications updating same sql table using EF objectcontext多个控制台应用程序使用 EF objectcontext 更新同一个 sql 表
【发布时间】:2015-11-04 21:06:02
【问题描述】:

我有多个控制台应用程序,但它们会读取和插入更新同一个 sql 表。我使用了 transactionscope,但我收到了这个错误 “事务(进程 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);
            }
        }

【问题讨论】:

    标签: c# sql entity-framework objectcontext


    【解决方案1】:

    IsolationLevel.RepeatableRead 就像ReaderWriterLockSlim 一样,许多线程可以同时读取一条记录,但一旦要写入,您必须等待所有读取器完成,然后对该对象进行排他锁,直到完成写作。

    假设你有一个程序,它读取对象“A”稍等片刻,然后写入对象“A”。现在让我们看看当程序的两个副本运行时会发生什么。

    程序 1 程序 2 --------- --------- 开始 Trans 未开始 阅读开始翻译 等待读取 A 试着写一个等待 试试写一个试试写一个 试试写一个试试写一个 试试写一个试试写一个

    您可以看到程序 1 正在等待程序 2 释放它的读锁,但是程序 2 不能释放它的读锁,直到程序 1 释放它的读锁。这种两人都在等待对方完成的情况称为死锁

    有两种方法可以解决这个问题,一种可以使用更严格的IsolationLevel.Serializable,这会阻止其他读者,直到事务完成。

    程序 1 程序 2 --------- --------- 开始 Trans 未开始 阅读开始翻译 等待尝试阅读A 写一个尝试读一个 结束 Trans Read A 等待 写一个 结束翻译

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

    【讨论】:

    • 感谢您的回复。我将 IsolationLevel 更改为 Serializable 但这也无济于事。这是我得到的错误,从商店提供者的数据阅读器读取时发生错误。有关详细信息,请参阅内部异常。位于 System.Data.Common.Internal.Materialization.Shaper`1.StoreRead()。这确实与我在互联网上检查的错误相同。仅供参考,我的 SQL 表只有 4 列,其中一列是 Id,它是 IDENTITY(1,1) 的主键,其他三列是 bigint 类型。
    • 需要查看内部异常才能找到错误原因。
    • 正如我所说的一样,error.System.Data.SqlClient.SqlException (0x80131904)。事务(进程 ID 293)与另一个进程在锁资源上死锁,并已被选为死锁牺牲品。重新运行事务。
    • 除了您在答案中显示的代码之外,其他代码是否使用dbContext.TourneyInstanceTrackers
    猜你喜欢
    • 1970-01-01
    • 2015-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-17
    • 1970-01-01
    相关资源
    最近更新 更多