| When EntityManager#find fails while requesting a pessimistic lock with a timeout specified, Hibernate throws org.hibernate.PessimisticLockException, which is converted to javax.persistence.LockTimeoutException by the following code in ExceptionConverterImpl#wrapLockException(HibernateException e, LockOptions):
else if ( e instanceof org.hibernate.PessimisticLockException ) {
final org.hibernate.PessimisticLockException jdbcLockException = (org.hibernate.PessimisticLockException) e;
if ( lockOptions != null && lockOptions.getTimeOut() > -1 ) {
pe = new LockTimeoutException( jdbcLockException.getMessage(), jdbcLockException, null );
}
else {
pe = new PessimisticLockException( jdbcLockException.getMessage(), jdbcLockException, null );
}
}
The resulting LockTimeoutException causes a statement-level rollback. The same should happen for Query#getResultList and #getSingleResult when the query fails while requesting a pessimistic lock with a timeout specified. Instead, ExceptionConverterImpl#wrapLockException incorrectly gets called with a null value for lockOptions. As a result, org.hibernate.PessimisticLockException gets converted to javax.persistence.PessimisticLockException, which causes a transaction-level rollback. The fix should pass the query's LockOptions to ExceptionConverterImpl#wrapLockException, so org.hibernate.PessimisticLockException will be properly converted to javax.persistence.LockTimeoutException. |