×
DocsConsole

DocsConsole

Hibernate Cache Tutorial-Query Level Cache

By | | Updated : 2019-11-13 | Viewed : 374 times

Hibernate-Cache-Tutorial-Query-Level-Cache

Query Level Cache Introduction:

Query Level Cache will be very useful in the case of fetching the entities. Query level Cache will not store the entity, unlike the Second Level Cache. Here it will store only the entity id. When Application query second time the same entity then hibernate will check and provide the same entity from the cache. Here is an example for Query Level Cache.

Code snippet for Query Level Cache
	Session session = HibernateUtil.getSessionFactory().openSession();
	session.beginTransaction();

	List<Product> products = session.createQuery("select p from Product p where p.productId = :productId")
		.setParameter( "productId", 101).setCacheable(true).list();			
	System.out.println(products.get(0).getProductName());
	session.getTransaction().commit();
	session.close();
	
	Session session1 = HibernateUtil.getSessionFactory().openSession();
	session1.beginTransaction();

	List<Product> products1 = session1.createQuery("select p from Product p where p.productId = :productId")
		.setParameter( "productId", 101).setCacheable(true).list();		
	System.out.println(products1.get(0).getProductName());
	session1.getTransaction().commit();
	session1.close();

Without Query Level Cache:

If you observe the above code snippet, we are trying to fetch the same list of entities. Note that Here list contains only one entity. Hibernate will pass the same query to Database twice. It will be processed the query execution twice for fetching entity form the Database. We can avoid this query execution second time in Database by configuring the query level cache.

With Query Level Cache:

For the first time, the query will be processed and fetched the record. After fetching, hibernate will cache the fetched record id. In the second time of query execution, the data will not be fetched from the Database. hibernate will search for record existence. If hibernate finds the record id, then the record will be returned to the application. Here hibernate will not pass the query for execution second time. Hence performance will be improved here. This is the advantage of the second level query.

Query Level Cache Example:

Create Maven project for Hibernate5-QueryLevelCache-Example
Click on File tab 
--> New 
--> Click on Maven Project 
--> Please check on Create Simple Project (Skip architype selection) 
--> Click on Next --> Enter the values com.docsconsole.tutorials.hibernate5 as Group Id, Hibernate5-QueryLevelCache-Example as Artifact Id 
--> Click on Finish

Please create files as given for executing example to test Query Cache.

pom.xml
<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>com.docsconsole.tutorials.hibernate5</groupId>
	<artifactId>Hibernate5-QueryLevelCache-Example</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>Hibernate5-QueryLevelCache-Example</name>
	<description>Hibernate5-QueryLevelCache-Example</description>
	
	<properties>
		<hibernate-core-version>5.4.3.Final</hibernate-core-version>
		<mysql.connector.version>8.0.12</mysql.connector.version>
	</properties>
	<dependencies>


		<!-- Hibernate 5.4.3.Final -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>${hibernate-core-version}</version>
		</dependency>

		<!-- MySql Driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>${mysql.connector.version}</version>
		</dependency>
		
		<dependency>
		    <groupId>org.hibernate</groupId>
		    <artifactId>hibernate-ehcache</artifactId>
		    <version>${hibernate-core-version}</version>
		</dependency>
		
		<dependency>
		    <groupId>net.sf.ehcache</groupId>
		    <artifactId>ehcache</artifactId>
		    <version>2.10.6</version>
		    <type>pom</type>
		</dependency>
	</dependencies>

	<!-- Maven Compiler Plugin -->
	<build>
		<sourceDirectory>src/main/java</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5.1</version>
				<configuration>
					<source>11</source>
					<target>11</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

	<session-factory>
		<!-- Database connection settings -->
		<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
		<property name="connection.url">jdbc:mysql://localhost/docsconsole_tutorial</property>
		<property name="connection.username">root</property>
		<property name="connection.password">MyNewPass</property>
		
		<!-- JDBC connection pool (use the built-in) -->
		<property name="connection.pool_size">1</property>
		
		<!-- SQL dialect -->
		<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
		
		<!-- Enable Hibernate's automatic session context management -->
		<property name="current_session_context_class">thread</property>
		
		<!-- Disable the second-level cache -->
		<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
		
		<!-- Echo all executed SQL to stdout -->
		<property name="show_sql">true</property>
		
		<!-- Drop and re-create the database schema on startup -->
		<property name="hbm2ddl.auto">update</property>
		
		<!-- set up for Query level cache -->
		

		<property name="hibernate.cache.use_second_level_cache">true</property>
		<property name="hibernate.cache.use_query_cache">true</property>
		<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
		<property name="net.sf.ehcache.configurationResourceName">/product-cache-config.xml</property>
		
		<!-- Mappings with hbm xml files -->
		<mapping resource="product.hbm.xml" />
		
	</session-factory>
	
