2010-04-19 161 views
2

我对“UPDATE ... SET .. WHERE ...”语句的原子性有一个相当基本和普遍的问题。基本SQL原子性“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

+3

在第一条语句之后,其他人都不会做任何事情,因为您已将名称从* a *更改为* b1 *。 – RedFilter 2010-04-19 14:33:03

回答

8

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

其他人将等待资源被释放。

当幸运的声明将提交,其他人要么重读表,什么也不做(如果你的事务隔离模式设置为READ COMMITTED)或未能序列化的事务(如果事务隔离级别是SERIALIZABLE)。

0

随着你发布的声明,你会最终出现一个错误,因为在第一次更新后'a'找不到。你想用这个做什么?

+1

不会有错误:您只会得到“0行受影响”。 – 2010-04-19 14:35:04

1

如果你一次运行这些UPDATE,它将按顺序运行它们,所以它会将所有更新都更新为b1,但其他3将更新任何更新,因为A不会更新。

1

围绕每个队列都会有一个隐含的事务,它会在队列中保存其他UPDATE。在这种情况下,只有第一次胜利才会赢,因为每次后续更新都不会看到名为“a”的名称。

编辑:我在这里假设你是从不同的进程调用每个更新。如果他们被称为一个脚本,他们将按照出现顺序连续运行。

1

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

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

+0

“或更正确,记录在页面上” - 不一定。在Oracle中,只有行被锁定,而不是整个页面。它真的取决于数据库。 – dcp 2010-04-19 14:40:18

+0

@dcp:是的,以及有效的锁定策略,任何查询提示等等。我的观点是 - 它不一定锁定整个桌子。 – Tomalak 2010-04-19 14:49:41

0

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

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。