2013-06-06 56 views
5

我正在閱讀不同的事務隔離級別,並且跨越了SERIALIZABLE隔離級別。我也知道像Postgres,Oracle和MySQL這樣的數據庫支持SELECT .. FOR UPDATE語法。可序列化事務vs SELECT FOR UPDATE

但是,當我想鎖定希望執行更新的行(或一系列行)時,我應該如何使用這些應用程序。

以前使用JPA時,我總是在查詢中使用@Transactional加上LockModeType.PESSIMISTIC_WRITE。這轉換爲在SQL中使用READ_COMMITTED隔離級別與SELECT .. FOR UPDATE

但現在,已經瞭解SERIALIZABLE,我想知道如果我用@Transactional(isolation=SERIALIZABLE)與正常SELECT(如em.findById獲取分離實體),接着是UPDATE(合併的會有什麼不同實體)。

行爲是一樣的嗎?

舉例說,我有一個銀行系統,我希望在兩個賬戶之間轉賬。在轉移過程中,我需要這些賬戶不被幹涉。所以,假設我用-100借記​​一個帳戶並將其記入另一個帳戶。確保這些帳戶僅適用於執行更新的交易的最佳方法是什麼?

假設我正在操作JPA分離的實體,因此在更新之前,我將不得不從數據庫中讀取它們,例如, findById()

  • 使用@Transactional(isolation=READ_COMMITTED)em.findByIdLockModeType.PESSIMISTIC_WRITE(即SELECT .. FOR UPDATE),然後em.merge(即UPDATE)?
  • 或使用@Transactional(isolation=SERIALIZABLE)em.findById,然後em.merge(即UPDATE)?

回答

2

SERIALIZABLE與使用SELECT FOR UPDATE的主要區別在於,使用SERIALIZABLE時,所有內容始終處於鎖定狀態。與SELECT FOR UPDATE一樣,您可以選擇什麼以及何時鎖定。

所以如果你只想鎖定一些數據,即BankAccount而不是其他的,即Branch,AccountTypes,那麼SELECT FOR UPDATE會給你更好的控制,因爲SERIALIZABLE會阻塞你的整個系統,因爲從ACCOUNT_TYPES表。另外,有些交易可能只是想檢查餘額,所以不需要鎖定ACCOUNT表。

見,

http://en.wikibooks.org/wiki/Java_Persistence/Locking

+6

「*與SERIALIZABLE一切都始終鎖定*」作爲一般性陳述並非如此。這在很大程度上取決於DBMS的實現(例如Postgres沒有這樣做) –

+0

這是真的「PostgreSQL例如不會這樣做」在可序列化的PostgreSQL中將執行所有沒有Lock的選擇語句,但是當發生併發時寫入語句最後一個事務獲得授予序列化完整性失敗 – deFreitas

0

在我看來,可序列化不能在這個商業交易的工作,因爲你需要選擇一個實體(例如後檢查一些條件,如果一個帳戶有足夠的錢)。併發事務可以通過SERIALIZABLE級別獲取錯誤的值,因爲它擁有SELECT的共享(讀取)鎖定。

但是SELECT ...FOR UPDATE將正常工作,因爲它將持有一個排他鎖,直到交易結束,並強制其他交易等待。