基本的SQL原子性“UPDATE ... SET .. WHERE ...”

时间:2010-04-19 14:28:11

标签: sql atomicity

我对“UPDATE ... SET .. WHERE ...”声明的原子性有一个相当基本和普遍的问题。

有一张桌子(没有额外的约束),

+----------+
| id | name|
+----------+
|  1 |  a  |
+----+-----+

现在,我将“同时”(同时)执行以下4个语句。

UPDATE table SET name='b1' WHERE name='a'
UPDATE table SET name='b2' WHERE name='a'
UPDATE table SET name='b3' WHERE name='a'
UPDATE table SET name='b4' WHERE name='a'

是否只有一个UPDATE语句将与表更新一起执行? 或者,有多个UPDATE语句可以真正更新表吗?

我是否需要额外的事务或锁定才能让只有一个UPDATE写入值?

感谢

[编辑] 4个UPDATE语句从不同进程并行执行。 [编辑]与Postgresql

7 个答案:

答案 0 :(得分:8)

其中一个语句将锁定记录(或页面或整个表,具体取决于您的引擎和锁定粒度)并将被执行。

其他人将等待释放资源。

当lucky语句提交时,其他人将重新读取表并且不执行任何操作(如果事务隔离模式设置为READ COMMITTED)或者无法序列化事务(如果事务隔离级别为{{ 1}})。

答案 1 :(得分:1)

如果您一次性运行这些UPDATE,它将按顺序运行它们,因此它会将所有内容更新为b1,但是其他3将无法更新任何内容,因为没有A可以更新。

答案 2 :(得分:1)

每个都会有一个隐式事务,它会将其他UPDATE保存在队列中。在这种情况下,只有第一个通过将获胜,因为每个后续更新都不会看到名为“a”的名称。

编辑:我在这里假设你从不同的进程调用每个UPDATE。如果在一个脚本中调用它们,它们将按照外观顺序连续运行。

答案 3 :(得分:1)

只有一个UPDATE语句可以访问记录。在它运行之前,它启动一个事务并锁定表(或更正确地,记录所在的页面,甚至只记录本身 - 这取决于许多因素)。然后它再次进行更改并解锁表,在此过程中提交事务。

对某个记录的更新/删除/插入本质上是单线程的,需要确保表的完整性。这并不意味着对许多记录(位于不同页面上)的更新无法并行运行。

答案 4 :(得分:0)

根据您发布的声明,您最终会收到错误消息,因为在第一次更新后无法找到“a”。你想用这个来实现什么?

答案 5 :(得分:0)

即使您未指定begin transactioncommit transaction,单个SQL语句也始终是事务性的。这意味着只允许其中一个更新同时修改该行。其他查询将阻止第一个查询拥有的update lock

答案 6 :(得分:0)

我相信这可能就是你要找的东西(在T-SQL中):

UPDATE [table]
SET [table].[name] = temp.new_name
FROM
[table],
(
    SELECT
        id,
        new_name = 'B'+ cast(row_number() over (order by [name]) as varchar)
    FROM
        [table]
    WHERE
        [table].name = 'A'
) temp
WHERE [table].id = temp.id

在其他SQL风格中应该有与row_number等效的函数。