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(这是奇怪的恕我直言)。 –