欢迎来到Hibernate缓存-第一级缓存示例教程。最近我们研究了Hibernate架构,hibernate映射以及如何使用HQL以面向对象的方式执行SQL查询。今天我们将研究Hibernate的一个重要方面-Hibernate缓存。
Hibernate缓存
如果使用正确,Hibernate缓存可以在提高应用程序性能方面非常有用。缓存背后的思想是减少数据库查询的数量,从而减少应用程序的吞吐时间。Hibernate提供了不同类型的缓存:
- 一级缓存: Hibernate一级缓存与Session对象关联。Hibernate一级缓存默认启用,且无法禁用。然而,Hibernate提供了方法,通过这些方法我们可以从缓存中删除选定的对象或完全清除缓存。在会话中缓存的任何对象对其他会话都不可见,当会话关闭时,所有缓存的对象也将丢失。
- 二级缓存: Hibernate二级缓存默认禁用,但我们可以通过配置启用它。目前,EHCache和Infinispan提供了Hibernate二级缓存的实现,我们可以使用它们。我们将在下一个Hibernate缓存教程中详细介绍这一点。
- 查询缓存: Hibernate还可以缓存查询的结果集。Hibernate查询缓存不会缓存缓存中实体的实际状态;它只缓存标识符值和值类型的结果。因此,它应始终与二级缓存一起使用。
Hibernate缓存 – 一级缓存示例
对于我的Hibernate一级缓存示例程序,我正在使用与HQL示例相同的配置,您可以查看并配置表格,并使用虚拟数据填充它。让我们首先查看程序、其输出,然后我们将浏览与Hibernate一级缓存相关的一些重要点。HibernateCacheExample.java
package com.journaldev.hibernate.main;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.journaldev.hibernate.model.Employee;
import com.journaldev.hibernate.util.HibernateUtil;
public class HibernateCacheExample {
public static void main(String[] args) throws InterruptedException {
SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
//获取id为1的员工
Employee emp = (Employee) session.load(Employee.class, new Long(1));
printData(emp,1);
//等待一段时间以更改后端的数据
Thread.sleep(10000);
//再次获取相同的数据,检查日志,确认未发出查询
Employee emp1 = (Employee) session.load(Employee.class, new Long(1));
printData(emp1,2);
//创建新会话
Session newSession = sessionFactory.openSession();
//获取id为1的员工, notice the logs for query
Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1));
printData(emp2,3);
//START:驱逐示例以从Hibernate一级缓存中移除特定对象
//获取id为2的员工,首次因此日志中有查询
Employee emp3 = (Employee) session.load(Employee.class, new Long(2));
printData(emp3,4);
//驱逐id为1的员工对象
session.evict(emp);
System.out.println("Session Contains Employee with id=1?"+session.contains(emp));
//由于对象已从一级缓存中移除,您将在日志中看到查询
Employee emp4 = (Employee) session.load(Employee.class, new Long(1));
printData(emp4,5);
//此对象仍然存在,因此您不会在日志中看到查询
Employee emp5 = (Employee) session.load(Employee.class, new Long(2));
printData(emp5,6);
//END: 驱逐示例
//START: 清除示例以从一级缓存中删除所有内容
session.clear();
Employee emp6 = (Employee) session.load(Employee.class, new Long(1));
printData(emp6,7);
Employee emp7 = (Employee) session.load(Employee.class, new Long(2));
printData(emp7,8);
System.out.println("Session Contains Employee with id=2?"+session.contains(emp7));
tx.commit();
sessionFactory.close();
}
private static void printData(Employee emp, int count) {
System.out.println(count+":: Name="+emp.getName()+", Zipcode="+emp.getAddress().getZipcode());
}
}
当我们运行上面的示例时,输出包含大量与Hibernate相关的信息。但我们主要关注我们代码特定的输出和Hibernate加载数据时发出的查询。输出片段如下。
Hibernate Configuration loaded
Hibernate serviceRegistry created
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
2:: Name=Pankaj, Zipcode=95129
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=?
3:: Name=PankajK, Zipcode=95129
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=David, Zipcode=95051
Session Contains Employee with id=1?false
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=?
5:: Name=Pankaj, Zipcode=95129
6:: Name=David, Zipcode=95051
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=?
7:: Name=Pankaj, Zipcode=95129
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=?
8:: Name=David, Zipcode=95051
Session Contains Employee with id=2?true
在Hibernate中一级缓存的重要要点
从上述程序中可以得出关于Hibernate一级缓存的重要要点:
- Hibernate一级缓存默认启用,无需任何配置。
- Hibernate一级缓存是与会话相关联的,因此当在相同会话中获取相同数据时,不会触发查询,而在其他会话中会触发查询以加载数据。
- Hibernate一级缓存可以包含旧值,正如上面所示,我将程序休眠了10秒,在此期间我更新了数据库中的值(将名称从Pankaj更改为PankajK),但在相同会话中没有反映出来。但在其他会话中,我们得到了更新后的值。
- 我们可以使用会话的
evict()
方法从Hibernate一级缓存中移除单个对象。 - 我们可以使用会话的
clear()
方法清除缓存,即从缓存中删除所有对象。 - 我们可以使用会话的
contains()
方法检查对象是否存在于Hibernate缓存中,如果在缓存中找到对象,则返回true,否则返回false。 - 由于Hibernate将所有对象缓存到会话的一级缓存中,在运行批量查询或批量更新时,有必要定期清除缓存以避免内存问题。
这就是关于 Hibernate 缓存和一级缓存示例的全部内容,在未来的文章中,我们将深入了解 Hibernate 第二级缓存 – EHCache的实现。
Source:
https://www.digitalocean.com/community/tutorials/hibernate-caching-first-level-cache