2013-07-24 90 views
1

我正在使用c3p0和postgres。我有一個多線程應用程序,沒有適當的鎖定,不同的線程可能會意外更新相同的記錄。爲了防止這種情況,我打算使用諮詢鎖。c3p0:會話級別諮詢鎖

SELECT pg_advisory_lock(id) FROM ...; 

但是,我不知道是否我其實可以結合使用諮詢鎖與連接池,因爲如果那是什麼東西用來創建鎖的連接被關閉(這是透明的應用程序邏輯) ?相應的鎖是否被釋放?

+0

我對「諮詢鎖」沒有實質性評論;我從來沒有用過它們。但是,如果您認爲它們適合您的應用程序,請按照下面的Craig Ringer,聽起來您需要確保在連接返回到池之前將它們丟棄。在c3p0中這樣做的正確方法是創建一個ConnectionCustomizer(擴展AbstractConnectionCustomizer)並覆蓋onCheckIn(...)以執行DISCARD ALL語句。 –

回答

4

是的,鎖定(建議和其他方式)在連接關閉時釋放。

他們可能不是如果連接返回到一個池,必然會被釋放;事務級別的鎖定將會是因爲任何打開的事務都會使用ROLLBACK,但是如果連接池在向連接池返回會話後知道run the PostgreSQL-specific DISCARD ALL; statement,則諮詢鎖定纔會被釋放。

爲了防止這種情況,我打算使用諮詢鎖。

爲什麼?您正在防止更新記錄,所以您有一個普通的行,您可以鎖定得很好。你的程序應該是:

  1. 退房的連接池
  2. SELECT * FROM the_table WHERE id = 123 FOR UPDATE
  3. 的連接做應用
  4. UPDATE the_table SET whatever = blah WHERE id = 123
  5. 返回連接到連接池所需的工作

這要求您持有未結交易上的相同連接爲三個步驟。如果你的體系結構阻止你這樣做並在(2)之後將連接返回到池中,那麼它可能也會阻止使用建議鎖定,因爲您需要持有相同的基礎連接來管理建議鎖定。

如果是這種情況,則必須使用optimistic concurrency control(通常稱爲「樂觀鎖定」),這是爲無狀態Web應用程序創建的設計。您存儲在實體版本字段,你的流程是這樣的:

  1. SELECT col1, col2, entity_version FROM the_table WHERE id = 123(假裝entity_version回來與價值42
  2. 不要在應用程序所需的工作
  3. 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要避免的問題。

+0

樂觀鎖定當然需要應用程序存儲每個鎖定實體的實體版本。在我的情況下,我可能會堅持顯式地在各個項​​目上設置一個鎖定位,因爲應用程序邏輯會以批量方式處理必須以原子方式處理的實體。 – dsd

+0

@dsd爲什麼你不能只使用'SELECT ... FOR UPDATE',簡單和標準的方法來做到這一點? –

+0

鎖必須持有會話/連接... – dsd