我沒有看到如何在不鎖定整個表格的情況下實現可序列化的隔離級別 - 這似乎是可能的,因爲我可以找到有關該主題的所有材料,並討論行和範圍鎖定。如何實現可序列化事務?
我在討論可序列化和Sql Server的快照隔離級別here時發現了一個有趣的例子。
這個例子是關於有兩個彈珠,一個黑色,一個白色和兩個交易,它們同時將所有黑色大理石變成白色,反之亦然。我的問題是:可序列化的隔離級別如何防止最終結果再次是一個白色和一個黑色大理石的結果?
我試過SQL Server上的以下內容:
create table marbles (id int primary key, color char(5))
insert marbles values(1, 'White')
insert marbles values(2, 'Black')
我現在啓動兩個交易,一個是
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
-- returns 1
SELECT id FROM marbles m WHERE m.color = 'White';
UPDATE marbles SET color = 'Black' WHERE id = 1;
COMMIT
另一個是類似的:
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRAN
-- returns 2
SELECT id FROM marbles m WHERE m.color = 'Black';
UPDATE marbles SET color = 'White' WHERE id = 2;
COMMIT
的選擇意味着類似於程序客戶端的讀取,該程序客戶端使用該id稍後發出相應的更新。
如果我先運行兩個事務,直到select語句先執行,然後讓它們繼續執行,則它們會死鎖。這是我們希望發生的事情(或者至少比混合顏色的結果更好)。
我試圖將更新設置爲分別將顏色設置爲綠色和黃色,並且事務仍處於死鎖狀態,這次他們確實不應該這樣做。如果白色大理石變成黃色,那麼對於黑色大理石感興趣的交易就不會選擇它 - 爲什麼會陷入僵局?
爲了正確地實現序列化(正好鎖定必要的情況),必須保存一個事務選擇的記錄,以便數據庫引擎可以計算其他事務的更新如何影響這些結果集。
我可以看到,在這個例子中的簡單情況下,或者簡單的範圍查詢,但是在一般情況下,它會讓我覺得這是一個非常複雜的問題。
我覺得在這方面令人困惑的是,我沒有找到關於該主題的消息來源提到這個問題。他們都只是說了「可序列化的隔離級別是通過聰明的鎖定實現的,參見範圍鎖定」,並表明這是事實。但那不是全部,是嗎?
特別是,當數據庫引擎聲稱「支持可序列化」時,它根本不清楚可能是什麼:它可能是每個事務上的所有事物的簡單鎖定,它可能永遠不會成爲鎖定的另一個極端真正有必要的是,這太複雜了,無法實施。
相比之下,很明顯Sql Server的快照隔離級別究竟意味着什麼。
如果我看得很清楚,我會很感興趣,如果有的話,人們是否有指向進一步讀取主題的指針,特別是關於SQL Server。
[編輯:在Postgres的世界類似的問題已經被問here]
[EDIT2:Postgres的維基也有這個非常例子here討論]
鏈接的文章是我已經看過的解釋範圍查詢的範圍鎖之一。這解釋了在特定情況下如何完成這項工作,但似乎一般情況似乎更爲複雜。畢竟,我的例子甚至沒有範圍查詢,它也可能同時具有兩個「之間」子句 - 它可以任意複雜。 – John
@John - 不那麼複雜。除非計劃具有索引查找,否則可序列化將始終鎖定整個事物(無論是通過對象級鎖還是包含整個索引的單個範圍鎖)。然後個別範圍可能被鎖定。 –
我試圖添加一個索引,並在兩種情況下再次出現死鎖。 – John