Hibernate handles concurrent access to the same data through two locking strategies: optimistic locking, which detects conflicts at commit time using a version field, and pessimistic locking, which prevents conflicts upfront by holding a database lock.
Key Points: • Optimistic locking (@Version) assumes conflicts are rare, checking the version at commit time and throwing OptimisticLockException on a mismatch. • Pessimistic locking acquires an actual database row lock (e.g. SELECT ... FOR UPDATE) via LockModeType.PESSIMISTIC_WRITE or PESSIMISTIC_READ, blocking other transactions until release. • Optimistic locking scales better for read-heavy workloads since it never blocks readers or other writers upfront. • Pessimistic locking is preferable when conflicts are frequent and retry logic would be too costly or complex. • Isolation levels configured at the transaction or connection level work alongside these strategies to further control what concurrent transactions can see.
Example: A high-traffic e-commerce catalog uses optimistic locking on Product prices since conflicting simultaneous edits are rare, while a seat-booking system for a single flight uses pessimistic locking on the Seat row to guarantee only one passenger can claim it at a time.
Code Example:
Product product = session.find(Product.class, id,
LockModeType.PESSIMISTIC_WRITE);Interview Tip: A concise interview answer is:
"Hibernate offers optimistic locking through a @Version field that detects conflicts at commit time, and pessimistic locking through explicit row-level database locks acquired upfront with LockModeType. I pick optimistic for read-heavy, low-conflict scenarios and pessimistic when conflicts are frequent enough that blocking is cheaper than retrying."