|
|
在多人使用的環境
下,每個使用者可能進行自己的交易,交易與交易之間,必須互不干擾,使用者不會意識到別的使用者正在進行交易,就好像只有自己在進行操作一樣。 隔離設定與與特定的資源相關,並不在 Java EE 規範之中。 您可以進一步參考:簡 介隔離層級。 樂觀鎖定(Optimistic locking)樂觀的認為資料很少發生同時存取的問題,通常在資料庫層級上設為read-commited隔離層級,並實行樂觀鎖定。 在read commited隔離層級之下,允許交易讀取另一個交易已COMMIT的資料,但可能有unrepeatable read與lost update的問題存在,例如:
交易B可能基於舊的資料來更新欄位,使得交易A的資料遺失,或者是:
為了維護正確的資料,樂觀鎖定使用應用程式上的邏輯實現版 本控制的解決。 對於lost update的問題,可以有幾種選擇:
交易A先COMMIT,交易B在COMMIT時會得到錯誤訊息,表示更新失敗,交易B必須重新取得資料,嘗試進行更新。
交易A、B都可以COMMIT,交易B覆蓋交易A的資料也無所謂。
先更新為主的變化應用,交易A先COMMIT,交易B要更新時會得到錯誤訊息,提示使用者檢查所有欄位,選擇性的更新沒有衝突的欄位。
JPA中透過版本號檢查來實現先更新為主,在資料庫中加入一個version欄位記錄,在讀取資料時 連同版本號一同讀取,並在更新資料時比對版本號與資料庫中的版本號,如果等於資料庫中的版本號則予以更新,並遞增版本號,如果小於資料庫中的版本號就丟出 例外(OptimisticLockingException),版本號可以是數字或時間戳記,通常使用數字。 若要定義Entity上版本號欄位對應的屬性,則可以使用@Version,例如: package onlyfun.caterpillar;
public class User { private Long id; @Version private Long version; // 增加版本屬性 .... public Long getVersion() { return version; } public void setVersion(Long version) { this.version = version; } } 在EntityManager上有個lock()方法,可以讓您主動對Entity進行鎖定,lock()有兩種模式: LockModeType.READ與LockModeType.WRITE。前者允許另一使用者讀取,但不允許更新、刪除,可避免Dirty read、Non-repeatable read,後者則不允許另一使用者讀取、更新、刪除。使用lock()方法,Entity上必須有版本屬性,且必須在Managed狀態,否則無法取得鎖 定,會丟出javax.persistence.PersistenceException,EntityManager會嘗試將lock()轉為資料庫 的鎖定指令。 |