当我使用创建事务的实体框架执行SQL查询并锁定某个表以对其执行耗时的操作时,当另一个应用程序同时尝试从同一个表读取时会发生什么?
SQL Server是否会等待第一个事务完成并在锁定消失后继续执行,或者它只是返回时出现错误,表明该表无法访问?
答案 0 :(得分:1)
是的,实体框架在调用SaveChanges
时自动创建一个事务,默认隔离级别为Read Committed
(实际上它是从提供程序获取的,SQL Server的默认值是Read Committed)。
可在this documentation page内找到更多详情。
为了更改隔离级别,您可以在实例化上下文时禁止EF的上下文使用它自己的事务(contextOwnsConnection: false
)。
我的首选替代方法是使用TransactionScope,因为它不需要对实例化上下文的方式进行任何更改,保存更改等。但是,请注意its default isolation level is Serializable(引用的问题和答案)还告诉你如何改变它)
注意:不建议使用长事务,也许您应该查看using bulk operations(或检查this library)以避免由正常更改保存生成的多个插入/更新/删除。
答案 1 :(得分:1)
默认情况下,EF将使用READ COMMITTED SNAPSHOT创建SQL Server数据库。这意味着作者不会阻止读者,读者也不会阻止作者。有关基于行版本的隔离级别的详细信息,请参阅Snapshot Isolation in SQL Server。
虽然SaveChanges()在事务中锁定了行,但是尝试读取这些行的其他会话将被重定向到版本存储,并读取这些行的最后已知版本。换句话说,读者可以在任何飞行中交易之前的一致时间点查看每个表格。
如果对现有数据库使用EF,则可能没有配置READ COMMITTED SNAPSHOT,在这种情况下,尝试读取事务锁定的行的读取器将阻塞,直到事务结束。通常这只有几毫秒,除非有大量的事务在运行且读者正在尝试扫描大量行,或者存在运行时间较长的事务。在这种情况下,您应该在将来将数据库移动到READ COMMITTED SNAPSHOT。
答案 2 :(得分:-1)
答案是,这取决于。 SQL可以通过多种方式锁定数据。一般来说,如果您正在进行DML操作(插入,更新,删除),并且您尝试从该表中select
,它将阻止select
直到DML操作完成。
可以使用with (nolock)
或set transaction isolation level read uncommmitted
覆盖(由您自己承担风险)。执行其中一个基本上允许您的查询读取“当前看起来像什么的数据”,这可能是不完整的,甚至包含在事务完成时不会存在的行。
唯一一次返回错误的方法是,如果你的实际连接超时(这将是你的应用程序连接设置中的某些内容),或者你在桌面上造成了死锁(一个更复杂的主题)。