【问题标题】:SQL Server transactions and transaction isolation - getting errors that I don't know how to fixSQL Server 事务和事务隔离 - 出现我不知道如何修复的错误
【发布时间】:2014-01-16 20:47:24
【问题描述】:

我有一个使用 EF6 和 SQL Server 的 ASP.NET MVC 应用程序,最多有 15 个左右的并发用户。为了确保每个页面请求期间不同查询之间的数据一致性,我将所有内容都包含在事务中(使用System.Transactions.TransactionScope)。

当我使用IsolationLevel.ReadCommitted.Serializable 时,会出现如下死锁错误:

事务(进程 ID #)在锁资源上与另一个进程死锁,并已被选为死锁牺牲品。

当我使用IsolationLevel.Snapshot 时,我收到如下错误:

快照隔离事务由于更新冲突而中止。您不能使用快照隔离直接或间接访问数据库“#”中的表“dbo.#”来更新、删除或插入已被另一个事务修改或删除的行。重试事务或更改更新/删除语句的隔离级别。

这些错误在使用IsolationLevel.Snapshot 时最不常见(大致每天一到三个)。

我对这个问题的理解使我相信,保证零交易失败的唯一方法是:

  1. 完全序列化所有数据库访问,或
  2. 实现某种类型的事务重试功能。

我无法做到 1,因为某些任务和请求需要一段时间才能运行,而应用程序的其他部分需要保持合理的响应。

我倾向于认为可以通过让 MVC 重新运行控制器操作来实现重试,但我不知道如何去做这样的事情。

我也不知道如何重现我的用户造成的错误。我现在得到的只是信息量不大的异常日志。我可以设置 EF 来记录在数据库上运行的所有 SQL,现在 EF6 允许您这样做,但我不确定这实际上会有多大帮助。

有什么想法吗?

【问题讨论】:

    标签: c# sql-server asp.net-mvc transactions


    【解决方案1】:

    无论隔离级别如何,都有两类锁。对 INSERT、DELETE、UPDATE 和对 SELECT 共享。

    您应该尝试将 EXCLUSIVE 锁的事务时间限制在最短。默认隔离级别是 READ COMMITTED。如果您针对 OLTP 系统编写/运行报告,编写者将阻止阅读者。您可能会遇到阻塞问题。

    2005 年,引入了READ COMMITTED SNAPSHOT ISOLATION。对于读者来说,tempdb 中的版本存储用于捕获数据的快照以满足当前查询。比 SNAPSHOT ISOLATION 少很多开销。简而言之,读者现在不会被作者屏蔽。

    这应该可以解决您的屏蔽问题。您需要删除当前拥有的所有表格提示或隔离命令。

    参见 Brent Ozar 的文章。

    http://www.brentozar.com/archive/2013/01/implementing-snapshot-or-read-committed-snapshot-isolation-in-sql-server-a-guide/

    它会解决你的僵局吗?应该不会吧。

    死锁是两个或多个资源排他锁顺序相反的原因。

    查看 MSDN = 更酷的图片并提到死锁标志。

    http://technet.microsoft.com/en-us/library/ms178104(v=sql.105).aspx

    Process 1
    DEBIT BANK ACCOUNT
    CREDIT VENDOR ACCOUNT
    
    Process 2
    CREDIT VENDOR ACCOUNT
    DEBIT BANK ACCOUNT
    

    简而言之,更改 DML 的顺序以对表进行一致的访问。打开跟踪标志以获取导致问题的实际 TSQL。

    最后但并非最不重要的一点是,检查应用程序锁作为最后的手段。可以在可能导致死锁的代码上用作 MUTEX。

    http://www.sqlteam.com/article/application-locks-or-mutexes-in-sql-server-2005

    【讨论】:

    • 嗯,这很不愉快。我的应用程序在内部使用服务实例,其中许多依赖于其他服务,从而产生了相当深且多管齐下的调用树,其中任何一个都可以运行 LINQ 查询。解决这个问题将非常耗时。 :(
    • 看看我关于隔离级别的介绍。旧命令 sp_lock 将显示锁。跟踪标志将显示死锁。调试有问题的 TSQL 将是困难的部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-22
    • 2018-02-02
    • 2011-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多