6

我在 C#.Net 中制作一个自我项目,通过使用 3 层应用程序,我不想让我的 sql 语句具有事务性,这些语句用于多个存储过程,我一直在使用 WITH(NOLOCK)方法是为了查询那些在事务期间用于插入或更新的表,在 C# 端我一直在使用 TransactionScope,但我最近读到不推荐使用 WITH(NOLOCK),因为它会导致幻像读取或使用脏数据和不一致数据。我的问题是,为了使用在事务期间插入或更新的数据,当涉及到选择时,就事务操作而言,最好的方法是什么?无论是数据库端还是业务代码端。

4

4 回答 4

4

您是否考虑过快照隔离?它提供了完美的读取一致性,并且完全不锁定数据。

SI 在许多 RDBMS 上是标准的,并且默认启用。不知道为什么 SQL Server 的人对使用它犹豫不决。缺点是轻微的,但你需要研究它们。

于 2015-10-05T15:24:41.537 回答
3

你根本不需要它。如果你修改了一些数据,然后在同一个事务中查询它,你会得到修改后的数据。

您的事务将对修改的数据持有排他锁,因此它可以对它做任何事情 - 查询、再次修改等。

如果指定 WITH(NOLOCK),则允许查询忽略来自其他事务的排他锁。这将导致您的查询返回不正确的数据。

于 2015-10-05T14:18:24.323 回答
3

也许你不知道你想要什么。

WITH(NOLOCK) 返回脏数据和不一致数据。

如果您想要干净的数据,则必须删除此子句,并等待您要读取的表的最终并发更新。

于 2015-10-05T14:20:39.090 回答
0

链接:https ://docs.microsoft.com/en-us/sql/connect/jdbc/understanding-isolation-levels?view=sql-server-ver15#remarks

下表显示了不同隔离级别允许的并发副作用。

在此处输入图像描述

从上面的链接中阅读并理解每个列标题的含义。

大多数数据库的默认设置为已提交读。因此,当您在使用或不使用 NOLOCK 的情况下触发查询时,并假设您的数据库处于默认的读取提交模式,您将面临不可重复读取和幻象的问题。

当您使用 NOLOCK 时,您还面临脏读问题。这意味着您甚至可以在事务提交或回滚之前读取它们所做的修改。

还有缺失行的问题(例如,假设您的选择查询已读取更新的行)和重复行(例如,假设已读取的行已更新为尚未读取的值选择查询)。NOLOCK 会导致分配顺序扫描而不是索引顺序扫描,这会导致丢失或重复行问题。

您需要务实地思考上述问题对您的影响,并决定是否使用 NOLOCK 提示。

这是一个示例:https ://dba.stackexchange.com/questions/306994/what-are-the-problems-with-using-nolock-given-an-approach-to-handle-the-short-co

以下答案给出了一个关于两次读取某些行的示例:https ://stackoverflow.com/a/2268078/1779091 (答案粘贴在下面)

NOLOCK 提示会导致脏读异常,其中一种异常是重复读取。如果更新更改了查询扫描的索引中行的位置,则此类读取很频繁:

假设您在表中有 2 行,具有 ID 键,键值为 1 和 2 的行一个请求 (T1) 运行 UPDATE table SET key=3 WHERE key=1;

第二个请求 (T2) 运行 SELECT ... FROM table WITH(NOLOCK);

T1 锁定键值为 1 的行

T2 忽略 T1 拥有的锁并读取键值为 1 的行

T2 继续并读取键值为 2 的行

T1 更新该行,该行在索引中移动到键值 3 的新位置

T2继续扫描,读取键值为3的行

因此 SELECT 读取了一行两次,一次是键值为 1 时,另一次是键值为 3 时。这只是可能发生的事情的一个简单示例。实际上,更复杂的查询可以运行复杂的计划并使用其他索引,所有这些都会受到此类异常的影响。

简而言之:NOLOCK 提示是邪恶的。如果要避免争用,请使用快照隔离。

于 2022-02-03T12:57:44.990 回答