2012-05-22 104 views
1

我首先使用EF代码。最近,我不得不更换下面的代码:与首次使用EF代码时锁定资源事务死锁

Context.ExecuteSqlCommand("IF NOT EXISTS(SELECT 1 FROM Users WHERE Email = '{0}') 
          INSERT INTO Users(Email, CreatedAt) 
          VALUES ('email', GETDATE())"); 

User user = userRepository.GetByEmail("[email protected]"); 

if (user == null) 
{ 
    user = New User { Email = email, CreatedAt = DateTime.Now }; 

    userRepository.Add(user); 
    unitOfWork.Commit(); 
} 

这背后的原因是,它EF花了很长的时间来运行第一段代码尝试添加数以千计的时行。通过将其更改为ExecuteSqlCommand,处理多行的时间减少了很多。

我现在看到的问题(仅发生两次)是来自数据库的以下消息:事务(进程ID 52)在锁资源上与另一个进程死锁并被选作死锁牺牲品。重新运行交易。

我该如何解决这个问题?我的大部分数据访问都是通过EF完成的,只有上面的例外。我从未在日志中看到过死锁,所以我认为这与查询有关。

我的问题是:

  1. 有编写使用无锁的查询的方法吗?那个 查询怎么样?
  2. 有没有办法告诉EF使用NO LOCK进行某些查询?

回答

0

你真正想要的是先锁定表,而不是防止锁定。锁定是必要的,以确保在您的命令中的两个语句之间,某个其他进程尚未出现并插入相同的用户。 (锁定因为物理存储正在被修改插入数据时总是必要的。)

假设这实际上是导致死锁的命令,以下应该解决它,因为它仅要求输入的排他锁:

Context.ExecuteSqlCommand(“IF NOT EXISTS(SELECT 1 FROM Users WHERE Email ='{0}') INSERT INTO Users(Email,CreatedAt) VALUES('email',GETDATE())”);