I\'m trying to use Pessimistic locking in JPA, over Hibernate 3 against a Postgres Database. I can\'t get the lock to time out - it just seems to hang forever.
Here
Postgres SELECT for update syntax only provides the options to not wait if a lock can not be obtained right away. See postgres docs.
To prevent the operation from waiting for other transactions to commit, use the NOWAIT option. With NOWAIT, the statement reports an error, rather than waiting, if a selected row cannot be locked immediately. Note that NOWAIT applies only to the row-level lock(s) — the required ROW SHARE table-level lock is still taken in the ordinary way (see Chapter 13). You can use LOCK with the NOWAIT option first, if you need to acquire the table-level lock without waiting.
When working with postgres I have observed that any value over 0 for the timeout will cause hibernate to issue SELECT FOR UPDATE
but when timeout is 0 it will issue SELECT FOR UPDATE NO WAIT
javax.persistence.lock.timeout doesn't to be working for me either when provided like below
@QueryHints({@QueryHint(name = "javax.persistence.lock.timeout",value = "15000")})
But then I tried something else which worked. Instead of using @Repository and using CrudRepository, now I am configuring my hbernate using entity manager. Used createQuery along with lock and setting lock timeout. And this configuration is working as expected. I have two transaction running in parellel and trying to lock exact same row in DB. First transaction is able to acquire WRITE lock and holds the lock for around 10 secs before releasing lock. Meanwhile, second transaction tries to acquire lock on same row but since javax.persistence.lock.timeout is set to 15 secs, it waits for lock to be released and then acquires its own lock. Hence making the flow serialized.
@Component
public class Repository {
@PersistenceContext
private EntityManager em;
public Optional<Cache> getById(int id){
List<Cache> list = em.createQuery("select c from Cache c where c.id = ?1")
.setParameter(1, id)
.setHint("javax.persistence.lock.timeout", 15000)
.setLockMode(LockModeType.PESSIMISTIC_WRITE)
.getResultList();
return Optional.ofNullable(list.get(0));
}
public void save(Cache cache) {
cache = em.find(Cache.class, cache.getId());
em.merge(cache);
}
}
Put this in your persistence.xml:
<property name="javax.persistence.lock.timeout" value="0"/>
Or set the property before calling the first lock.