为什么Entity Framework会在保存时锁定表?

时间:2015-07-06 08:08:04

标签: sql-server entity-framework transactions

我有一个事务,它将大量数据(超过5000条记录)插入到3个表中(因此需要一段时间),这没关系,但我注意到了一些令人不安的事情。在此过程中,所有3个表似乎都被锁定了。

插入交易:

using(var db = new MyEntities())
{
    using (var tr = db.Database.BeginTransaction())
    {
         // blah, blah, a lot of entities to create, **some custom SQL, bulk inserts** etc.

         db.SaveChanges();
         tr.Commit();
    }
}

我从表中保存时无法读取EF或原始SQL查询。但选择(NOLOCK)有效:

SELECT * FROM Table1 WITH (NOLOCK)

首先,我想知道实际发生了什么?它只是"自然"行为和表格无论锁定升级还是其他任何内容都被锁定。

第二,是否可以在插入事务级别禁用锁定?或者我是否必须添加" WITH(NOLOCK)"所有SELECT查询?

第三,是否有可能使SELECT查询在保存期间返回数据,但仅来自提交事务的记录(例如我的插入事务已添加2000条记录,3000条待处理,我进行选择查询并返回除那些以外的所有记录2000年,尚未提交)。

2 个答案:

答案 0 :(得分:0)

  1. 是的,写入数据时可以锁定。此外,系统可能会在需要时升级锁定,因此您可能会获得比第一眼看上去更多锁定的锁定
  2. 您不想禁用锁定,但有tricks(索引覆盖更多列)可能有助于缓解选择锁定问题。也只在必要时使用db.collection.aggregate([ {$unwind : "$todo_items"}, {$group: {_id : "$_id" , completed : {{$cond : { if : { $and : [ {"todo_items.completed_by" : {$exists: true, $ne : null }}, {"todo_items.completed_date" : {$exists : true, $ne : null}} ] } }, then : {$push : {"old_completed" : "$todo_items"}}, else: {$push : {"old_incompleted" : "$todo_items"}} } } } }, {$project: {_id : "$_id", completed : "$completed.old_completed" , incompleted : "$completed.old_incompleted"}} ]); 提示;有人称之为bad habit to kick。看看TRANSACTION ISOLATION LEVEL在以更加可控的方式处理此类问题时可能会有用。
  3. 是的,这是可能的,但不是你的情况。你有一个在最后提交的巨大事务,所以你可以确定地读取所有提交的行,但由于所有行都在批处理结束时提交,你必须等待整个批处理完成才能读取它们。

答案 1 :(得分:0)

表格未锁定。插入的特定记录已被锁定。您注意到阻塞是因为在提交之前尝试读取这些新插入的行。

在数据库中启用读提交的快照。

ALTER DATABASE <yourdb> SET READ_COMMITTED_SNAPSHOT ON;

有些人希望了解可能的lock escalationmissing indexes causing scanscost of row level isolation