A persistence context is the set of entity instances managed by an EntityManager. It tracks their state within a unit of work, detects changes to managed instances, and can synchronize those changes with the database. Creating an application-managed EntityManager starts its context; closing the EntityManager ends it. A context can exist without an active transaction. section 10.1 section 10.1.2 section 11.3.1
The context is also a first-level cache. Within one context, repeated find() calls for the same entity type and identifier return the same managed instance rather than loading another. When a query returns an entity already managed by the context, that instance is reused. A scalar query instead returns values read from its database result. section 10.1.2 section 10.2.3 section 11.3.1
Path: managing-data/src/test/java/com/manning/javapersistence/ch10 /SimpleTransitionsTest.java – retrievePersistent() Item itemA = em.find(Item.class, ITEM_ID); #1 Item itemB = em.find(Item.class, ITEM_ID); #2 assertTrue(itemA == itemB); assertTrue(itemA.equals(itemB)); assertTrue(itemA.getId().equals(itemB.getId())); #1 The first <kbd>find()</kbd> operation hits the database and retrieves the <kbd>Item</kbd> instance with a <kbd>SELECT</kbd> statement. #2 The second <kbd>find()</kbd> is a repeatable read and is resolved in the persistence context, and the same cached <kbd>Item</kbd> instance is returned.
Two identifier lookups return the same Java object in one persistence context. section 10.2.3
For example, find an Item and change its name inside a transaction. No explicit update call is needed: at flush, the provider checks the managed instance for changes and issues the necessary SQL UPDATE. Flush normally occurs when the joined transaction commits; Hibernate may also flush before a query, and EntityManager.flush() requests synchronization during a transaction. FlushModeType.COMMIT postpones synchronization before queries, so a query may return a database value older than the value held in memory. section 10.2.3 section 10.2.9
Context and transaction boundaries need not coincide. Without a transaction, Hibernate can read entities and retain in-memory modifications, but it does not flush them automatically; calling flush() raises TransactionRequiredException. Operations such as persist(), merge(), and remove() can queue changes in an unsynchronized context for a later joined transaction. In the persist() example, obtaining an identifier before INSERT requires a pre-insert identifier generator. section 11.3.1 section 11.3.2
Path: Ch11/transactions4/src/test/java/com/manning/javapersistence/ch11 /concurrency/NonTransactional.java EntityManager em = emf.createEntityManager(); Item newItem = new Item("New Item"); em.persist(newItem); #1 assertNotNull(newItem.getId()); em.getTransaction().begin(); #2 if (!em.isJoinedToTransaction()) { em.joinTransaction(); } em.getTransaction().commit(); #3 em.close(); #1 Call <kbd>persist()</kbd> to save a transient entity instance with an unsynchronized persistence context. #2 Join the persistence context with a transaction. #3 Synchronization and flushing occur when the transaction commits.
The sequence separates persist() from joining a transaction and committing the queued INSERT. section 11.3.2
Keep the context no larger than the unit of work requires. Its cache does not shrink automatically, and loading many entities can consume substantial memory through retained instances and state snapshots. Narrow queries to needed data; use detach() to evict one instance or clear() to detach all. Hibernate read-only settings can avoid snapshots and dirty checking where modifications need not be written. Close an application-managed EntityManager in a finally block. section 10.2.8 section 10.2.1
