爲了可以同步訪問實體,JPA提供了2種鎖機制。這兩種機制均可以免兩個事務中的其中一個,在不知情的狀況下覆蓋另外一個事務的數據。html
經過實體鎖,咱們一般但願避免在兩個並行事務中產生以下情形:java
結果是,Adam所作的修改徹底被Barbara所覆蓋掉了,可是Barbara對此卻絕不知曉。像這樣的狀況一般被稱爲「髒讀」。顯然,咱們但願的結果是Adam寫入 XA,而Barbara須要在寫入 XB以前檢查對 XA 的修改。數據庫
樂觀鎖基於的假設是實際中衝突不多發生,即便發生,拋出一個錯誤也比想辦法避免它們更容易接受和簡單。在樂觀鎖中,容許一個事務正確完成,但另外一個事務須要拋出異常並回滾,而且必須被從新執行或者丟棄。apache
咱們還以Adam和Barbara爲例,下面是一個使用樂觀鎖可能發生的情形:api
如你所見,Barbara被強制要求檢查Adam的修改,而且她能夠選擇繼續修改Adam的結果並保存(合併修改)。最後的數據將同時包括Adam和Barbara的修改。oracle
樂觀鎖徹底由JPA控制。它須要在DB表中額外存儲一個版本號列。它徹底依靠於底層用來存儲關係型數據的DB引擎來工做。ui
對於某些人來講,悲觀鎖更容易接受。當事務須要修改一個可能被其餘事務同時修改的實體時,事務會發起一個命令將實體鎖住。全部的鎖會持續到事務結束後再自動釋放。spa
使用悲觀鎖的情形可能以下所示:設計
如你所見,Barbara又一次被強制的寫入 XAB,同時也包含了Adam的修改。可是,這個方案與樂觀鎖徹底不一樣——Barbara須要等待Adam的事務完成之後纔可以讀取數據。更甚的是,爲了讓該場景正確工做,咱們須要在兩個事務中都手動發起一個lock命令。(由於咱們並不肯定那個事務先運行,因此兩個事務都須要在修改數據前先進行鎖定)雖然樂觀鎖要爲每一個實體增長一個版本列,比悲觀鎖工做略多,可是以後咱們不須要再在事務中發起鎖操做了。JPA會自動完成全部的檢查,咱們只須要處理可能的異常便可。code
悲觀鎖使用底層數據庫提供的鎖機制來鎖住表中已有的記錄。JPA須要知道如何觸發這些鎖,而且尚不能徹底支持某些數據庫。
即便是JPA規範中也說到,不須要提供PESSIMISTIC_READ(由於許多DB只支持WRITE鎖):
容許JPA實現用
LockModeType.PESSIMISTIC_WRITE
來代替LockModeType.PESSIMISTIC_READ
,可是反之不可。
首先,我想說,對於實體中有添加了@Version註解的列,JPA會自動對該實體使用樂觀鎖。你不須要使用任何鎖命令。可是,你能夠在任什麼時候候發起一個如下類型的鎖:
LockModeType.Optimistic
LockModeType lockMode = resolveLockMode();
A a = em.find(A.class, 1, lockMode);
LockModeType.OPTIMISTIC_FORCE_INCREMENT
LockModeType.PESSIMISTIC_READ
LockModeType.PESSIMISTIC_WRITE
,可是有一點不一樣:若是沒有事務對實體加寫鎖,那麼就不能阻塞對該實體的讀取。它還容許其餘事務使用LockModeType.PESSIMISTIC_READ
來加鎖。WRITE鎖和READ鎖之間的區別,已經被這兩篇文章(here (ObjectDB) 和 here (OpenJPA))很詳細的說明了。可是,不只由於規範中容許,並且許多實現也沒有分開處理,因此該鎖模式常常被等價於LockModeType.PESSIMISTIC_WRITE
。LockModeType.PESSIMISTIC_WRITE
LockModeType.PESSIMISTIC_READ
的加強版。當WRITE
鎖發生時,JPA在數據庫的幫助下,會阻止其餘事務讀取實體,而不像READ
鎖那樣只禁止寫入。LockModeType.PESSIMISTIC_FORCE_INCREMENT
這是另外一個不多使用的鎖模式。可是,它能夠用來結合PESSIMISTIC
和OPTIMISTIC
時使用。在如下場景中,單獨使用PESSIMISTIC_WRITE
是無效的:
在步驟4中,若是事務B沒有增長版本列的值,那麼就沒法阻止事務A覆蓋B的修改。即便事務B使用的是悲觀鎖,鎖模式LockModeType.PESSIMISTIC_FORCE_INCREMENT
也會強制事務B更新版本號,並讓事務A失敗並拋出OptimisticLockException
。
爲了發起一個指定類型的鎖,JPA提供瞭如下方法:
某些EntityManager
方法接收一個指定鎖類型的可選參數,例如
merge()
或者refresh()
JPA的Query接口還提供了setLockMode(LockModeType lockMode)方法來鎖住全部經過查詢獲取的實體
你可使用JPA中這兩種鎖機制中的任意一種。若是須要,也能夠選擇悲觀鎖類型PESSIMISTIC_FORCE_INCREMENT
,把兩者混起來用。