Hibernate缓存 – 一级缓存

欢迎来到Hibernate缓存 – 一级缓存示例教程。最近我们了解了Hibernate的架构、Hibernate映射以及如何以面向对象的方式使用HQL执行SQL查询。今天我们将重点介绍Hibernate的一个重要方面 – Hibernate缓存。

Hibernate 缓存

如果正确使用,Hibernate缓存可以非常有用,可以实现快速的应用程序性能。缓存的理念是减少数据库查询次数,从而减少应用程序的吞吐时间。Hibernate提供了不同类型的缓存。

    1. 一级缓存:Hibernate一级缓存与Session对象相关联。Hibernate一级缓存默认启用,无法禁用。但是Hibernate提供了通过方法从缓存中删除选定的对象或完全清除缓存的方式。在会话中缓存的任何对象对其他会话都不可见,并且当会话关闭时,所有缓存的对象也将丢失。

 

    1. 二级缓存:Hibernate二级缓存默认禁用,但可以通过配置启用。目前,EHCache和Infinispan为Hibernate二级缓存提供实现,我们可以使用它们。在下一个Hibernate缓存教程中,我们将深入介绍此内容。

 

    查询缓存:Hibernate还可以缓存查询的结果集。Hibernate查询缓存不会缓存实际实体的状态,而只会缓存标识符值和值类型的结果。因此,它应始终与二级缓存结合使用。

一级缓存示例 – Hibernate缓存

我的Hibernate一级缓存示例程序使用与HQL示例相同的配置,您可以查看并配置表格,并使用虚拟数据填充它。让我们先看一下程序的输出,然后我们将介绍一些与Hibernate一级缓存相关的重要点。HibernateCacheExample.java

package com.Olivia.hibernate.main;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.Olivia.hibernate.model.Employee;
import com.Olivia.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=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中一级缓存的重要要点是:

    1. 默认情况下,Hibernate启用了一级缓存,无需进行任何配置。

 

    1. Hibernate一级缓存是与会话相关的,这就是为什么在同一个会话中获取相同的数据时,不会发出查询,而在其他会话中会发出查询以加载数据。

 

    1. Hibernate一级缓存可能存在旧值,正如你可以看到上面的例子中,我将程序休眠了10秒,在此期间我更新了数据库中的值(将名字从Pankaj改为PankajK),但是在同一个会话中没有反映出来。但是在其他会话中,我们得到了更新后的值。

 

    1. 我们可以使用session.evict()方法从Hibernate一级缓存中删除单个对象。

 

    1. 我们可以使用session.clear()方法清除缓存,即删除缓存中的所有对象。

 

    1. 我们可以使用session.contains()方法检查Hibernate缓存中是否存在一个对象,如果在缓存中找到了该对象,则返回true,否则返回false。

 

    由于Hibernate将所有对象缓存到会话的一级缓存中,因此在运行大量查询或批量更新时,有必要定期清除缓存以避免内存问题。

关于 Hibernate 缓存和一级缓存示例的介绍到此为止,未来的文章中我们将探讨 Hibernate 二级缓存 – EHCache 的实现。

广告
将在 10 秒后关闭
bannerAds