我有一个使用EF6和SQL Server的ASP.NET MVC应用程序,最多有15个并发用户。为确保每个页面请求期间不同查询之间数据的一致性,我将所有内容都包含在事务中(使用System.Transactions.TransactionScope
)。
当我使用IsolationLevel.ReadCommitted
和.Serializable
时,我会遇到这样的死锁错误:
事务(进程ID#)在锁资源上与另一个进程发生死锁,并被选为死锁牺牲品。
当我使用IsolationLevel.Snapshot
时,我会收到这样的错误:
由于更新冲突导致快照隔离事务中止。您不能使用快照隔离直接或间接访问数据库'#'中的表'dbo。#'来更新,删除或插入已被另一个事务修改或删除的行。重试事务或更改更新/删除语句的隔离级别。
使用IsolationLevel.Snapshot
时,这些错误最少(每天一到三次)。
我对这个问题的理解使我相信保证零交易失败的唯一方法是:
我不能做1因为某些任务和请求需要一段时间才能运行,而应用程序的其他部分需要保持合理的响应。
我倾向于认为重试可以通过让MVC重新运行控制器动作来实现,但我不知道如何去做这样的事情。
我也不知道如何重现用户造成的错误。我现在得到的只是无法提供信息的异常日志。我可以设置EF来记录在DB上运行的所有SQL,现在EF6允许你这样做,但我不确定它实际上会有多大帮助。
有什么想法吗?
答案 0 :(得分:0)
无论隔离级别如何,都有两类锁。 SELECT的INSERT,DELETE,UPDATE和shared的EXCLUSIVE。
您应该尝试将EXCLUSIVE锁定的事务时间限制到最小。默认隔离级别为READ COMMITTED。如果您正在针对OLTP系统编写/运行报告,编写者将阻止读者。你可能会遇到阻塞问题。
2005年,推出了 READ COMMITTED SNAPSHOT ISOLATION 。对于读者,tempdb中的版本存储用于捕获数据的快照以满足当前查询。比SNAPSHOT ISOLATION少了很多开销。简而言之,读者现在不被作家封锁。
这应该可以解决您的阻止问题。您需要删除当前的任何表提示或隔离命令。
见Brent Ozar的文章。
它会解决你的僵局吗?可能不是。
死锁是两个或多个资源以相反顺序排他的原因。
查看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