Close

Cache Store Mode

[Updated: Mar 23, 2018, Created: Mar 23, 2018]

In the last example, we saw how to use javax.persistence.cache.retrieveMode. In this example, we will understand the use javax.persistence.cache.storeMode

javax.persistence.cache.storeMode controls whether or not second-level cache should be stored/updated while committing/reading data from database.

javax.persistence.cache.storeMode can be assigned to one of the enum value of CacheStoreMode. This enum has three constants:

package javax.persistence;
 ....
public enum CacheStoreMode {
    /**
     * Insert/update entity data into cache when read
     * from database and when committed into database:
     * this is the default behavior. Does not force refresh
     * of already cached items when reading from database.
     */
    USE,

    /**
     * Don't insert into cache.
     */
    BYPASS,

    /**
     * Insert/update entity data into cache when read
     * from database and when committed into database.
     * Forces refresh of cache for items read from database.
     */
    REFRESH
}

Example

In the following example also, we are going to use shared-cache-mode=ALL mode.

persistence.xml

src/main/resources/META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

    <persistence-unit name="example-unit" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
        <exclude-unlisted-classes>false</exclude-unlisted-classes>
        <shared-cache-mode>ALL</shared-cache-mode>
        <properties>
            <property name="javax.persistence.schema-generation.database.action" value="create"/>
            <property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
            <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"/>
            <property name="hibernate.cache.region.factory_class"
                      value="org.hibernate.cache.ehcache.EhCacheRegionFactory"/>
            <property name="hibernate.show_sql" value="true"/>
        </properties>
    </persistence-unit>

</persistence>

The Entity

@Entity
public class Employee {
  @Id
  @GeneratedValue
  private long id;
  private String name;
  private String dept;
    .............
}

Using CacheStoreMode.BYPASS

public class ExampleMain {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");

  public static void main(String[] args) {
      try {
          System.out.println("-- persisting entity --");
          persistEntity();
          System.out.println("-- loading entity --");
          loadEntity();
      } finally {
          entityManagerFactory.close();
      }
  }

  public static void persistEntity() {
      Employee employee = new Employee();
      employee.setName("Dawn");
      employee.setDept("IT");
      EntityManager em = entityManagerFactory.createEntityManager();
      em.setProperty("javax.persistence.cache.storeMode", CacheStoreMode.BYPASS);
      em.getTransaction().begin();
      em.persist(employee);
      em.getTransaction().commit();
      System.out.println("Employee persisted: " + employee);
      em.close();
      printCacheState();
  }

  private static void loadEntity() {
      EntityManager em = entityManagerFactory.createEntityManager();
      Employee employee = em.find(Employee.class, 1L,
              Collections.singletonMap("javax.persistence.cache.storeMode", CacheStoreMode.BYPASS));
      System.out.println("Employee loaded: " + employee);
      em.close();
      printCacheState();
  }

  private static void printCacheState() {
      Cache cache = entityManagerFactory.getCache();
      boolean contains = cache.contains(Employee.class, 1L);
      System.out.printf("Cache#contains() for Employee: %5s%n", contains);
  }
}
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: create table Employee (id bigint not null, dept varchar(255), name varchar(255), primary key (id))
-- persisting entity --
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Employee (dept, name, id) values (?, ?, ?)
Employee persisted: Employee{id=1, name='Dawn', dept='IT'}
Cache#contains() for Employee: false
-- loading entity --
Hibernate: select employee0_.id as id1_0_0_, employee0_.dept as dept2_0_0_, employee0_.name as name3_0_0_ from Employee employee0_ where employee0_.id=?
Employee loaded: Employee{id=1, name='Dawn', dept='IT'}
Cache#contains() for Employee: false

As seen in the above output, during inserting data (in persistEntity() method) and during reading data (in loadEntity() method), no second-level cache was stored because of the CacheStoreMode.BYPASS in both cases.

Using CacheStoreMode.REFRESH

In the following example, we are not going to use any CacheStoreMode while persisting data (CacheStoreMode.USE will be applied), that means data will be stored in the second-level cache. Then while loading data, we will specify CacheStoreMode#REFRESH:

public class ExampleMain2 {
  private static EntityManagerFactory entityManagerFactory =
          Persistence.createEntityManagerFactory("example-unit");

  public static void main(String[] args) {
      try {
          System.out.println("-- persisting entity --");
          persistEntity();
          System.out.println("-- loading entity --");
          loadEntity();
      } finally {
          entityManagerFactory.close();
      }
  }

  public static void persistEntity() {
      Employee employee = new Employee();
      employee.setName("Dawn");
      employee.setDept("IT");
      EntityManager em = entityManagerFactory.createEntityManager();
      em.getTransaction().begin();
      em.persist(employee);
      em.getTransaction().commit();
      System.out.println("Employee persisted: " + employee);
      em.close();
      printCacheState();
  }

  private static void loadEntity() {
      EntityManager em = entityManagerFactory.createEntityManager();
      Employee employee = em.find(Employee.class, 1L,
              Collections.singletonMap("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH));
      System.out.println("Employee loaded: " + employee);
      em.close();
      printCacheState();
  }

  private static void printCacheState() {
      Cache cache = entityManagerFactory.getCache();
      boolean contains = cache.contains(Employee.class, 1L);
      System.out.printf("Cache#contains() for Employee: %5s%n", contains);
  }
}
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: create table Employee (id bigint not null, dept varchar(255), name varchar(255), primary key (id))
-- persisting entity --
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Employee (dept, name, id) values (?, ?, ?)
Employee persisted: Employee{id=1, name='Dawn', dept='IT'}
Cache#contains() for Employee: true
-- loading entity --
Hibernate: select employee0_.id as id1_0_0_, employee0_.dept as dept2_0_0_, employee0_.name as name3_0_0_ from Employee employee0_ where employee0_.id=?
Employee loaded: Employee{id=1, name='Dawn', dept='IT'}
Cache#contains() for Employee: true

As seen in the above output, in both cases (persisting and loading), the Employee entity is stored in the second-level cache, but still during find() operation (in loadEntity() method) a 'select' statement is fired, showing that data is read directly from database, hence it's been refreshed. In case if data has externally been changed then second level-cache will get updated (refreshed) with new data.

Example Project

Dependencies and Technologies Used:

  • h2 1.4.196: H2 Database Engine.
  • hibernate-core 5.2.12.Final: The core O/RM functionality as provided by Hibernate.
    Implements javax.persistence:javax.persistence-api version 2.1
  • hibernate-ehcache 5.2.12.Final: Integration for Ehcache into Hibernate as a second-level caching service.
  • JDK 1.8
  • Maven 3.3.9

CacheStoreMode Examples Select All Download
  • jpa-cache-store-mode
    • src
      • main
        • java
          • com
            • logicbig
              • example
                • ExampleMain.java
          • resources
            • META-INF

    See Also