Query Cache in Hibernate
Let us understand the Query Cache
We know that, Query cache will cache the results of the query against the object.
If we have queries which runs multiple times with the same parameters then Query caching is best to use to avoid multiple DB calls.
Let us see complete project on Hibernate Query cache
Step 1
Create Hibernate project
Please refer Hibernate setup in eclipse article on how to do it.
Project structure
Step 2
Update pom.xml with required dependnecies
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>HibernateQueryCache</groupId>
- <artifactId>HibernateQueryCache</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>jar</packaging>
- <name>HibernateQueryCache</name>
- <url>http://maven.apache.org</url>
- <properties>
- <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
- </properties>
- <dependencies>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>3.8.1</version>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-core</artifactId>
- <version>5.2.6.Final</version>
- </dependency>
- <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>6.0.5</version>
- </dependency>
- <dependency>
- <groupId>org.hibernate</groupId>
- <artifactId>hibernate-ehcache</artifactId>
- <version>5.2.9.Final</version>
- </dependency>
- </dependencies>
- </project>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>HibernateQueryCache</groupId> <artifactId>HibernateQueryCache</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>HibernateQueryCache</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>5.2.6.Final</version> </dependency> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>6.0.5</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>5.2.9.Final</version> </dependency> </dependencies> </project>
Step 3
Create the Employee class
- package com.kb.model;
- import javax.persistence.Column;
- import javax.persistence.Entity;
- import javax.persistence.GeneratedValue;
- import javax.persistence.GenerationType;
- import javax.persistence.Id;
- import javax.persistence.Table;
- import org.hibernate.annotations.Cache;
- import org.hibernate.annotations.CacheConcurrencyStrategy;
- @Entity
- @Table(name="Employee")
- @Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="employeeCache")
- public class Employee {
- @Id
- @GeneratedValue(strategy = GenerationType.SEQUENCE)
- @Column(name = "Employee_Id")
- private int employeeId;
- @Column(name = "FirstName")
- private String firstName;
- @Column(name = "LastName")
- private String lastName;
- @Column(name = "Age")
- private int age;
- @Column(name = "Education")
- private String education;
- @Column(name = "Salary")
- private int salary;
- public int getEmployeeId() {
- return employeeId;
- }
- public void setEmployeeId(int employeeId) {
- this.employeeId = employeeId;
- }
- public String getFirstName() {
- return firstName;
- }
- public void setFirstName(String firstName) {
- this.firstName = firstName;
- }
- public String getLastName() {
- return lastName;
- }
- public void setLastName(String lastName) {
- this.lastName = lastName;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getEducation() {
- return education;
- }
- public void setEducation(String education) {
- this.education = education;
- }
- public int getSalary() {
- return salary;
- }
- public void setSalary(int salary) {
- this.salary = salary;
- }
- }
package com.kb.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; @Entity @Table(name="Employee") @Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="employeeCache") public class Employee { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @Column(name = "Employee_Id") private int employeeId; @Column(name = "FirstName") private String firstName; @Column(name = "LastName") private String lastName; @Column(name = "Age") private int age; @Column(name = "Education") private String education; @Column(name = "Salary") private int salary; public int getEmployeeId() { return employeeId; } public void setEmployeeId(int employeeId) { this.employeeId = employeeId; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getEducation() { return education; } public void setEducation(String education) { this.education = education; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } }
Step 4
Create hibernate.cfg.xml file
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
- <hibernate-configuration>
- <session-factory>
- <!-- Database connection properties -->
- <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
- <property name="connection.url">jdbc:mysql://localhost/javainsimpleway</property>
- <property name="connection.username">root</property>
- <property name="connection.password">root</property>
- <!-- JDBC connection pool (using the built-in) -->
- <property name="connection.pool_size">100</property>
- <!-- SQL dialect -->
- <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
- <!-- Enable the second-level cache -->
- <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
- <property name="hibernate.cache.use_second_level_cache">true</property>
- <property name="hibernate.cache.region.factory_class">
- org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
- <property name="hibernate.cache.use_query_cache">true</property>
- <!-- Echo all executed SQL to stdout -->
- <property name="show_sql">true</property>
- <!-- Format the generated Sql -->
- <property name="format_sql">true</property>
- <!-- Dont Drop and re-create the database schema on startup,Just update
- it -->
- <property name="hbm2ddl.auto">update</property>
- <mapping class="com.kb.model.Employee" />
- </session-factory>
- </hibernate-configuration>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection properties --> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost/javainsimpleway</property> <property name="connection.username">root</property> <property name="connection.password">root</property> <!-- JDBC connection pool (using the built-in) --> <property name="connection.pool_size">100</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <!-- Enable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property> <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.region.factory_class"> org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <property name="hibernate.cache.use_query_cache">true</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Format the generated Sql --> <property name="format_sql">true</property> <!-- Dont Drop and re-create the database schema on startup,Just update it --> <property name="hbm2ddl.auto">update</property> <mapping class="com.kb.model.Employee" /> </session-factory> </hibernate-configuration>
Step 5
Create hibernate utility class
- package com.kb.util;
- import org.hibernate.SessionFactory;
- import org.hibernate.cfg.Configuration;
- public class HibernateUtil {
- private static final SessionFactory sessionFactory = buildSessionFactory();
- private static SessionFactory buildSessionFactory() {
- try {
- // Create the SessionFactory from hibernate.cfg.xml
- return new Configuration().configure().buildSessionFactory();
- } catch (Throwable ex) {
- // Make sure you log the exception to track it
- System.err.println("SessionFactory creation failed." + ex);
- throw new ExceptionInInitializerError(ex);
- }
- }
- public static SessionFactory getSessionFactory() {
- return sessionFactory;
- }
- public static void shutdown() {
- // Optional but can be used to Close caches and connection pools
- getSessionFactory().close();
- }
- }
package com.kb.util; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class HibernateUtil { private static final SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { // Create the SessionFactory from hibernate.cfg.xml return new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Make sure you log the exception to track it System.err.println("SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } public static void shutdown() { // Optional but can be used to Close caches and connection pools getSessionFactory().close(); } }
Step 6
Populate the data in DB
- package com.kb.db;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import org.hibernate.Transaction;
- import com.kb.model.Employee;
- import com.kb.util.HibernateUtil;
- public class PopulateData {
- public static void main(String[] args) {
- // Get session factory using Hibernate Util class
- SessionFactory sf = HibernateUtil.getSessionFactory();
- // Get session from Sesson factory
- Session session = sf.openSession();
- // Begin transaction
- Transaction t = session.beginTransaction();
- //Create Employee data
- Employee employee1 = new Employee();
- employee1.setFirstName("John");
- employee1.setLastName("KC");
- employee1.setAge(28);
- employee1.setEducation("PG");
- employee1.setSalary(25000);
- Employee employee2 = new Employee();
- employee2.setFirstName("Jacob");
- employee2.setLastName("JC");
- employee2.setAge(30);
- employee2.setEducation("PG");
- employee2.setSalary(30000);
- Employee employee3 = new Employee();
- employee3.setFirstName("Martin");
- employee3.setLastName("A");
- employee3.setAge(24);
- employee3.setEducation("UG");
- employee3.setSalary(20000);
- Employee employee4 = new Employee();
- employee4.setFirstName("Peter");
- employee4.setLastName("M");
- employee4.setAge(25);
- employee4.setEducation("UG");
- employee4.setSalary(22000);
- Employee employee5 = new Employee();
- employee5.setFirstName("Roshan");
- employee5.setLastName("B");
- employee5.setAge(29);
- employee5.setEducation("PG");
- employee5.setSalary(45000);
- session.save(employee1);
- session.save(employee2);
- session.save(employee3);
- session.save(employee4);
- session.save(employee5);
- // Commit the transaction and close the session
- t.commit();
- session.close();
- System.out.println("successfully persisted Employee details");
- }
- }
package com.kb.db; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.kb.model.Employee; import com.kb.util.HibernateUtil; public class PopulateData { public static void main(String[] args) { // Get session factory using Hibernate Util class SessionFactory sf = HibernateUtil.getSessionFactory(); // Get session from Sesson factory Session session = sf.openSession(); // Begin transaction Transaction t = session.beginTransaction(); //Create Employee data Employee employee1 = new Employee(); employee1.setFirstName("John"); employee1.setLastName("KC"); employee1.setAge(28); employee1.setEducation("PG"); employee1.setSalary(25000); Employee employee2 = new Employee(); employee2.setFirstName("Jacob"); employee2.setLastName("JC"); employee2.setAge(30); employee2.setEducation("PG"); employee2.setSalary(30000); Employee employee3 = new Employee(); employee3.setFirstName("Martin"); employee3.setLastName("A"); employee3.setAge(24); employee3.setEducation("UG"); employee3.setSalary(20000); Employee employee4 = new Employee(); employee4.setFirstName("Peter"); employee4.setLastName("M"); employee4.setAge(25); employee4.setEducation("UG"); employee4.setSalary(22000); Employee employee5 = new Employee(); employee5.setFirstName("Roshan"); employee5.setLastName("B"); employee5.setAge(29); employee5.setEducation("PG"); employee5.setSalary(45000); session.save(employee1); session.save(employee2); session.save(employee3); session.save(employee4); session.save(employee5); // Commit the transaction and close the session t.commit(); session.close(); System.out.println("successfully persisted Employee details"); } }
Step 7
Check the output and queries executed
Step 8
Create QueryCacheDemo.java for testing query cache
- package com.kb.db;
- import org.hibernate.Query;
- import org.hibernate.Session;
- import org.hibernate.SessionFactory;
- import com.kb.model.Employee;
- import com.kb.util.HibernateUtil;
- public class QueryCacheDemo {
- @SuppressWarnings("deprecation")
- public static void main(String[] args) {
- // Get session factory using Hibernate Util class
- Employee employee1 = getEmployee(1);
- displayEmployeeDetails(employee1);
- Employee employee2 = getEmployee(1);
- displayEmployeeDetails(employee2);
- Employee employee3 = getEmployee(2);
- displayEmployeeDetails(employee3);
- }
- @SuppressWarnings("deprecation")
- private static Employee getEmployee(int id) {
- SessionFactory sf = HibernateUtil.getSessionFactory();
- // Get session from Session factory
- Session session = sf.openSession();
- Query query = session.createQuery("from Employee e where e.employeeId = :employeeId ");
- query.setParameter("employeeId", id);
- query.setMaxResults(1);
- query.setCacheable(true);
- return query.list() == null ? null : (Employee) query.getResultList().get(0);
- }
- private static void displayEmployeeDetails(Employee employee) {
- System.out.println(
- "ID: " + employee.getEmployeeId() + " Age: " + employee.getAge() + " Salary: " + employee.getSalary());
- }
- }
package com.kb.db; import org.hibernate.Query; import org.hibernate.Session; import org.hibernate.SessionFactory; import com.kb.model.Employee; import com.kb.util.HibernateUtil; public class QueryCacheDemo { @SuppressWarnings("deprecation") public static void main(String[] args) { // Get session factory using Hibernate Util class Employee employee1 = getEmployee(1); displayEmployeeDetails(employee1); Employee employee2 = getEmployee(1); displayEmployeeDetails(employee2); Employee employee3 = getEmployee(2); displayEmployeeDetails(employee3); } @SuppressWarnings("deprecation") private static Employee getEmployee(int id) { SessionFactory sf = HibernateUtil.getSessionFactory(); // Get session from Session factory Session session = sf.openSession(); Query query = session.createQuery("from Employee e where e.employeeId = :employeeId "); query.setParameter("employeeId", id); query.setMaxResults(1); query.setCacheable(true); return query.list() == null ? null : (Employee) query.getResultList().get(0); } private static void displayEmployeeDetails(Employee employee) { System.out.println( "ID: " + employee.getEmployeeId() + " Age: " + employee.getAge() + " Salary: " + employee.getSalary()); } }
In this program, we are calling getEmployee() method twice by passing the same employee id “1” and we can observe in the output that query is executed only once for both the method call.
This is because Query is cached with that parameter.
When we make another call to the method by passing Employee Id as “2”, it’s making DB call as data is not available in cache with Employee id “2”.
Step 9
Check the output and queries executed