2010-04-19 164 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。