</hibernate-configuration>

Here we simply configure the database settings, Second and Query level settings as well. Here settings for Second level cache is also needed. The reason behind this is that, after the first fetch, record’s id will be cached into Second Level Cache only. So, we can easily fetch the same record even with a new session also.

Code Snippet for Query level settings in hibernate.cfg.xml
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="net.sf.ehcache.configurationResourceName">/product-cache-config.xml</property>

hibernate.cache.use_second_level_cache: will be used for enabling the second level Cache.

hibernate.cache.use_query_cache: will enable the Query level Cache.

hibernate.cache.region.factory_class: will be used for integrating the hibernate and cache provider. Region factory class will reside in between hibernate and Cache provider. it will integrate the hibernate and Cache Provider for providing the Cached results.

net.sf.ehcache.configurationResourceName: will be used for configuring a file location. This file contains the instruction for caching mechanism.

product.hbm.xml
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
	<class name="com.docsconsole.tutorials.hibernate5.entity.Product" table="product">

		<meta attribute="class-description">
			This class contains the product details.
		</meta>
		
 		<cache usage="read-write"/>
		<id name="productId" type="int" column="product_id">
			<generator class="native" />
		</id>

		<property name="productName" column="product_name" type="string" />
		<property name="productVendor" column="product_vendor" type="string" />

	</class>

</hibernate-mapping>
product-cache-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
	monitoring="autodetect" dynamicConfig="true">

	<diskStore path="java.io.tmpdir/ehcache" />

	<defaultCache maxEntriesLocalHeap="10000" eternal="false"
		timeToIdleSeconds="120" timeToLiveSeconds="120" diskSpoolBufferSizeMB="30"
		maxEntriesLocalDisk="10000000" diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU" statistics="true">
		<persistence strategy="localTempSwap" />
	</defaultCache>

	<cache name="employee" maxEntriesLocalHeap="10000" eternal="false"
		timeToIdleSeconds="5" timeToLiveSeconds="10">
		<persistence strategy="localTempSwap" />
	</cache>

	<cache name="org.hibernate.cache.internal.StandardQueryCache"
		maxEntriesLocalHeap="5" eternal="false" timeToLiveSeconds="120">
		<persistence strategy="localTempSwap" />
	</cache>

	<cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
		maxEntriesLocalHeap="5000" eternal="true">
		<persistence strategy="localTempSwap" />
	</cache>
</ehcache>

Please make a note the tag, is required for Query Level Cache.

HibernateUtil.java
package com.docsconsole.tutorials.hibernate5.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) {
			System.err.println("Initial SessionFactory creation failed." + ex);
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
}
Product .java
package com.docsconsole.tutorials.hibernate5.entity;

public class Product {

	private Integer productId;
	private String productName;
	private String productVendor;

	public Integer getProductId() {
		return productId;
	}

	public void setProductId(Integer productId) {
		this.productId = productId;
	}

	public String getProductName() {
		return productName;
	}

	public void setProductName(String productName) {
		this.productName = productName;
	}

	public String getProductVendor() {
		return productVendor;
	}

	public void setProductVendor(String productVendor) {
		this.productVendor = productVendor;
	}

}
MainClient.java
package com.docsconsole.tutorials.hibernate5;

import java.util.List;

import org.hibernate.Session;

import com.docsconsole.tutorials.hibernate5.entity.Product;
import com.docsconsole.tutorials.hibernate5.util.HibernateUtil;

public class MainClient {

	public static void main(String[] args) {

		try {
			Session session = HibernateUtil.getSessionFactory().openSession();
			session.beginTransaction();

			List<Product> products = session.createQuery("select p from Product p where p.productId = :productId")
				.setParameter( "productId", 101).setCacheable(true).list();			
			System.out.println(products.get(0).getProductName());
			session.getTransaction().commit();
			session.close();
			
			Session session1 = HibernateUtil.getSessionFactory().openSession();
			session1.beginTransaction();

			List<Product> products1 = session1.createQuery("select p from Product p where p.productId = :productId")
				.setParameter( "productId", 101).setCacheable(true).list();		
			System.out.println(products1.get(0).getProductName());
			session1.getTransaction().commit();
			session1.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

Please execute the above MainClient.java and observe the no of queries are getting fired in the database. The result will be as given below.

Leave A Reply