20
- 春季啓動1.4.2
- 春數據JPA 1.10.5
- 的PostgreSQL數據庫9.5
我想有一個findOne
方法悲觀鎖定在我的Spring數據存儲庫中,它與已經提供的findOne
方法分開。
繼this answer我寫道:
public interface RegistrationRepository extends CrudRepository<Registration, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select r from Registration r where r.id = ?1")
Registration findOnePessimistic(Long id);
}
這幾乎工程。
不幸的是,這不會刷新實體管理器緩存中的實體的先前實例。我有更新我的註冊狀態兩個併發請求
- 的第一個交易的第二個等待提交
- 第二個不沒有考慮到第一個所做的更改。
因此破壞行爲。
任何線索爲什麼@Lock
沒有開箱刷新實體管理器?
更新
這裏是請求的示例代碼:
public interface RegistrationRepository extends CrudRepository<Registration, Long> {
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("select r from registration_table r where r.id = ?1")
Registration findOnePessimistic(Long id);
}
public void RegistrationService {
@Transactional
public void doSomething(long id){
// Both threads read the same version of the data
Registration registrationQueriedTheFirstTime = registrationRepository.findOne(id);
// First thread gets the lock, second thread waits for the first thread to have committed
Registration registration = registrationRepository.findOnePessimistic(id);
// I need this to have this statement, otherwise, registration.getStatus() contains the value not yet updated by the first thread
entityManager.refresh(registration);
registration.setStatus(newStatus);
registrationRepository.save(registration);
}
}
你必須向我們展示了代碼,它改變了實體值。爲什麼你在只讀實體的方法上用'PESSIMISTIC_WRITE'鎖定表? –
我在註釋爲「@ Transactional」的方法中使用代碼,在那裏讀取實體,更新它並寫回。相當標準。我想避免這個操作的併發性,所以我想使用一個悲觀的鎖。我只想在'update'之前執行'select for update'。 – rcomblen
整個代碼塊是事務性的,因此使用相同的entitymanager。 'EntityManager'充當第一級緩存。您首先檢索沒有鎖的對象,然後用鎖再次檢索它。但是,對於第一級緩存,您將檢索該對象而不是新的數據庫對象。這基本上是'EntityManager'的工作原理,如果你不想讓你首先必須「清除」實體管理器。或者說,你爲什麼首先檢索它沒有鎖在同一TX(這是奇怪的恕我直言)。 –