Automatic version checking detects competing changes to a JPA entity without locking it throughout a unit of work. It suits multiuser applications where concurrent modifications are uncommon and a conflict can be detected when changes are flushed. section 11.2.2
Add a numeric `@Version` property to the entity. It maps to a database column; the application should not set its value. When Hibernate flushes a dirty entity, it increments the version and includes the previously read version in the `UPDATE` condition. For example, an entity read at version 0 produces an update shaped like `UPDATE ITEM SET NAME = ?, VERSION = 1 WHERE ID = ? AND VERSION = 0`. If another transaction has changed the row, the flush raises an `OptimisticLockException` rather than silently overwriting that change. 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>.
Follow the entity load, intervening change, and failed flush alongside the version condition in the generated SQL. section 11.2.2
Choose the check that matches the unit of work:
- For ordinary entity changes, `@Version` supplies the automatic check. A `LocalDateTime` version property is also shown as a timestamp-based mapping. section 11.2.2
- For reads that must be checked even without an entity update, request `LockModeType.OPTIMISTIC` on the query. section 11.2.2
- When an operation such as persisting a related `Bid` must change an `Item` version, request `LockModeType.OPTIMISTIC_FORCE_INCREMENT`. section 11.2.2
Hibernate also shows a versionless alternative using its `OptimisticLocking` and `DynamicUpdate` annotations: an update compares previously read column values in its `WHERE` clause. That approach is Hibernate-specific, unlike the basic JPA `@Version` mapping. section 11.2.2
