Sql 的 Where 子句 - 它可以读取过时的数据吗?

Posted

技术标签:

【中文标题】Sql 的 Where 子句 - 它可以读取过时的数据吗?【英文标题】:Where clause of Sql - may it read a stale data? 【发布时间】: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" 由第一个用户找到,但在第一个用户更改余额之前?

我的意思是:

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

【问题讨论】:

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

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

所以:

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

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

【讨论】:

所以你说隔离级别和它无关?而 NOLOCK 不能改变这种行为? 是的。亲自尝试一下,您可以使用 begin transaction 使您的事务更长,并在您准备好时显式提交。为了破坏数据,而不是像您共享的那样使用更新语句,您可以将原子更新拆分为选择然后更新(使用来自选择的信息作为更新的基础)。

以上是关于Sql 的 Where 子句 - 它可以读取过时的数据吗?的主要内容,如果未能解决你的问题,请参考以下文章

SQL查询where子句如果没有匹配记录则省略

9where子句

mysql语句where条件中的是啥意思

MySQL-SQL语句命令

雪花,SQL where 子句

Sql where 子句