liveBook · Manning

OptimisticLockException

As explained in Java Persistence with Spring Data and Hibernate epub

OptimisticLockException is the JPA exception indicating that an optimistic concurrency check detected a conflicting update or deletion.

OptimisticLockException signals that an optimistic concurrency check failed. With an @Version field, Hibernate includes the entity’s loaded version in an UPDATE or DELETE condition. If the statement affects no rows, Hibernate detects the conflict during flushing: the row may have changed or been deleted. section 11.2.2

First commit wins

Two transactions load an Item at version 0. The first commits an update at version 1. The second transaction’s update cannot match version 0, so flushing throws OptimisticLockException. The user can be asked to restart with fresh data. section 11.2.2

Listing 11.2 Hibernate incrementing and checking the version automatically
Path: /Ch11/transactions/src/test/java/com/manning/javapersistence/ch11
 /concurrency/Versioning.java – firstCommitWins()
 
   EntityManager em1 = emf.createEntityManager();
   em1.getTransaction().begin();
Item item = em1.find(Item.class, ITEM_ID);                             #1
// select * from ITEM where ID = ?
assertEquals(0, item.getVersion());                                    #2
item.setName("New Name");
// . . .  Another transaction changes the record
assertThrows(OptimisticLockException.class, () -> em1.flush());        #3
// update ITEM set NAME = ?, VERSION = 1 where ID = ? and VERSION = 0
#1 Retrieving an entity instance by identifier loads the current version from the database with a <kbd>SELECT</kbd>.
#2 The current version of the <kbd>Item</kbd> instance is <kbd>0</kbd>.
#3 When the persistence context is flushed, Hibernate detects the dirty <kbd>Item</kbd> instance and increments its version to <kbd>1</kbd>. SQL <kbd>UPDATE</kbd> now performs the version check, storing the new version in the database, but only if the database version is still <kbd>0</kbd>.

The listing shows the versioned UPDATE and the flush call expected to throw the exception. section 11.2.2

How Java Persistence with Spring Data and Hibernate epub covers it

How deep it goes
Traces detection through flush-time SQL version checks and affected-row counts.
Examples
Shows two transactions updating an Item after loading version 0.
What it assumes
Assumes familiarity with entities and transactions while showing the @Version mapping and generated SQL.
What you can do after
Diagnose/debug with it a failed version check and prompt a restart with fresh data.
How it connects
Connects @Version, flushing, JDBC affected-row counts, and optimistic concurrency control.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Java Persistence with Spring Data and Hibernate epub. The section links point to the parts of the book it draws on.