liveBook · Manning

Manual version checking

As explained in Java Persistence with Spring Data and Hibernate epub

Manual version checking explicitly requests version-aware reads or lock modes to verify that data remains unchanged during a unit of work.

Automatic version checking detects conflicts when a versioned entity is updated or deleted. A read-only unit of work may also need to know whether the entities it used changed before completion. Manual version checking requests that check explicitly. section 11.2.2

Map a version property with `@Version`, then request `LockModeType.OPTIMISTIC` on the query that loads the entities. Hibernate checks their versions at flush or commit, even if the transaction never modifies them. This suits work that can detect a rare conflict late rather than prevent concurrent changes. section 11.2.2

Listing 11.4 Requesting a version check at flush time to ensure repeatable reads
Path: /Ch11/transactions/src/test/java/com/manning/javapersistence/ch11
 /concurrency/Versioning.java – manualVersionChecking()
 
   EntityManager em = emf.createEntityManager();
   em.getTransaction().begin();
 
BigDecimal totalPrice = BigDecimal.ZERO;
for (Long categoryId : CATEGORIES) {
    List<Item> items =                                            #1
        em.createQuery("select i from Item i where i.category.id = :catId", 
 Item.class)
            .setLockMode(LockModeType.OPTIMISTIC)
            .setParameter("catId", categoryId)
            .getResultList();
    for (Item item : items)
        totalPrice = totalPrice.add(item.getBuyNowPrice());
}
  em.getTransaction().commit();                                   #2
em.close();
assertEquals("108.00", totalPrice.toString());
#1 For each <kbd>Category</kbd>, query all <kbd>Item</kbd> instances with an <kbd>OPTIMISTIC</kbd> lock mode. Hibernate now knows it has to check each <kbd>Item</kbd> at flush time.
#2 For each <kbd>Item</kbd> loaded earlier with the locking query, Hibernate executes a <kbd>SELECT</kbd> during flushing. It checks whether the database version of each <kbd>ITEM</kbd> row is still the same as when it was loaded. If any <kbd>ITEM</kbd> row has a different version or the row no longer exists, an <kbd>OptimisticLockException</kbd> is thrown.

The query requests an optimistic check while summing item prices across categories; committing completes the unit of work. section 11.2.2

When a related change must count as a conflict, `LockModeType.OPTIMISTIC_FORCE_INCREMENT` is a different choice: it requests a version increment even when the entity itself is not otherwise changed. section 11.2.2

How Java Persistence with Spring Data and Hibernate epub covers it

How deep it goes
Shows `@Version` mapping and query-level optimistic locking through transaction completion, but does not develop a general conflict-retry procedure.
Examples
Uses a category-by-category item price total whose queries request `LockModeType.OPTIMISTIC`.
What it assumes
Introduces `@Version` mapping while assuming familiarity with entity queries and transactions.
What you can do after
Apply it via JPA `EntityManager` queries to request version checks for entities used in a transaction.
How it connects
Links optimistic concurrency control, entity versioning, transaction commits, and optimistic lock modes.

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.