2014-06-05 44 views
1

相似問題; Update SQL with consecutive numbering在PostgreSQL數據庫中生成序列號 - 併發和隔離級別

我希望能夠通過在名爲SeqNum的表中遞增列num來生成序列號。 SeqNum表格佈局;

|num| 
|===| 
| 0 | 

正在運行的查詢;

BEGIN TRANSACTION 
UPDATE SeqNum 
SET num = num + 1 
SELECT num from SeqNum 
COMMIT TRANSACTION 

我的問題是,如果我有運行此查詢在同一時間READ COMMITTED隔離級別多個進程,將SELECT子句總是返回一個唯一的更新值。我假設這將是一致的,沒有兩個進程會返回相同的數量......顯然,這是所有運行在一個事務中。如果它不在事務中,我希望它可能會返回重複的值。

根據隔離級別,我不確定行爲如何改變(如果有的話)。

+0

而不是'update;選擇''使用'update .. returning'會更好。但是,爲什麼不首先使用真正的序列呢? –

回答

2

在PostgreSQL中,您可以請求任何四個標準事務隔離級別。但在內部,只有三個不同的隔離級別,分別對應於Read Committed,Repeatable Read和Serializable。當您選擇級別未提交讀你真正提交讀...1

提交讀隔離級別髒讀每標準是不可能的,這意味着這些交易無法讀取併發未提交的事務寫入的數據。這可以只發生在每秒讀取標準未提交隔離級別(但不會在PostgreSQL中發生:四種隔離級別只定義哪些現象不能發生,他們也不確定哪些現象一定會發生)。

總之,您的select子句不會始終返回唯一值。如果您將其重寫爲UPDATE ... RETUNRING ...,但這兩者都不會,但時間窗口將非常小,因此多個事務的機會將會更低,從而返回相同的值。

但幸運的你,在PostgreSQL的,不影響交易的唯一的事情,是sequence

以避免阻塞從同一個序列獲取數值併發事務,nextval操作從未回滾;也就是說,一旦一個值被取出,它就被認爲是被使用的,即使nextval後來的事務中止。這意味着中止的交易可能會在分配的值序列中留下未使用的「漏洞」。 2

因爲序列是非事務性的,所以如果事務回滾,setval所做的更改不會撤消。 2