在本快速教程中,咱們將討論在Spring Data JPA中爲自定義查詢方法和預約義存儲庫的CRUD
方法啓用事務鎖, 咱們還將查看不一樣的鎖類型並設置事務鎖超時。html
JPA定義了兩種主要的鎖類型,即悲觀鎖和樂觀鎖。java
當咱們在事務中使用悲觀鎖並訪問實體時,它將當即鎖定。經過提交或回滾事務來釋放鎖。git
**在樂觀中,事務不會當即鎖定實體。**相反,事務一般會保存實體的狀態,併爲其分配版本號。github
當咱們嘗試在不一樣的事務中更新實體的狀態時,事務會在更新期間將保存的版本號與現有的版本號進行比較。spring
此時,若是版本號不一樣,則表示沒法修改實體。若是存在活動事務,那麼該事務將被回滾,而且底層JPA實現將拋出OptimisticLockException。數據庫
除版本號方法外,咱們還可使用其餘方法,如時間戳,哈希值計算或序列化校驗和,具體取決於哪一種方法最適合咱們當前的開發環境。api
要獲取實體的鎖定,咱們能夠經過使用@Lock
來註解目標查詢方法, 並傳遞所需的鎖定模式類型。併發
鎖定模式類型(Lock mode types)是鎖定實體時要指定的枚舉值。而後,將指定的鎖定模式傳遞到數據庫,以在實體對象上應用相應的鎖定。oracle
要在Spring Data JPA存儲庫的自定義查詢方法上指定鎖定,咱們可使用@Lock
註解該方法並指定所需的鎖定模式類型:高併發
@Lock(LockModeType.OPTIMISTIC_FORCE_INCREMENT)
@Query("SELECT c FROM Customer c WHERE c.orgId = ?1")
public List<Customer> fetchCustomersByOrgId(Long orgId);
複製代碼
要強制鎖定預約義的存儲庫方法(如findAll或findById(id)),咱們必須在存儲庫中聲明方法並使用@Lock
註解該方法:
@Lock(LockModeType.PESSIMISTIC_READ)
public Optional<Customer> findById(Long customerId);
複製代碼
當顯式啓用鎖而且沒有活動事務時,底層JPA實現將拋出TransactionRequiredException。
若是沒法授予鎖而且鎖衝突不會致使事務回滾,則JPA會拋出LockTimeoutException。但它不標記回滾的活動事務。
使用悲觀鎖時,數據庫將嘗試當即鎖定實體。當沒法當即獲取鎖定時,底層JPA實現會拋出LockTimeoutException。爲避免此類異常,咱們能夠指定鎖超時時間。
在Spring Data JPA中,可使用[@QueryHints](docs.spring.io/spring-data… /jpa/repository/QueryHints.html)指定鎖定超時時間:
@Lock(LockModeType.PESSIMISTIC_READ)
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout", value = "3000")})
public Optional<Customer> findById(Long customerId);
複製代碼
有關在不一樣範圍設置鎖定超時提示的更多詳細信息,請參見ObjectDB文章。
在本教程中,咱們學習了不一樣類型的事務鎖定模式,以及如何在Spring Data JPA中啓用事務鎖,並簡單介紹瞭如何設置鎖定超時。
在正確的位置應用正確的事務鎖,能夠幫助維護高併發狀況下應用程序中數據完整性。
當交易須要嚴格遵照ACID規則時,咱們應該使用悲觀鎖。當咱們須要容許多個併發讀取以及在應用程序上下文中可接受的最終一致性時,應該應用樂觀鎖。
固然,能夠在Github上找到悲觀鎖和樂觀鎖的示例代碼。
做者:baeldung
譯者:Leesen