【问题标题】:Where clause of Sql - may it read a stale data?Sql 的 Where 子句 - 它可以读取过时的数据吗?
【发布时间】:2020-10-24 13:17:44
【问题描述】:

我有一个 一个 行的简单表 (SQL Server),许多用户可以 访问该行。

如果第一个用户这样做:

Update Table1 
Set Balance = Balance +10
Where FirstName= 'John' //The value in this column is "John" indeed.

是否有可能,该余额将由第一个用户更新,尽管其他用户已输入并将 FirstName 更改为“Dan”在行之后 FirstName = "John" 由第一个用户找到,但在第一个用户更改余额之前?

我的意思是:

  1. 第一个用户的 Where 子句找到 FirstName = "john" 的行
  2. 第二个用户输入,并将 FirstName 更改为“Dan”。
  3. 从 #1 继续,余额由第一个用户更新,因为第一个用户不知道第二个用户已经更改了某些内容(Where 子句在第二个用户做某事之前已经找到了该行)。

【问题讨论】:

  • (1) 您的代码不是有效的 SQL Server 代码。 (2) 如果有人开始在他们的查询中使用NOLOCK 之类的东西,那么是的,可能会读取过时的数据。
  • @GordonLinoff 感谢您的评论。假设没有人使用 NOLOCK,我确定不会发生这种情况吗?我的意思是,每个 Update 命令都默认实现 Lock 吗?
  • 在 sql server 中是不可能的
  • 请运行DBCC useroptions 并发布结果。我们需要查看默认的事务隔离级别
  • @SteveC 感谢您教我这个命令(DBCC 用户选项)。隔离级别已提交读。

标签: sql sql-server sql-update where-clause multi-user


【解决方案1】:

行在被修改时被锁定(NOLOCK 在更新语句中不起作用,因此您不必担心)。

所以:

  1. 第一位用户出现并更新 John + 10 的余额。
  2. 第二个用户更新行并将名称更改为 Dan,如果第一个用户尚未提交,则第二个用户将等到 +10 余额已提交。
  3. 第一个用户提交
  4. 第二个用户提交
  5. 余额 +10,现在的名字是 Dan。
  6. 如果第一个用户为 John 触发另一个语句,那么他们将找不到行,因此不会更新任何内容。

如果第一个用户在 2 和 3 之间触发了相同的更新,那么更新将成功,因为他们仍然拥有必要的行锁。

【讨论】:

  • 所以你说隔离级别和它无关?而 NOLOCK 不能改变这种行为?
  • 是的。亲自尝试一下,您可以使用 begin transaction 使您的事务更长,并在您准备好时显式提交。为了破坏数据,而不是像您共享的那样使用更新语句,您可以将原子更新拆分为选择然后更新(使用来自选择的信息作为更新的基础)。
猜你喜欢
  • 2013-08-10
  • 1970-01-01
  • 2014-09-04
  • 2011-09-16
  • 2010-12-12
  • 2018-04-07
  • 2022-10-25
  • 2012-11-05
  • 2011-02-18
相关资源
最近更新 更多