【问题标题】:Do Sql Update Statements run at the same time if requested at the same time?如果同时请求,Sql Update 语句是否同时运行?
【发布时间】:2026-01-21 04:10:02
【问题描述】:

如果两个独立的脚本调用数据库,对同一字段的更新请求具有不同的值,它们会同时执行并且一个覆盖另一个吗?

作为一个有助于确保清晰的示例,想象一下这两个语句被请求同时运行,每个语句都由不同的脚本执行,其中 Status = 2 巧合地在 Status = 1 之后被称为微秒。

Update My_Table SET Status = 1 WHERE Status= 0;
Update My_Table SET Status = 2 WHERE Status= 0;

我的结果是什么,为什么?如果有其他因素发挥作用,请尽可能多地扩展它们,这只是一个总体思路。

旁注: 因为我知道人们仍然会问,我的情况是将 MySql 与 Google App Engine 一起使用,但我不想将这个问题仅限于我,如果它对其他人有用的话。我使用 Status 作为脚本对该字段执行操作的标识符。如果 status 不为 0,则不允许其他脚本触摸它。

【问题讨论】:

  • 可能因所使用的 RDBMS 而异,您应该使用您的 RDBMS 标记您的问题(根据问题的主体,这听起来像 mysql)

标签: mysql sql sql-update


【解决方案1】:

简短的回答是:这取决于首先提交的语句。仅仅因为一个进程在另一个进程之前启动了update 语句并不意味着它将在另一个进程之前完成。它可能没有首先被调度,它可能被另一个进程阻塞,等等。

最终,这是一个竞争条件:最后完成(并提交)的操作获胜。

【讨论】:

  • 完成last的操作获胜是什么意思?不是反过来,第一个完成的就是获胜的吗?因为第二次更新将无法再看到或更新该行...
  • 在您的具体情况下,这是真的。一般来说,最后获胜。
  • 你说的可能是因为2在1之后运行,它可能会因为语句的措辞而覆盖1。如果有,比如说 300 条记录,我在这两条上都发布了 200 条限制。我会有 100 个 0 和 200 个 2 吗?
【解决方案2】:

由于您有两个脚本执行相同的操作并为 UPDATE 使用不同的值,因此它们不会同时运行,即使您认为同时调用它们,其中一个脚本也会先运行。您需要指定每个脚本应该运行的时间,否则程序将不知道什么应该是 1,什么应该是 2。

【讨论】:

  • 奇怪的是,我遇到此问题的原因是因为我无法轻松指定何时。如果我可以高度准确地指定何时,我就不会遇到这个问题,因为我可以强制 1 和 2 在彼此甚至 30 秒内永远不会运行,但 GAE 没有那种级别的控制。所以我最终会得到零星的开始时间,最终可能会在同一时间结束,我无法控制。
【解决方案3】:

来自https://dev.mysql.com/doc/refman/5.0/en/lock-tables-restrictions.html (MySql)

通常,您不需要锁定表,因为所有单个 UPDATE 语句都是原子的;没有其他会话可以干扰任何其他当前正在执行的 SQL 语句。但是,在某些情况下,锁定表可能会提供优势:

来自https://msdn.microsoft.com/en-us/library/ms177523.aspx(sql 服务器)

UPDATE 语句总是在它修改的表上获取一个排他 (X) 锁,并持有该锁直到事务完成。使用排他锁,没有其他事务可以修改数据。

如果您有两个单独的连接来执行两个发布的更新语句,则首先启动的语句将是完成的语句。另一条语句不会更新数据,因为不再有状态为 0 的记录

【讨论】:

  • update在它正在修改的资源上获取一个[独占]更新锁。锁的范围,取决于您使用的 SQL 实现和许多其他因素, 可能是 1 个或多个 rowspages 或整个表。随着越来越多的锁被正在运行的进程占用,获取的锁的范围将升级(例如,一旦锁的数量达到升级阈值,行锁就会升级为页锁。一旦页锁计数达到其升级阈值,锁将升级为表锁。有关详细信息,请阅读您的文档。
【解决方案4】:

这就是锁定的用途。默认情况下,所有主要的 SQL 实现都会锁定 DML 语句,这样一个查询就不会在第一个查询完成之前覆盖另一个查询。

有不同级别的锁定。如果你有行锁定,那么你的第二次更新将与第一次并行运行,所以在某些时候你的表中会有 1 和 2。

表锁定将强制第二个查询等待第一个查询完全完成以释放它的表锁定。

您通常可以直接在 SQL 中关闭锁定,但只有在您需要提高性能并且您知道不会遇到示例中的竞争条件时才会这样做。

基于新的MySQL 标签的编辑

如果您正在更新使用InnoDB 引擎的表,那么您正在使用行锁定,并且您的查询可能会生成一个包含 1 和 2 的表。

如果您正在处理使用MyISAM 引擎的表,那么您正在使用表锁定,并且您的更新语句最终会得到一个全为 1 或全为 2 的表。

【讨论】: