我正在使用c3p0和postgres。我有一個多線程應用程序,沒有適當的鎖定,不同的線程可能會意外更新相同的記錄。爲了防止這種情況,我打算使用諮詢鎖。c3p0:會話級別諮詢鎖
SELECT pg_advisory_lock(id) FROM ...;
但是,我不知道是否我其實可以結合使用諮詢鎖與連接池,因爲如果那是什麼東西用來創建鎖的連接被關閉(這是透明的應用程序邏輯) ?相應的鎖是否被釋放?
我正在使用c3p0和postgres。我有一個多線程應用程序,沒有適當的鎖定,不同的線程可能會意外更新相同的記錄。爲了防止這種情況,我打算使用諮詢鎖。c3p0:會話級別諮詢鎖
SELECT pg_advisory_lock(id) FROM ...;
但是,我不知道是否我其實可以結合使用諮詢鎖與連接池,因爲如果那是什麼東西用來創建鎖的連接被關閉(這是透明的應用程序邏輯) ?相應的鎖是否被釋放?
是的,鎖定(建議和其他方式)在連接關閉時釋放。
他們可能不是如果連接返回到一個池,必然會被釋放;事務級別的鎖定將會是因爲任何打開的事務都會使用ROLLBACK
,但是如果連接池在向連接池返回會話後知道run the PostgreSQL-specific DISCARD ALL;
statement,則諮詢鎖定纔會被釋放。
爲了防止這種情況,我打算使用諮詢鎖。
爲什麼?您正在防止更新記錄,所以您有一個普通的行,您可以鎖定得很好。你的程序應該是:
SELECT * FROM the_table WHERE id = 123 FOR UPDATE
UPDATE the_table SET whatever = blah WHERE id = 123
這要求您持有未結交易上的相同連接爲三個步驟。如果你的體系結構阻止你這樣做並在(2)之後將連接返回到池中,那麼它可能也會阻止使用建議鎖定,因爲您需要持有相同的基礎連接來管理建議鎖定。
如果是這種情況,則必須使用optimistic concurrency control(通常稱爲「樂觀鎖定」),這是爲無狀態Web應用程序創建的設計。您存儲在實體版本字段,你的流程是這樣的:
SELECT col1, col2, entity_version FROM the_table WHERE id = 123
(假裝entity_version
回來與價值42
)UPDATE the_table SET whatever = blah, entity_version = 43 WHERE id = 123 AND entity_version = 42
如果entity_version
已被另一個會話更改,則UPDATE
上的WHERE
子句將不匹配,並且更新將影響零行。您可以測試受影響的計數行並重試整個操作,或者在出現這種情況時適當地向用戶報告錯誤。
樂觀併發控制由許多ORM實現,如Hibernate和其他JPA ORMs。您不必將它與ORM一起使用,這只是最常見的用法,因爲ORM鼓勵「選擇然後更新」反模式,否則這是SQL DB要避免的問題。
我對「諮詢鎖」沒有實質性評論;我從來沒有用過它們。但是,如果您認爲它們適合您的應用程序,請按照下面的Craig Ringer,聽起來您需要確保在連接返回到池之前將它們丟棄。在c3p0中這樣做的正確方法是創建一個ConnectionCustomizer(擴展AbstractConnectionCustomizer)並覆蓋onCheckIn(...)以執行DISCARD ALL語句。 –