SQL Server事务和事务隔离 - 获取我不知道如何修复的错误

时间:2014-01-16 20:47:24

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

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

当我使用IsolationLevel.ReadCommitted.Serializable时,我会遇到这样的死锁错误:

  

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

当我使用IsolationLevel.Snapshot时,我会收到这样的错误:

  

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

使用IsolationLevel.Snapshot时,这些错误最少(每天一到三次)。

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

  1. 完全序列化所有数据库访问,或
  2. 实施某种类型的事务重试功能。
  3. 我不能做1因为某些任务和请求需要一段时间才能运行,而应用程序的其他部分需要保持合理的响应。

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

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

    有什么想法吗?

1 个答案:

答案 0 :(得分:0)

无论隔离级别如何,都有两类锁。 SELECT的INSERT,DELETE,UPDATE和shared的EXCLUSIVE。

您应该尝试将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