Race condition in optimistic locking

Let’s assume an entity (a) using optimistic concurrency control with @Version attribute. If we lock it using em.lock() and LockMode.OPTIMISTIC, Hibernate issues a SELECT statement to compare the version of the entity in the persistence context with what’s in the db right before transaction completion. As documented here: How to fix optimistic locking race conditions with pessimistic locking - Vlad Mihalcea this leads to a race condition. The proposed workaround in the article is to upgrade the lock but then what’s the point of explicitly locking it optimistically in the first place (not to mention issuing a pessimistic lock will require the db connection to be open).

Is there a reason why Hibernate ORM chose to implement the explicit optimistic lock check via a SELECT instead of an UPDATE (i.e. UPDATE a SET version = 1 WHERE id = xyz AND version = 1) which would acquire a write lock on the record and therefore (in theory) prevent the race condition?

Thanks in advance!

You have to use OPTIMISTIC_FORCE_INCREMENT if you want the update to happen.

Thanks for the suggestion, Christian.

FORCE INCREMENT, however, does not fit the use case since it actually updates the entity (which would then need to be invalidated from caches, etc.). My goal is only to make sure that the entity is locked but not updated (the SQL statement I listed as an example achieves that). Was there an intentional design decision to allow for (an albeit short) time window where the entity can change (i.e. after the SELECT VERSION but before the transaction commit)?

If you want to lock the entity, then use PESSIMISTIC_WRITE which will execute a select .. for update statement. It’s all described in the Javadoc of the LockModeType enumeration.