为啥实体框架在保存时锁定表?

Posted

技术标签:

【中文标题】为啥实体框架在保存时锁定表?【英文标题】:Why Entity Framework locks tables on save?为什么实体框架在保存时锁定表? 【发布时间】:2015-07-06 08:08:04 【问题描述】:

我有一个事务将大量数据(超过 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)

首先我想知道实际发生了什么?是否只是“自然”行为和表被锁定,或者可能是锁定升级或其他原因。

其次,是否可以禁用插入事务级别的锁?还是我必须在所有 SELECT 查询中添加“WITH (NOLOCK)”?

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

【问题讨论】:

你在那里明确地使用了一个事务,那么为什么要读取提交的数据,你必须等到事务被提交才会让你感到惊讶? 【参考方案1】:

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

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

ALTER DATABASE <yourdb> SET READ_COMMITTED_SNAPSHOT ON;

对于那些想要学习的人来说,lock escalation、missing indexes causing scans 和cost of row level isolation 有更多详细信息。

【讨论】:

【参考方案2】:
    是的,写数据的时候加锁就可以了。此外,系统可能会在需要时升级锁,因此您最终可能会得到比您乍一看更多的锁 您不想禁用锁,但有tricks(索引覆盖更多列)可能有助于缓解选择时的锁定问题。也仅在必要时使用NOLOCK 提示;有人打电话给bad habit to kick。看看TRANSACTION ISOLATION LEVEL,它在以更可控的方式处理此类问题时可能很有用。 是的,这是可能的,但这不是您的情况。您有一个在最后提交的大型事务,因此您肯定可以读取所有已提交的行,但由于所有行都在批处理结束时提交,您必须等待整个批处理完成才能读取它们。李>

【讨论】:

以上是关于为啥实体框架在保存时锁定表?的主要内容,如果未能解决你的问题,请参考以下文章

如何让实体框架在不保存对象的情况下创建/更新数据库表

为啥要在移动设备中使用实体框架?

android开发三大框架

实体框架 ChangeTracker 流并保存到查询

实体框架使用 Codefirst、通用存储库、工作单元模式保存多对多关系

如何在实体框架中完全锁定一行