这里遇到了一些棘手的情况:我们的系统偶尔遇到僵局。而且我完全没有数据库并发方面的背景知识。
System.Data.SqlClient.SqlException: Transaction (Process ID 69) was deadlocked on
lock resources with another process and has been chosen as the deadlock victim.
Rerun the transaction.
有几个应用程序可以访问数据库:使用Entity Framework访问数据库的主要MVC应用程序,以及几个简单的控制台应用程序,每个控制台应用程序都使用ADO.NET和原始SQL查询数据库,并通过BinaryTap ActiveRecord插入数据。
不幸的是,我是客户组织的FNG,所以我无法部署和测试新的想法。另外,我们正在使用SSMS Express,因此我无权访问SQL Profiler。但是,立即解决问题并不重要,而记录对问题的分析则更为重要。
错误消息说我应该重新运行事务时,是否有任何真相?这是我们的DaoBase-我们在每个HttpContext中使用一个ObjectContext(通过Db属性)。我们总是将Dao更新(而不是查询)放在SafeAction中,以便将它们打包在事务中。我是否在尝试正确地重新运行事务?
public abstract class DaoBase
{
protected static CaseMateEntities Db
{
get
{
return ContextHelper<CaseMateEntities>.GetCurrentContext();
}
}
protected static void SafeAction(Action<ObjectContext> action)
{
Exception exception = null;
try {
using (var scope = new TransactionScope()) {
try {
if (Db.Connection.State != ConnectionState.Open)
Db.Connection.Open();
if (action != null)
action(Db);
Db.SaveChanges(SaveOptions.DetectChangesBeforeSave);
scope.Complete();
} catch (Exception ex) {
exception = ex;
if (exception is UpdateException)
// TODO: Is this a proper way to rerun a transaction?
scope.Complete();
}
}
if (exception == null) {
Db.AcceptAllChanges();
} else {
throw exception;
}
} finally {
Db.Connection.Close();
}
}
}
其他应用程序通过ADO.NET/Raw SQL查询数据库。它们各自的SELECT语句没有
WITH (NOLOCK)
名称-也许应该吗?在任何情况下,您确实希望锁定纯查询?查询会创建哪种类型的锁:行锁和页锁?关于实体框架生成的查询,我应该告诉EF不要锁定查询吗?感谢所有阅读本文的人。我知道这是一个复杂的问题,我需要做很多阅读工作。
最佳答案
死锁分析需要访问SQL事件探查器,以在关闭死锁时查看数据库服务器上的情况。特别是如果您不是在数据库上执行的SQL查询的所有者,则有必要。使用EF时,您不是所有者-EF生成查询。必须解决数据库查询的死锁以及使用事务执行的数据库操作顺序=您必须知道数据库中发生了什么。
以隔离级别进行播放需要非常了解您的应用程序以及数据库上运行的任何其他应用程序。如果将隔离级别设置为未提交,则将打破事务的核心规则之一-隔离。以读取未提交模式运行的事务可以读取其他事务未提交的数据(脏数据)-如果该事务回滚,则您的代码可以使用无效数据并将数据库移到不一致状态(或由于某些数据库约束而失败)。 SQL查询中的NOLOCK
提示与全局使用未提交读操作相同,但提示仅针对单个查询中的单个表。
使用NOLOCK
或未提交阅读是否很糟糕?否,但是您必须绝对确定何时执行此操作=必须了解您的应用程序(以及使用数据库的其他应用程序),并确保这些用于获取未提交数据的查询不会用于任何其他数据修改或任何风险决策。TransactionScope
的默认隔离级别是可序列化的,它是事务的最严格级别(=导致死锁的频率更高)。您应该首先使用Read commit隔离级别(但是必须确保在事务处理期间不要从数据库中多次读取相同的数据)以减少数据库锁定,但是这很可能无法解决问题(可以降低频率)。 More关于隔离级别。