Close

Cache Retrieve Mode

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

If the second-level cache has been enabled by setting the <shared-cache-mode>, the behavior of the second-level cache can be overridden by setting the property of javax.persistence.cache.retrieveMode and/or javax.persistence.cache.storeMode.

javax.persistence.cache.retrieveMode property (this tutorial) controls whether to read from second-level cache or not, whereas javax.persistence.cache.storeMode property (next tutorial) controls whether to store data to the second-level cache while reading or committing data.

There are two ways to set these properties:

  • At persistence context level by passing the property name and value to the EntityManager.setProperty() method.
  • At per-EntityManager operation level (EntityManager.find() or EntityManager.refresh()) or per-query level.

javax.persistence.cache.retrieveMode can be assigned to one of the enum value of CacheRetrieveMode. This enum has two constants:

package javax.persistence;
 ....
public enum CacheRetrieveMode {
    /**
     * Read entity data from the cache: this is
     * the default behavior.
     */
    USE,

    /**
     * Bypass the cache: get data directly from
     * the database.
     */
    BYPASS
}

Since CacheRetrieveMode.USE is the default mode, we are going to use CacheRetrieveMode.BYPASS only in the following example.

Example

In the following example, 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 Entities

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

The main class

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

  public static void main(String[] args) {
      try {
          System.out.println("-- persisting entities --");
          persistEntities();
          System.out.println("-- loading entities --");
          loadEntities();
          System.out.println("-- loading entities with CacheRetrieveMode.BYPASS --");
          loadEntities2();
          System.out.println("-- loading entities with CacheRetrieveMode.BYPASS for employee only --");
          loadEntities3();
      } finally {
          entityManagerFactory.close();
      }
  }

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

  private static void loadEntities() {
      EntityManager em = entityManagerFactory.createEntityManager();
      Employee employee = em.find(Employee.class, 1L);
      System.out.println("Employee loaded: " + employee);
      Task task = em.find(Task.class, 2L);
      System.out.println("Task loaded: " + task);
      em.close();
  }

  private static void loadEntities2() {
      EntityManager em = entityManagerFactory.createEntityManager();
      em.setProperty("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
      Employee employee = em.find(Employee.class, 1L);
      System.out.println("Employee loaded: " + employee);
      Task task = em.find(Task.class, 2L);
      System.out.println("Task loaded: " + task);
      em.close();
  }

  private static void loadEntities3() {
      EntityManager em = entityManagerFactory.createEntityManager();
      Map<String, Object> properties = new HashMap<>();
      properties.put("javax.persistence.cache.retrieveMode", CacheRetrieveMode.BYPASS);
      Employee employee = em.find(Employee.class, 1L, properties);
      System.out.println("Employee loaded: " + employee);
      Task task = em.find(Task.class, 2L);
      System.out.println("Task loaded: " + task);
      em.close();
  }
}
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))
Hibernate: create table Task (id bigint not null, description varchar(255), primary key (id))
-- persisting entities --
Hibernate: call next value for hibernate_sequence
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Employee (dept, name, id) values (?, ?, ?)
Hibernate: insert into Task (description, id) values (?, ?)
Employee persisted: Employee{id=1, name='Dawn', dept='IT'}
Task persisted: Task{id=2, description='UI Coding'}
-- loading entities --
Employee loaded: Employee{id=1, name='Dawn', dept='IT'}
Task loaded: Task{id=2, description='UI Coding'}
-- loading entities with retrieveMode=CacheRetrieveMode.BYPASS --
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'}
Hibernate: select task0_.id as id1_1_0_, task0_.description as descript2_1_0_ from Task task0_ where task0_.id=?
Task loaded: Task{id=2, description='UI Coding'}
-- loading entities with retrieveMode=CacheRetrieveMode.BYPASS for employee only --
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'}
Task loaded: Task{id=2, description='UI Coding'}

Above output shows that:

  • When CacheRetrieveMode.BYPASS is not specified at all (in loadEntities() method) then both entities are loaded from the second-level cache (no SQL 'select' was fired).
  • When CacheRetrieveMode.BYPASS is specified on the EntityManager context level (in loadEntities2()) then both entities are loaded directly from database, hence bypassing the second-level cache.
  • When CacheRetrieveMode.BYPASS is specified targeting only one find method (while loading employee in loadEntities3()) then employee is loaded from database, whereas, Task is loaded from the cache.

Note that CacheRetrieveMode.BYPASS just by passes the local cache and reads directly from the database. This mode does not update the data in the existing cache, if the directly retrieved data and cached data are different.

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.
  • hibernate-ehcache 5.2.12.Final: Integration for Ehcache into Hibernate as a second-level caching service.
  • JDK 1.8
  • Maven 3.3.9

CacheRetrieveMode.BYPASS Example Select All Download
  • jpa-cache-retrieve-mode
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • resources
          • META-INF

See Also