Monday, October 28, 2019

Hibernate 5 + JCache + Ehcache 3 Configuration Example



The JCache API (a.k.a. JSR-107) is a  Java specification for temporary, in memory caching of Java objects, including object creation, shared access, spooling, invalidation, and consistency across JVM's. 
Ehcache is open source and most widely used java based cache, which can be integrated with popular libraries and frameworks. Ehcache 3.x provides an implementation of JCache specification, which is fully compliant with the JCache API.
In this post, we will learn how to configure the Second-Level cache in Hibernate application using the JCache API with Ehcache’s implementation.
Technologies and tools used for this application are -
  • Hibernate 5.2.10.Final
  • Ehcache 3.3.1
  • JCache API 1.0
  • Log4j 2.8.2
  • JavaSE 1.8
  • Eclipse Neon.3
  • Maven 3.3.9
  • MySQL 5.7.12

Jar Dependencies

Open pom.xml file of your maven project and add the following dependencies in it.
  <dependencies>
    <!-- Mysql Connector -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>6.0.5</version>
    </dependency>

    <!-- Hibernate 5.2.10 Final -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>5.2.10.Final</version>
    </dependency>

    <!-- Hibernate Jcache -->
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-jcache</artifactId>
      <version>5.2.10.Final</version>
    </dependency>
    
  <!-- Ehcache 3.x -->
    <dependency>
      <groupId>org.ehcache</groupId>
      <artifactId>ehcache</artifactId>
      <version>3.3.1</version>
    </dependency>

    <!--Log4j2 API -->
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
      <version>2.8.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
      <version>2.8.2</version>
    </dependency>
    <dependency>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-slf4j-impl</artifactId>
      <version>2.8.2</version>
    </dependency>

  </dependencies>

Hibernate Utility class

To integrate the JCache API and Ehcache with Hibernate, you need to specify the following configuration properties.
1 - Enable second level cache (you can skip this property because default value is true for it).
hibernate.cache.use_second_level_cache = true
2 - Specify cache region factory class.
hibernate.cache.region.factory_class = org.hibernate.cache.jcache.JCacheRegionFactory
3 - Specify cache provider.
hibernate.javax.cache.provider = org.ehcache.jsr107.EhcacheCachingProvider
Here is the complete example of HibernateUitl helper class to bootstrap application.
HibernateUtil.java
package com.boraji.tutorial.hibernate;

import java.util.HashMap;
import java.util.Map;

import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;

import com.boraji.tutorial.hibernate.entity.Person;

/**
 * @author imssbora
 */
public class HibernateUtil {

   private static StandardServiceRegistry registry;
   private static SessionFactory sessionFactory;

   public static SessionFactory getSessionFactory() {
      if (sessionFactory == null) {
         try {
            StandardServiceRegistryBuilder registryBuilder = 
                  new StandardServiceRegistryBuilder();

            Map<String, Object> settings = new HashMap<>();
            settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver");
            settings.put(Environment.URL, "jdbc:mysql://localhost:3306/BORAJI?useSSL=false");
            settings.put(Environment.USER, "root");
            settings.put(Environment.PASS, "admin");
            settings.put(Environment.HBM2DDL_AUTO, "update");

            // Enable second level cache (default value is true)
            settings.put(Environment.USE_SECOND_LEVEL_CACHE, true);
            
            // Specify cache region factory class
            settings.put(Environment.CACHE_REGION_FACTORY,
                  "org.hibernate.cache.jcache.JCacheRegionFactory");
            
            // Specify cache provider
            settings.put("hibernate.javax.cache.provider", 
                  "org.ehcache.jsr107.EhcacheCachingProvider");

            registryBuilder.applySettings(settings);
            registry = registryBuilder.build();
            MetadataSources sources = new MetadataSources(registry)
                  .addAnnotatedClass(Person.class);
            Metadata metadata = sources.getMetadataBuilder().build();
            sessionFactory = metadata.getSessionFactoryBuilder().build();
         } catch (Exception e) {
            if (registry != null) {
               StandardServiceRegistryBuilder.destroy(registry);
            }
            e.printStackTrace();
         }
      }
      return sessionFactory;
   }

   public static void shutdown() {
      if (registry != null) {
         StandardServiceRegistryBuilder.destroy(registry);
      }
   }
}

Entity class

To enable entity caching, annotate entity class with @Cache annotation as follow.
Person.java
package com.boraji.tutorial.hibernate.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;

@Entity
@Table(name = "PERSONS")
@Cache(region = "personCache", usage = CacheConcurrencyStrategy.READ_ONLY)
public class Person implements Serializable {

   private static final long serialVersionUID = 1L;

   @Id
   @GeneratedValue
   @Column(name = "ID")
   private Long id;

   @Column(name = "NAME")
   private String name;

   // Setter and Getter methods
}

Ehcache logging

In this example, we will use the Slf4j API to enable logging for Ehcache and Hibernate.
So, create a log4j2.xml file under src/main/resources folder and write the following code in it.
log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <!-- Console Appender -->
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout pattern="%d{yyyy-MMM-dd HH:mm:ss a} [%t] %-5level %logger{36} - %msg%n" />
    </Console>
  </Appenders>
  <Loggers>
    <!-- Log SQL statements -->
    <Logger name="org.hibernate.SQL" level="debug" additivity="false">
      <AppenderRef ref="Console" />
    </Logger>
    <!-- Log cache -->
    <Logger name="org.hibernate.cache" level="debug" additivity="false">
      <AppenderRef ref="Console" />
    </Logger>
    <Logger name="org.ehcache" level="debug" additivity="false">
      <AppenderRef ref="Console" />
    </Logger>
    <Root level="error">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>

Run Application

Create the MainApp class to test the JCache, Ehcache and Hibernate configuration.
MainApp.java
package com.boraji.tutorial.hibernate;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.boraji.tutorial.hibernate.entity.Person;

/**
 * @author imssbora
 */
public class MainApp {

   public static void main(String[] args) {
      Session session = null;
      Transaction transaction = null;
      try {
        
         //Retrieve the person object from database
         session = HibernateUtil.getSessionFactory().openSession();
         transaction = session.beginTransaction();
         transaction.begin();
         Person person=session.get(Person.class, 1L);
         System.out.println(person);
         transaction.commit();
         session.close();
         
         //Retrieve the person object from cache
         session = HibernateUtil.getSessionFactory().openSession();
         transaction = session.beginTransaction();
         transaction.begin();
         Person person2=session.get(Person.class, 1L);
         System.out.println(person2);
         transaction.commit();
         session.close();
         
      } catch (Exception e) {
         e.printStackTrace();
      }
      
      HibernateUtil.shutdown();
   }
}
Output

Reference:
Previous Post
Next Post

0 komentar: