Search code examples
javajpalockingjpa-2.0pessimistic-locking

How to get a PessimisticLockException with JPA


I am trying JPA's support of database locking in order to avoid concurrent requests in a record. In my scenario I need to use a pesssimistic lock. I got that using the following approach:

EntityManager em;
...

Map<String,Object> props = new HashMap<String,Object>();
props.put("javax.persistence.lock.timeout", 0);
em.find(MyEntity.class, id, LockModeType.PESSIMISTIC_READ, props)

but with that approach I handle a LockTimeoutException instead of a PessimisticLockException. How to handle a PessimisticLockException specifically?


Solution

  • According to the spec, the PessimisticLockException only occurs on a transaction-level rollback:

    When the lock cannot be obtained, and the database locking failure results in transaction-level rollback, the provider must throw the PessimisticLockException and ensure that the JTA transaction or EntityTransaction has been marked for rollback.

    Your transaction seems to consists only of that single data retrieval query and the persistence provider considers that if a lock error occurs on that query, then the rollback would be considered as a statement-level rollback. Which according to the spec would result in the LockTimeoutException:

    When the lock cannot be obtained, and the database locking failure results in only statement-level rollback, the provider must throw the LockTimeoutException (and must not mark the transaction for rollback).

    I think thats a clever way of the driver / persistence provider to give you a chance to repeat / fix your statement instead of rolling back the whole transaction implicitly.

    In general, I think that if you had an insert or an update before that find (or some more complex data manipulation statements), then you would get the PessimisticLockException.