Hibernate Caching
Hibernate Cache Levels
Hibernate provides two levels of caching to improve performance by reducing database queries:
| Cache Level | Scope | Default | Description |
|---|---|---|---|
| First-Level Cache (L1) | Session | Always enabled | Per-session cache. Entities loaded in a session are cached for the session's lifetime. |
| Second-Level Cache (L2) | SessionFactory | Disabled | Shared across sessions. Requires a cache provider (EHCache, Infinispan, etc.). |
| Query Cache | SessionFactory | Disabled | Caches query results. Works with L2 cache. |
Session session = sessionFactory.openSession();
// First get: hits the database
User user1 = session.get(User.class, 1L);
System.out.println("First get: " + user1.getUsername()); // SQL executed
// Second get: served from L1 cache (same session)
User user2 = session.get(User.class, 1L);
System.out.println("Second get: " + user2.getUsername()); // NO SQL - from cache
// Same object reference
System.out.println(user1 == user2); // true
// Clear L1 cache
session.evict(user1); // Remove specific entity from cache
// session.clear(); // Clear entire L1 cache
// After evict: hits database again
User user3 = session.get(User.class, 1L);
System.out.println("After evict: " + user3.getUsername()); // SQL executed again
session.close();
// L1 cache is destroyed when session closes
Second-Level Cache with EHCache
<!-- Enable L2 cache in hibernate.cfg.xml -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.jcache.JCacheRegionFactory
</property>
<!-- pom.xml dependency -->
<!--
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>6.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.10.8</version>
</dependency>
-->
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
// Cache strategies:
// READ_ONLY: For data that never changes (best performance)
// READ_WRITE: For data that changes occasionally (uses soft locks)
// NONSTRICT_READ_WRITE: No strict locking (slight risk of stale data)
// TRANSACTIONAL: Full transactional cache (JTA required)
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Product {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
}
// Cache a collection
@Entity
public class User {
@OneToMany(mappedBy = "user")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private List<Order> orders;
}
// Using query cache
Session session = sessionFactory.openSession();
List<Product> products = session.createQuery("FROM Product", Product.class)
.setCacheable(true) // Enable query cache
.setCacheRegion("productCache") // Optional: named cache region
.list();
session.close();
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.