Welcome to the Hibernate Second Level Cache Example Tutorial. Today we will look into Hibernate EHCache that is the most popular Hibernate Second Level Cache provider.
欢迎使用Hibernate二级缓存示例教程。 今天,我们将研究最流行的Hibernate二级缓存提供程序Hibernate EHCache。
Hibernate二级缓存 (Hibernate Second Level Cache)
One of the major benefit of using Hibernate in large application is it’s support for cache, hence reducing database queries and better performance. In earlier example, we looked into the Hibernate First Level Cache and today we will look into Hibernate Second Level Cache using Hibernate EHCache implementation.
在大型应用程序中使用Hibernate的主要好处之一是它对缓存的支持,从而减少了数据库查询并提高了性能。 在前面的示例中,我们研究了Hibernate一级缓存 ,今天我们将使用Hibernate EHCache实现研究Hibernate二级缓存。
Hibernate Second Level cache providers include EHCache and Infinispan, but EHCache is more popular and we will use it for our example project. However before we move to our project, we should know different strategies for caching an object.
Hibernate Second Level缓存提供程序包括EHCache和Infinispan,但是EHCache更为流行,我们将在示例项目中使用它。 但是,在进行项目之前,我们应该了解用于缓存对象的不同策略。
- Read Only: This caching strategy should be used for persistent objects that will always read but never updated. It’s good for reading and caching application configuration and other static data that are never updated. This is the simplest strategy with best performance because there is no overload to check if the object is updated in database or not. 只读 :此缓存策略应用于将始终读取但永不更新的持久对象。 这对于读取和缓存应用程序配置以及永不更新的其他静态数据非常有用。 这是具有最佳性能的最简单策略,因为没有重载可以检查对象是否在数据库中更新。
- Read Write: It’s good for persistent objects that can be updated by the hibernate application. However if the data is updated either through backend or other applications, then there is no way hibernate will know about it and data might be stale. So while using this strategy, make sure you are using Hibernate API for updating the data. 读写 :这对于可以由Hibernate应用程序更新的持久对象很有用。 但是,如果通过后端或其他应用程序更新了数据,则Hibernate将无法知道它,并且数据可能会过时。 因此,在使用此策略时,请确保使用Hibernate API来更新数据。
- Nonrestricted Read Write: If the application only occasionally needs to update data and strict transaction isolation is not required, a nonstrict-read-write cache might be appropriate. 非限制性读写 :如果应用程序仅偶尔需要更新数据,并且不需要严格的事务隔离,则非限制性读写缓存可能是合适的。
- Transactional: The transactional cache strategy provides support for fully transactional cache providers such as JBoss TreeCache. Such a cache can only be used in a JTA environment and you must specify hibernate.transaction.manager_lookup_class. 事务性 :事务性缓存策略为完全事务性缓存提供程序(例如JBoss TreeCache)提供支持。 这样的缓存只能在JTA环境中使用,并且必须指定hibernate.transaction.manager_lookup_class。
HibernateEHCache (Hibernate EHCache)
Since EHCache supports all the above cache strategies, it’s the best choice when you are looking for second level cache in hibernate. I would not go into much detail about EHCache, my main focus will be to get it working for hibernate application.
由于EHCache支持上述所有缓存策略,因此在Hibernate状态下寻找二级缓存时,它是最佳选择。 我不会详细介绍EHCache,我的主要重点是使它适用于Hibernate应用程序。
Create a maven project in the Eclipse or your favorite IDE, final implementation will look like below image.
在Eclipse或您喜欢的IDE中创建一个maven项目,最终实现如下图所示。
Let’s look into each component of the application one by one.
让我们逐一研究应用程序的每个组件。
Hibernate EHCache Maven依赖关系 (Hibernate EHCache Maven Dependencies)
For hibernate second level cache, we would need to add ehcache-core and hibernate-ehcache dependencies in our application. EHCache uses slf4j for logging, so I have also added slf4j-simple for logging purposes. I am using the latest versions of all these APIs, there is a slight chance that hibernate-ehcache APIs are not compatible with the ehcache-core API, in that case you need to check the pom.xml of hibernate-ehcache to find out the correct version to use. Our final pom.xml looks like below.
对于Hibernate二级缓存,我们需要在应用程序中添加ehcache-core和hibernate-ehcache依赖项。 EHCache使用slf4j进行日志记录,因此我还添加了slf4j-simple来进行日志记录。 我正在使用所有这些API的最新版本,因此hibernate-ehcache API与ehcache-core API不兼容的可能性很小,在这种情况下,您需要检查hibernate-ehcache的pom.xml来找出使用的正确版本。 我们最终的pom.xml如下所示。
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.journaldev.hibernate</groupId>
<artifactId>HibernateEHCacheExample</artifactId>
<version>0.0.1-SNAPSHOT</version>
<description>Hibernate Secondary Level Cache Example using EHCache implementation</description>
<dependencies>
<!-- Hibernate Core API -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.3.5.Final</version>
</dependency>
<!-- MySQL Driver -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.5</version>
</dependency>
<!-- EHCache Core APIs -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.6.9</version>
</dependency>
<!-- Hibernate EHCache API -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.3.5.Final</version>
</dependency>
<!-- EHCache uses slf4j for logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.5</version>
</dependency>
</dependencies>
</project>
Hibernate二级缓存–HibernateEHCache配置 (Hibernate Second Level Cache – Hibernate EHCache Configuration)
Hibernate Second level cache is disabled by default, so we would need to enable it and add some configurations to get it working. Our hibernate.cfg.xml file looks like below.
Hibernate二级缓存默认情况下处于禁用状态,因此我们需要启用它并添加一些配置以使其正常工作。 我们的hibernate.cfg.xml文件如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration SYSTEM "classpath://org/hibernate/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">pankaj123</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
<property name="hibernate.connection.username">pankaj</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- For singleton factory -->
<!-- <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
-->
<!-- enable second level cache and query cache -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="net.sf.ehcache.configurationResourceName">/myehcache.xml</property>
<mapping class="com.journaldev.hibernate.model.Employee" />
<mapping class="com.journaldev.hibernate.model.Address" />
</session-factory>
</hibernate-configuration>
Some important points about hibernate second level cache configurations are:
有关Hibernate二级缓存配置的一些重要点是:
- hibernate.cache.region.factory_class is used to define the Factory class for Second level caching, I am using
org.hibernate.cache.ehcache.EhCacheRegionFactory
for this. If you want the factory class to be singleton, you should useorg.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
class.If you are using Hibernate 3, corresponding classes will be
hibernate.cache.region.factory_class用于定义二级缓存的Factory类,为此我正在使用net.sf.ehcache.hibernate.EhCacheRegionFactory
andnet.sf.ehcache.hibernate.SingletonEhCacheRegionFactory
.org.hibernate.cache.ehcache.EhCacheRegionFactory
。 如果希望工厂类为单例,则应使用org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
类。如果您使用的是Hibernate 3,则对应的类将是
net.sf.ehcache.hibernate.EhCacheRegionFactory
和net.sf.ehcache.hibernate.SingletonEhCacheRegionFactory
。 - hibernate.cache.use_second_level_cache is used to enable the second level cache. hibernate.cache.use_second_level_cache用于启用二级缓存。
- hibernate.cache.use_query_cache is used to enable the query cache, without it HQL queries results will not be cached. hibernate.cache.use_query_cache用于启用查询缓存,没有它,HQL查询结果将不会被缓存。
- net.sf.ehcache.configurationResourceName is used to define the EHCache configuration file location, it’s an optional parameter and if it’s not present EHCache will try to locate ehcache.xml file in the application classpath. net.sf.ehcache.configurationResourceName用于定义EHCache配置文件的位置,它是一个可选参数,如果不存在,则EHCache会尝试在应用程序类路径中找到ehcache.xml文件。
HibernateEHCache配置文件 (Hibernate EHCache Configuration File)
Our EHCache configuration file myehcache.xml looks like below.
我们的EHCache配置文件myehcache.xml如下所示。
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="https://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>
Hibernate EHCache provides a lot of options, I won’t go into much detail but some of the important configurations above are:
Hibernate EHCache提供了很多选项,我将不做太多详细介绍,但是上面的一些重要配置是:
- diskStore: EHCache stores data into memory but when it starts overflowing, it start writing data into file system. We use this property to define the location where EHCache will write the overflown data. diskStore :EHCache将数据存储到内存中,但是当它开始溢出时,它将开始将数据写入文件系统。 我们使用此属性来定义EHCache将写入溢出数据的位置。
- defaultCache: It’s a mandatory configuration, it is used when an Object need to be cached and there are no caching regions defined for that. defaultCache :这是强制性配置,用于需要缓存Object且没有为此定义缓存区域时使用。
- cache name=”employee”: We use cache element to define the region and it’s configurations. We can define multiple regions and their properties, while defining model beans cache properties, we can also define region with caching strategies. The cache properties are easy to understand and clear with the name. cache name =“ employee” :我们使用cache元素定义区域及其配置。 我们可以定义多个区域及其属性,在定义模型bean缓存属性的同时,还可以使用缓存策略定义区域。 高速缓存属性易于理解,并可以使用名称清除。
- Cache regions
org.hibernate.cache.internal.StandardQueryCache
andorg.hibernate.cache.spi.UpdateTimestampsCache
are defined because EHCache was giving warning to that. 定义了缓存区域org.hibernate.cache.internal.StandardQueryCache
和org.hibernate.cache.spi.UpdateTimestampsCache
,因为EHCache对此发出了警告。
Hibernate二级缓存–模型Bean缓存策略 (Hibernate Second Level Cache – Model Bean Caching Strategy)
We use org.hibernate.annotations.Cache
annotation to provide the caching configuration. org.hibernate.annotations.CacheConcurrencyStrategy
is used to define the caching strategy and we can also define the cache region to use for the model beans.
我们使用org.hibernate.annotations.Cache
注释来提供缓存配置。 org.hibernate.annotations.CacheConcurrencyStrategy
用于定义缓存策略,我们还可以定义用于模型bean的缓存区域。
package com.journaldev.hibernate.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
@Entity
@Table(name = "ADDRESS")
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="employee")
public class Address {
@Id
@Column(name = "emp_id", unique = true, nullable = false)
@GeneratedValue(generator = "gen")
@GenericGenerator(name = "gen", strategy = "foreign",
parameters = { @Parameter(name = "property", value = "employee") })
private long id;
@Column(name = "address_line1")
private String addressLine1;
@Column(name = "zipcode")
private String zipcode;
@Column(name = "city")
private String city;
@OneToOne
@PrimaryKeyJoinColumn
private Employee employee;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
package com.journaldev.hibernate.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.hibernate.annotations.Cascade;
@Entity
@Table(name = "EMPLOYEE")
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="employee")
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "emp_id")
private long id;
@Column(name = "emp_name")
private String name;
@Column(name = "emp_salary")
private double salary;
@OneToOne(mappedBy = "employee")
@Cascade(value = org.hibernate.annotations.CascadeType.ALL)
private Address address;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
Note that I am using the same database setup as in HQL example, you might want to check that to create the database tables and load sample data.
请注意,我使用的数据库设置与HQL示例中的相同,您可能需要检查以创建数据库表并加载示例数据。
Hibernate SessionFactory实用程序类 (Hibernate SessionFactory Utility Class)
We have a simple utility class to configure hibernate and get the SessionFactory
singleton instance.
我们有一个简单的实用程序类,用于配置Hibernate并获取SessionFactory
单例实例。
package com.journaldev.hibernate.util;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
public class HibernateUtil {
private static SessionFactory sessionFactory;
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
System.out.println("Hibernate Configuration loaded");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
System.out.println("Hibernate serviceRegistry created");
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
ex.printStackTrace();
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
if(sessionFactory == null) sessionFactory = buildSessionFactory();
return sessionFactory;
}
}
Our hibernate second level cache project using Hibernate EHCache is ready, let’s write a simple program to test it.
我们已经准备好使用Hibernate EHCache的hibernate二级缓存项目,让我们编写一个简单的程序对其进行测试。
HibernateEHCache测试程序 (Hibernate EHCache Test Program)
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.stat.Statistics;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateEHCacheMain {
public static void main(String[] args) {
System.out.println("Temp Dir:"+System.getProperty("java.io.tmpdir"));
//Initialize Sessions
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Statistics stats = sessionFactory.getStatistics();
System.out.println("Stats enabled="+stats.isStatisticsEnabled());
stats.setStatisticsEnabled(true);
System.out.println("Stats enabled="+stats.isStatisticsEnabled());
Session session = sessionFactory.openSession();
Session otherSession = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();
Transaction otherTransaction = otherSession.beginTransaction();
printStats(stats, 0);
Employee emp = (Employee) session.load(Employee.class, 1L);
printData(emp, stats, 1);
emp = (Employee) session.load(Employee.class, 1L);
printData(emp, stats, 2);
//clear first level cache, so that second level cache is used
session.evict(emp);
emp = (Employee) session.load(Employee.class, 1L);
printData(emp, stats, 3);
emp = (Employee) session.load(Employee.class, 3L);
printData(emp, stats, 4);
emp = (Employee) otherSession.load(Employee.class, 1L);
printData(emp, stats, 5);
//Release resources
transaction.commit();
otherTransaction.commit();
sessionFactory.close();
}
private static void printStats(Statistics stats, int i) {
System.out.println("***** " + i + " *****");
System.out.println("Fetch Count="
+ stats.getEntityFetchCount());
System.out.println("Second Level Hit Count="
+ stats.getSecondLevelCacheHitCount());
System.out
.println("Second Level Miss Count="
+ stats
.getSecondLevelCacheMissCount());
System.out.println("Second Level Put Count="
+ stats.getSecondLevelCachePutCount());
}
private static void printData(Employee emp, Statistics stats, int count) {
System.out.println(count+":: Name="+emp.getName()+", Zipcode="+emp.getAddress().getZipcode());
printStats(stats, count);
}
}
org.hibernate.stat.Statistics
provides the statistics of Hibernate SessionFactory, we are using it to print the fetch count and second level cache hit, miss and put count. Statistics are disabled by default for better performance, that’s why I am enabling it at the start of the program.
org.hibernate.stat.Statistics
提供了Hibernate SessionFactory的统计信息,我们正在使用它来打印访存计数和二级缓存命中,未命中和放置计数。 默认情况下,统计信息处于禁用状态以提高性能,这就是为什么我在程序开始时启用统计信息的原因。
When we run above program, we get a lot of output generated by Hibernate and EHCache APIs, but we are interested in the data that we are printing. A sample run prints following output.
当我们运行上述程序时,我们会从Hibernate和EHCache API生成许多输出,但是我们对正在打印的数据感兴趣。 样本运行将打印以下输出。
Temp Dir:/var/folders/h4/q73jjy0902g51wkw0w69c0600000gn/T/
Hibernate Configuration loaded
Hibernate serviceRegistry created
Stats enabled=false
Stats enabled=true
***** 0 *****
Fetch Count=0
Second Level Hit Count=0
Second Level Miss Count=0
Second Level Put Count=0
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
1:: Name=Pankaj, Zipcode=95129
***** 1 *****
Fetch Count=1
Second Level Hit Count=0
Second Level Miss Count=1
Second Level Put Count=2
2:: Name=Pankaj, Zipcode=95129
***** 2 *****
Fetch Count=1
Second Level Hit Count=0
Second Level Miss Count=1
Second Level Put Count=2
3:: Name=Pankaj, Zipcode=95129
***** 3 *****
Fetch Count=1
Second Level Hit Count=2
Second Level Miss Count=1
Second Level Put Count=2
Hibernate: select employee0_.emp_id as emp_id1_1_0_, employee0_.emp_name as emp_name2_1_0_, employee0_.emp_salary as emp_sala3_1_0_, address1_.emp_id as emp_id1_0_1_, address1_.address_line1 as address_2_0_1_, address1_.city as city3_0_1_, address1_.zipcode as zipcode4_0_1_ from EMPLOYEE employee0_ left outer join ADDRESS address1_ on employee0_.emp_id=address1_.emp_id where employee0_.emp_id=?
4:: Name=Lisa, Zipcode=560100
***** 4 *****
Fetch Count=2
Second Level Hit Count=2
Second Level Miss Count=2
Second Level Put Count=4
5:: Name=Pankaj, Zipcode=95129
***** 5 *****
Fetch Count=2
Second Level Hit Count=4
Second Level Miss Count=2
Second Level Put Count=4
As you can see from output, statistics were disabled at first but we enabled it for checking our hibernate second level cache.
从输出中可以看到,首先禁用了统计信息,但是我们启用了它来检查我们的Hibernate二级缓存。
Step by step explanation of the output is as follows:
输出的逐步说明如下:
- Before we load any data in our application, all the stats are 0 as expected. 在将任何数据加载到应用程序中之前,所有统计信息均为预期的0。
- When we are loading the Employee with id=1 for the first time, it’s first searched into first level cache and then second level cache. If not found in cache, database query is executed and hence fetch count becomes 1. Once the object is loaded, it’s saved into first level cache and second level cache both. So secondary level hit count remains 0 and miss count becomes 1. Notice that put count is 2, that is because Employee object consists of Address too, so both the objects are saved into second level cache and count is increased to 2. 当我们第一次加载id = 1的Employee时,首先将其搜索到一级缓存中,然后再搜索到二级缓存中。 如果未在高速缓存中找到,则执行数据库查询,因此访存计数变为1。一旦加载了对象,则将其保存到第一级缓存和第二级缓存中。 因此,二级命中计数保持为0,未命中计数变为1。请注意,推入计数为2,这是因为Employee对象也由Address组成,因此两个对象都保存到了二级缓存中,并且计数增加到了2。
- Next, we are again loading the employee with id=1, this time it’s present in the first level cache. So you don’t see any database query and all other secondary level cache stats also remains same. 接下来,我们再次加载id = 1的员工,这一次它存在于一级缓存中。 因此,您看不到任何数据库查询,并且所有其他二级缓存统计信息也保持不变。
- Next we are using
evict()
method to remove the employee object from the first level cache, now when we are trying to load it, hibernate finds it in the second level cache. That’s why no database query is fired and fetch count remains 1. Notice that hit count goes from 0 to 2 because both Employee and Address objects are read from the second level cache. Second level miss and put count remains at the earlier value. 接下来,我们使用evict()
方法从第一级缓存中删除employee对象,现在当我们尝试加载它时,hibernate在第二级缓存中找到它。 这就是为什么不会触发任何数据库查询并且提取计数保持为1的原因。请注意,命中计数从0变为2,因为Employee和Address对象都是从第二级缓存中读取的。 第二级未命中数和看跌数仍保持较早的值。 - Next we are loading an employee with id=3, database query is executed and fetch count increases to 2, miss count increases from 1 to 2 and put count increases from 2 to 4. 接下来,我们加载一个id = 3的员工,执行数据库查询,并且提取计数增加到2,未命中计数从1增加到2,放置计数从2增加到4。
- Next we are trying to load employee with id=1 in another session, Since hibernate second level cache is shared across sessions, it’s found in the second level cache and no database query is executed. Fetch count, miss count and put count remains same whereas hit count increases from 2 to 4. 接下来,我们尝试在另一个会话中加载id = 1的雇员,由于Hibernate二级缓存在各个会话之间共享,因此在二级缓存中可以找到它,并且不执行数据库查询。 提取计数,未命中计数和看跌计数保持不变,而命中计数从2增加到4。
So it’s clear that our Hibernate second level cache; Hibernate EHCache; is working fine. Hibernate statistics are helpful in finding the bottleneck in the system and optimize it to reduce the fetch count and load more data from the cache.
因此很明显,我们的Hibernate二级缓存; HibernateEHCache; 工作正常。 Hibernate统计信息有助于发现系统中的瓶颈并对其进行优化,以减少获取次数并从缓存中加载更多数据。
That’s all for the Hibernate EHCache example, I hope it will help you in configuring EHCache in your hibernate applications and getting better performance through hibernate second level cache. You can download the sample project from below link and use other stats data to learn more.
这就是Hibernate EHCache示例的全部内容,希望它能帮助您在hibernate应用程序中配置EHCache并通过hibernate二级缓存获得更好的性能。 您可以从下面的链接下载示例项目,并使用其他统计数据来了解更多信息。
翻译自: https://www.journaldev.com/2980/hibernate-ehcache-hibernate-second-level-cache