How does first-level cache work in JPA?
The first-level cache, also known as the Persistence Context cache, is a mandatory and essential component of the JPA specification. It plays a crucial role in managing entity lifecycles and optimizing database interactions within a single transaction or session.
What is the First-Level Cache?
The first-level cache is a transactional cache that is automatically associated with each active Persistence Context (i.e., an EntityManager instance). Its scope is typically limited to a single transaction or an extended Persistence Context, meaning entities cached in one transaction are not visible to another.
Its primary purpose is to ensure that within a given Persistence Context, all operations on an entity with a specific identifier refer to the same object instance, thus maintaining object identity and reducing unnecessary database calls.
How it Works
Entity Storage and Retrieval
When an entity is persisted, merged, or retrieved from the database using methods like find() or a query, JPA stores a copy of that entity in the first-level cache. Subsequent requests for the same entity within the same Persistence Context will first check the cache.
- If the entity is found in the cache, JPA returns the cached instance immediately, avoiding a trip to the database.
- If the entity is not found in the cache, JPA executes a database query, retrieves the data, constructs a new entity object, stores it in the first-level cache, and then returns this newly created and cached instance.
Dirty Checking and Synchronization
The first-level cache also tracks changes made to managed entities. When an entity is loaded into the cache, JPA typically takes a snapshot of its state. If a managed entity's state changes (i.e., its properties are modified), the Persistence Context marks it as 'dirty'.
At specific points, such as before a commit or when flush() is explicitly called, JPA performs 'dirty checking'. It compares the current state of the managed entities with their initial snapshots. For any dirty entity, JPA generates and executes the necessary SQL UPDATE statements to synchronize the database with the changes in the application's memory.
Object Identity
A key function of the first-level cache is to guarantee that within a single Persistence Context, an entity with a specific identifier (primary key) always maps to the same Java object instance. This ensures referential integrity and prevents issues like having multiple Java objects representing the exact same database row.
Benefits
- Performance Optimization: Reduces the number of database queries by serving entities directly from memory, especially for frequently accessed entities within a transaction.
- Object Identity: Guarantees that within a single Persistence Context, an entity with a given primary key always corresponds to the same Java object instance, preventing data consistency issues.
- Transactional Write-Behind: Enables JPA to track changes to managed entities and batch update operations, flushing them to the database only when necessary (e.g., at transaction commit), optimizing database writes.
Lifecycle
The first-level cache is intrinsically tied to the lifecycle of the EntityManager. It is created when an EntityManager instance is created and cleared or destroyed when the EntityManager is closed. This means that entities loaded in one EntityManager's cache are not automatically available in another EntityManager's cache. Each EntityManager operates with its own isolated first-level cache.