Hibernate 缓存–一级缓存
欢迎使用Hibernate Caching –一级缓存示例教程。
最近,我们研究了Hibernate体系结构,hibernate映射以及如何使用HQL以面向对象的方式触发SQL查询。
今天,我们将研究Hibernate的重要方面之一-Hibernate Cache。
Hibernate 缓存
如果正确使用Hibernate Cache,在获得快速应用程序性能方面将非常有用。
缓存背后的想法是减少数据库查询的数量,从而减少应用程序的吞吐时间。
Hibernate带有不同类型的缓存:
一级缓存:Hibernate一级缓存与Session对象相关联。
默认情况下,Hibernate一级缓存处于启用状态,无法禁用它。
但是hibernate提供了一些方法,通过这些方法我们可以从缓存中删除选定的对象或者完全清除缓存。
会话中缓存的任何对象对其他会话都不可见,并且当会话关闭时,所有缓存的对象也将丢失。二级缓存:默认情况下,Hibernate 二级缓存是禁用的,但我们可以通过配置启用它。
目前,EHCache和Infinispan为Hibernate Second level缓存提供了实现,我们可以使用它们。
我们将在下一个教程中研究Hibernate 缓存。查询缓存:Hibernate也可以缓存查询结果集。
Hibernate Query Cache不会在缓存中缓存实际实体的状态;它仅缓存标识符值和值类型的结果。
因此,应始终将其与二级缓存结合使用。
Hibernate 缓存–一级缓存示例
对于我的Hibernate 一级缓存示例程序,我使用的配置与HQL示例中的配置相同,您可以签出并配置表,并用伪数据填充表。
首先让我们看一下程序,将其输出,然后我们将介绍与Hibernate First Level Cache相关的一些重要信息。
HibernateCacheExample.java
package com.theitroad.hibernate.main; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import com.theitroad.hibernate.model.Employee; import com.theitroad.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(); //Get employee with id=1 Employee emp = (Employee) session.load(Employee.class, new Long(1)); printData(emp,1); //waiting for sometime to change the data in backend Thread.sleep(10000); //Fetch same data again, check logs that no query fired Employee emp1 = (Employee) session.load(Employee.class, new Long(1)); printData(emp1,2); //Create new session Session newSession = sessionFactory.openSession(); //Get employee with id=1, notice the logs for query Employee emp2 = (Employee) newSession.load(Employee.class, new Long(1)); printData(emp2,3); //START: evict example to remove specific object from hibernate first level cache //Get employee with id=2, first time hence query in logs Employee emp3 = (Employee) session.load(Employee.class, new Long(2)); printData(emp3,4); //evict the employee object with id=1 session.evict(emp); System.out.println("Session Contains Employee with id=1?"+session.contains(emp)); //since object is removed from first level cache, you will see query in logs Employee emp4 = (Employee) session.load(Employee.class, new Long(1)); printData(emp4,5); //this object is still present, so you won't see query in logs Employee emp5 = (Employee) session.load(Employee.class, new Long(2)); printData(emp5,6); //END: evict example //START: clear example to remove everything from first level cache 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=hyman, Zipcode=95129 2:: Name=hyman, 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=hymanK, 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=hyman, 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=hyman, 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 First Level缓存是启用的,不需要任何配置。
Hibernate 一级缓存是特定于会话的,这就是为什么当我们在同一会话中获取相同的数据时,不会触发查询,而在其他会话中,会触发查询来加载数据。
Hibernate一级缓存可能具有旧值,如上所示,我已使程序进入睡眠状态10秒钟,在那段时间内,我更新了数据库中的值(名称从hyman改为hymanK),但未其中反映出来。
同一会话。
但是在其他会话中,我们获得了更新的值。我们可以使用session evict()方法从Hibernate 的一级缓存中删除单个对象。
我们可以使用session
clear()
方法清除缓存,即从缓存中删除所有对象。我们可以使用session
contains()
方法来检查Hibernate 缓存中是否存在对象,如果在缓存中找到该对象,则返回true,否则返回false。由于Hibernate 将所有对象缓存到会话一级缓存中,因此在运行批量查询或者批处理更新时,必须按一定的时间间隔清除缓存以避免内存问题。