Multi-version concurrency control (MVCC) implements transaction isolation by retaining multiple data versions. Each transaction can read a consistent snapshot, reducing dependence on blocking locks and often improving scalability. section 11.2
In a Java Persistence application, MVCC affects transaction design in several practical ways:
- A database such as Oracle or PostgreSQL can give each transaction a snapshot containing data as it existed before that transaction began. section 11.3.1
- Snapshot isolation can prevent unrepeatable and phantom reads, whereas auto-commit provides no transaction scope for a meaningful snapshot. section 11.3.1
- Grouping even read-only operations in a system transaction makes transaction boundaries easier to understand and reduces difficult-to-find concurrency problems. section 11.3.1
- Hibernate normally flushes database changes at commit, so write locks are held late and for a relatively short period. section 11.3.1
Reading with a persistence context
An EntityManager loads an Item, changes its name, and queries the same item again before an explicit flush. The persistence context returns the changed value, while the database write remains deferred; em.refresh(item) reloads the entity state. section 11.3.1
Listing 11.7 Reading data in auto-commit mode
Path: Ch11/transactions4/src/test/java/com/manning/javapersistence/ch11 /concurrency/NonTransactional.java EntityManager em = emf.createEntityManager(); #1 Item item = em.find(Item.class, ITEM_ID); #2 item.setName("New Name"); assertEquals( #3 "Original Name", em.createQuery("select i.name from Item i where i.id = :id", String.class) .setParameter("id", ITEM_ID).getSingleResult() ); assertEquals( #4 "New Name", em.createQuery("select i from Item i where i.id = :id". Item.class) .setParameter("id", ITEM_ID).getSingleResult().getName() ); // em.flush(); #5 em.refresh(item); #6 assertEquals("Original Name", item.getName()); em.close(); #1 No transaction is active when creating the <kbd>EntityManager</kbd>. #2 Access the database to read data. #3 Because the context is unsynchronized, flushing doesn’t occur, and the query returns the old, original database value. #4 The already-loaded <kbd>Item</kbd> instance with the changed name is returned from the persistence context; values from the database are ignored. #5 You cannot execute an <kbd>UPDATE</kbd> in unsynchronized mode, because you wouldn’t be able to roll back the change. #6 Roll back the change you made with the <kbd>refresh()</kbd> method.
Inspect the complete EntityManager example showing entity lookup, in-memory modification, repeated queries, deferred flushing, and refresh behavior. section 11.3.1



