Caching Strategies - First Level and Second Level Caches

Site Admin · 11 Sep 2026 · 9 views

Caching Strategies - First Level and Second Level Caches

Every database call has overhead - network latency, SQL parsing, result set mapping. Caching stores frequently accessed data in memory to avoid repeated trips to the database. Hibernate provides two levels of caching, each with different scope, lifecycle, and use cases.

First Level Cache (Session Cache)

The first level cache is automatic and built into every Hibernate session. When you load an entity, Hibernate stores it in the persistence context. Any subsequent request for the same entity within the same session returns the cached instance without hitting the database:

// Same EntityManager instance
Book book1 = entityManager.find(Book.class, 1L);  // SELECT from DB
Book book2 = entityManager.find(Book.class, 1L);  // Returns cached, no SQL

The first level cache is scoped to the persistence context (typically one transaction in Spring). When the transaction completes and the EntityManager is closed, the cache is destroyed. This cache is not optional - you cannot disable it. It ensures identity within a single unit of work.

First Level Cache and Batch Inserts

The first level cache is also why batch inserts are efficient. When you persist 1000 entities, Hibernate does not issue 1000 INSERT statements immediately. It holds them in the cache and flushes them in batches:

for (int i = 0; i < 1000; i++) {
    Product product = new Product("Item " + i, 9.99);
    entityManager.persist(product);
    if (i % 50 == 0) {
        entityManager.flush();
        entityManager.clear(); // Clear cache to free memory
    }
}
entityManager.flush();

Calling entityManager.clear() evicts all cached entities, preventing the first level cache from consuming unbounded memory during large batch operations.

Second Level Cache (Shared Cache)

The second level cache persists across sessions and transactions. When one session loads an entity, it is stored in the second level cache. The next session that requests the same entity gets it from cache without any database call. This is configured per entity:

@Entity
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Category {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;
}

The @Cacheable annotation enables the second level cache for this entity. CacheConcurrencyStrategy.READ_ONLY is safe for data that does not change. Other strategies include READ_WRITE, NONSTRICT_READ_WRITE, and TRANSACTIONAL for entities that are updated.

Cache Providers

Hibernate does not implement its own cache storage. It delegates to a cache provider. Common options are Ehcache, Hazelcast, Infinispan, and Caffeine (for single-node applications). You configure the provider in your application properties and Hibernate plugs into it automatically.

# application.properties
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=org.hibernate.cache.jcache.JCacheRegionFactory
spring.cache.jcache.config=classpath:ehcache.xml

Cache Invalidation

The hardest part of caching is knowing when cached data is stale. READ_ONLY caches never expire data - if the database row changes, the cache is wrong until restart. READ_WRITE caches use soft locks to invalidate entries when the owning entity is updated. For distributed systems, you must ensure all nodes invalidate the same cache regions when data changes.

Real-World Scenario

A news website serves millions of page views. The Category and Tag entities change rarely - maybe a few times a day - but are read on every single page. With a second level cache configured as READ_ONLY, these entities are loaded once from the database and served from memory for all subsequent requests. This alone can eliminate thousands of database queries per second without any code changes.

Key Points

  • The first level cache is automatic, scoped to one session, and ensures entity identity within a transaction.
  • The second level cache persists across sessions and must be explicitly enabled per entity.
  • Second level caching is ideal for rarely changed data that is read frequently, such as lookup tables.
  • Cache concurrency strategies (READ_ONLY, READ_WRITE, TRANSACTIONAL) control consistency guarantees.
  • Hibernate delegates second level cache storage to providers like Ehcache, Hazelcast, or Caffeine.
Share this post:

Comments (0)

Please login or register to comment.