我首先使用EF代码。最近我不得不替换以下代码:
User user = userRepository.GetByEmail("some@email.com");
if (user == null)
{
user = New User { Email = email, CreatedAt = DateTime.Now };
userRepository.Add(user);
unitOfWork.Commit();
}
与
Context.ExecuteSqlCommand("IF NOT EXISTS(SELECT 1 FROM Users WHERE Email = '{0}')
INSERT INTO Users(Email, CreatedAt)
VALUES ('email', GETDATE())");
这背后的原因是,在尝试添加数千行时,EF花费了很长时间来运行第一段代码。通过将其更改为ExecuteSqlCommand,处理那么多行的时间减少了很多。
我现在看到的问题(到目前为止只发生过两次)是来自数据库的以下消息:事务(进程ID 52)在锁资源上与另一个进程死锁,并被选为死锁牺牲品。重新运行该交易。
我该如何解决这个问题?我的大多数数据访问都是通过EF完成的,除了上面的一些例外。我之前从未在日志中看到过死锁,所以我认为这与查询有关。
我的问题是:
答案 0 :(得分:0)
您真正想要的是提前锁定表,而不是阻止锁定。锁定是必要的,以确保在您的命令中的两个语句之间,一些其他进程没有出现并插入相同的用户。 (插入数据时始终需要锁定,因为正在修改物理存储。)
假设这实际上是导致死锁的命令,以下应该解决它,因为它只要求一个独占锁:
Context.ExecuteSqlCommand(“IF NOT EXISTS(SELECT 1 FROM Users WHERE Email ='{0}') 插入用户(Email,CreatedAt) VALUES('email',GETDATE())“);