Careeroza
The Persistence Context
What It Is
Every EntityManager owns a persistence context: a map from (entity type, id) to the one Java object that represents that row. Hibernate also calls it the first-level cache. While an entity is in this map it is managed: Hibernate watches it and saves its changes.
EntityManager
+-- persistence context
(Product, 1) -> Product@A { name=Boat Rockerz 450, stock=120 }
(Product, 3) -> Product@B { name=Noise ColorFit Pro, stock=40 }
(User, 7) -> User@C { [email protected] }
+ a snapshot of each one's loaded values (for dirty checking)Two Guarantees
- Repeatable identity: inside one persistence context,
em.find(Product.class, 1L)twice returns the same object (==is true). - One SELECT per row: the second
findis answered from the map, without SQL. - The context lives as long as the EntityManager — in Spring Boot that is normally one transaction. It is not a global cache shared between users.
Identity Map, Simulated
Example
A miniature persistence context: find checks the map first and only "queries the database" on a miss.
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<Long, String> productsTable = new TreeMap<>(Map.of(
1L, "Boat Rockerz 450", 3L, "Noise ColorFit Pro"));
MiniEntityManager em = new MiniEntityManager(productsTable);
Product a = em.find(1L);
Product b = em.find(1L); // same id again
Product c = em.find(3L);
System.out.println("a == b ? " + (a == b));
System.out.println("a == c ? " + (a == c));
System.out.println("SQL queries run: " + em.queries);
em.clear(); // new transaction / context
Product d = em.find(1L);
System.out.println("after clear, a == d ? " + (a == d));
System.out.println("SQL queries run: " + em.queries);
}
}
class Product {
final Long id; String name;
Product(Long id, String name) { this.id = id; this.name = name; }
}
class MiniEntityManager {
private final Map<Long, String> table;
private final Map<Long, Product> context = new LinkedHashMap<>();
int queries = 0;
MiniEntityManager(Map<Long, String> table) { this.table = table; }
Product find(Long id) {
Product cached = context.get(id);
if (cached != null) { System.out.println("find(" + id + "): from persistence context"); return cached; }
queries++;
System.out.println("find(" + id + "): select ... from products where id=" + id);
String name = table.get(id);
if (name == null) return null;
Product p = new Product(id, name);
context.put(id, p);
return p;
}
void clear() { context.clear(); }
}Output
find(1): select ... from products where id=1 find(1): from persistence context find(3): select ... from products where id=3 a == b ? true a == c ? false SQL queries run: 2 find(1): select ... from products where id=1 after clear, a == d ? false SQL queries run: 3