Hibernate L2 Cache with Infinispan (Standalone)

What You Will Learn

How to configure Infinispan as the Hibernate second-level (L2) cache provider in a standalone Java SE application, and observe entity cache puts, hits, misses, and query cache behavior through Hibernate statistics.

Prerequisites

  • Java 17+

Step 1: Add the Infinispan Hibernate Cache Dependency

Add the Infinispan Hibernate cache module and an in-memory database to your pom.xml:

<dependency>
   <groupId>org.hibernate.orm</groupId>
   <artifactId>hibernate-core</artifactId>
</dependency>
<dependency>
   <groupId>org.infinispan</groupId>
   <artifactId>infinispan-hibernate-cache-v66</artifactId>
</dependency>
<dependency>
   <groupId>com.h2database</groupId>
   <artifactId>h2</artifactId>
</dependency>

Step 2: Configure the Persistence Unit

In META-INF/persistence.xml, enable the second-level cache and query cache, and set Infinispan as the cache provider:

   <persistence-unit name="events">
      <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
      <properties>
         <!-- H2 in-memory database -->
         <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
         <property name="hibernate.connection.url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE"/>
         <property name="hibernate.connection.driver_class" value="org.h2.Driver"/>
         <property name="hibernate.connection.username" value="sa"/>
         <property name="hibernate.connection.password" value=""/>

         <!-- Create/drop database in each run -->
         <property name="hibernate.hbm2ddl.auto" value="create-drop" />

         <!-- Enables second level cache -->
         <property name="hibernate.cache.use_second_level_cache" value="true"/>
         <!-- Enable query cache -->
         <property name="hibernate.cache.use_query_cache" value="true"/>

         <!-- Use Infinispan second level cache provider -->
         <property name="hibernate.cache.region.factory_class"
                   value="infinispan"/>
         <!-- Force using local configuration when only using a single node.
              Otherwise a clustered configuration is loaded. -->
         <property name="hibernate.cache.infinispan.cfg"
                   value="org/infinispan/hibernate/cache/commons/builder/infinispan-configs-local.xml"/>

         <!-- Generate statistics to see effects of second level cache -->
         <property name="hibernate.generate_statistics" value="true" />

         <!-- Entity specific configuration, e.g. via property:
                 hibernate.cache.infinispan.<Entity FQN>.expiration.max_idle
         -->
         <property name="hibernate.cache.infinispan.org.infinispan.tutorial.simple.hibernate.cache.local.model.Person.expiration.max_idle"
                   value= "1000"/>
      </properties>
   </persistence-unit>

Step 3: Mark Entities as Cacheable

Annotate your JPA entities with @Cacheable so they participate in second-level caching:

@Entity
@Cacheable
public class Event {

   @Id
   @GeneratedValue
   private Long id;

   private String name;

   private LocalDateTime timestamp = LocalDateTime.now();

Step 4: Use the Entity Manager and Observe Cache Statistics

Persist, find, update, and query entities. Hibernate statistics reveal L2 cache activity:

      // Create JPA persistence manager
      emf = Persistence.createEntityManagerFactory("events");

      CacheRegionStatistics eventCacheStats;
      CacheRegionStatistics personCacheStats;
      Statistics stats;

      // Persist 3 entities, stats should show 3 second level cache puts
      persistEntities();
      eventCacheStats = getCacheStatistics(Event.class.getName());
      printfAssert("Event entity cache puts: %d (expected %d)%n", eventCacheStats.getPutCount(), 3);

      // Find one of the persisted entities, stats should show a cache hit
      findEntity(1L);
      eventCacheStats = getCacheStatistics(Event.class.getName());
      printfAssert("Event entity cache hits: %d (expected %d)%n", eventCacheStats.getHitCount(), 1);

Step 5: Run the Tutorial

mvn package exec:exec

The output shows cache puts when entities are persisted, cache hits when entities are found, cache misses after eviction, and query cache behavior on repeated queries.

What’s Next