hibernate的二级缓存----collection和query的二级缓存
collection二级缓存:
不使用集合的二级缓存时:
运行下面的代码:
@Test public void testCollectionSecondLevelCache1(){ Department dept = (Department) session.get(Department.class, 3); System.out.println(dept.getId()+" "+dept.getName()); System.out.println(dept.getEmps().size()); transaction.commit(); session.close(); session = sessionFactory.openSession(); transaction = session.beginTransaction(); Department dept2 = (Department) session.get(Department.class,3); Set<Employee> emps=dept2.getEmps(); for(Employee employee:emps){ System.out.println(employee.getId()+" " +employee.getName()); } }
产生的结果如下:
Hibernate:
select
department0_.ID as ID1_0_0_,
department0_.NAME as NAME2_0_0_
from
GG_DEPARTMENT department0_
where
department0_.ID=?
3 B
Hibernate:
select
emps0_.DEPT_ID as DEPT_ID5_0_1_,
emps0_.ID as ID1_1_1_,
emps0_.ID as ID1_1_0_,
emps0_.NAME as NAME2_1_0_,
emps0_.SALARY as SALARY3_1_0_,
emps0_.EMAIL as EMAIL4_1_0_,
emps0_.DEPT_ID as DEPT_ID5_1_0_
from
GG_EMPLOYEE emps0_
where
emps0_.DEPT_ID=?
3
--------------------------------------------------
Hibernate:
select
department0_.ID as ID1_0_0_,
department0_.NAME as NAME2_0_0_
from
GG_DEPARTMENT department0_
where
department0_.ID=?
Hibernate:
select
emps0_.DEPT_ID as DEPT_ID5_0_1_,
emps0_.ID as ID1_1_1_,
emps0_.ID as ID1_1_0_,
emps0_.NAME as NAME2_1_0_,
emps0_.SALARY as SALARY3_1_0_,
emps0_.EMAIL as EMAIL4_1_0_,
emps0_.DEPT_ID as DEPT_ID5_1_0_
from
GG_EMPLOYEE emps0_
where
emps0_.DEPT_ID=?
5 EE
7 GG
6 FF
1如果Session没有关闭的话应该是发送两条select语句的吧,因为Session的缓存中已经初始化了department和employee对象啦,但是Session关闭后,Session的一级缓存没有了吧,所以此时的department和employee对象都是游离对象,当需要要再次获得时必须发送select语句给数据吖
但是如果我们启用了集合的二级缓存呢??
集合二级缓存的操作步骤:
I. 配置对集合使用二级缓存
<collection-cache usage="read-write" collection="com.atguigu.hibernate.entities.Department.emps"/>
也可以在 .hbm.xml 文件中进行配置
<set name="emps" table="GG_EMPLOYEE" inverse="true" lazy="true">
<cache usage="read-write"/>
<key>
<column name="DEPT_ID" />
</key>
<one-to-many class="com.atguigu.hibernate.entities.Employee" />
</set>
II. 注意: 还需要配置集合中的元素对应的持久化类也使用二级缓存! 否则将会多出 n 条 SQL 语句.(集合缓存依赖于对持久化类的二级缓存)
例如在Hibernate.cfg.xml文件中配置集合的二级缓存:
<class-cache usage="read-write" class="com.atguigu.hibernate.entities.Employee"/>
<class-cache usage="read-write" class="com.atguigu.hibernate.entities.Department"/>
<collection-cache usage="read-write" collection="com.atguigu.hibernate.entities.Department.emps"/>
代码示例:
使用了集合二级缓存后结果为这个:
Hibernate:
select
department0_.ID as ID1_0_0_,
department0_.NAME as NAME2_0_0_
from
GG_DEPARTMENT department0_
where
department0_.ID=?
3 B
Hibernate:
select
emps0_.DEPT_ID as DEPT_ID5_0_1_,
emps0_.ID as ID1_1_1_,
emps0_.ID as ID1_1_0_,
emps0_.NAME as NAME2_1_0_,
emps0_.SALARY as SALARY3_1_0_,
emps0_.EMAIL as EMAIL4_1_0_,
emps0_.DEPT_ID as DEPT_ID5_1_0_
from
GG_EMPLOYEE emps0_
where
emps0_.DEPT_ID=?
3
--------------------------------------------------
6 FF
5 EE
7 GG
查询缓存:
查询缓存是二级缓存的一种用法
查询缓存(Query Cache):
对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把 查询结果存放在二级缓存中。以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能。
查询缓存适用于以下场合: 1在应用程序运行时经常使用的查询语句。 2 很少对与查询语句关联的数据库数据进行插入、删除或更新操作。
在hibernate的使用中,大家多数时间都在讨论一级缓存和二级缓存,而往往忽略了查询缓存。其实hibernate的查询缓存在使用过程中也起着同样重要的作用。hibernate的查询缓存是主要是针对普通属性结果集的缓存, 而对于实体对象的结果集只缓存id。在一级缓存,二级缓存和查询缓存都打开的情况下作查询操作时这样的:
查询普通属性---》会先到查询缓存中取,如果没有,则查询数据库;
查询实体---》 会先到查询缓存中取id,如果有,则根据id到缓存(一级/二级)中取实体,如果缓存中取不到实体,再查询数据库。
1查询缓存是属于二级缓存的一个子类别,所以查询缓存依赖于二级缓存,所以在使用查询缓存之前,必须配置好二级缓存,二级缓存上面有说,这里就不提了
2在 hibernate 配置文件中声明开启查询缓存
<property name="cache.use_query_cache">true</property>
3调用 Query 或 Criteria 的 setCacheable(true) 方法,启用当前(就是在你需要的查询语句后执行 setCacheable(true)方法)的查询缓存
例子说明:
测试代码:
@Test public void testQueryCache(){ Query query = session.createQuery("FROM Employee"); List<Employee> emps = query.list(); System.out.println(emps.size()); System.out.println(emps.iterator().next().getClass()); emps = query.list(); System.out.println(emps.size()); }
运行结果:
Hibernate: select employee0_.ID as ID1_1_, employee0_.NAME as NAME2_1_, employee0_.SALARY as SALARY3_1_, employee0_.EMAIL as EMAIL4_1_, employee0_.DEPT_ID as DEPT_ID5_1_ from GG_EMPLOYEE employee0_ 25 class com.atguigu.hibernate.entities.Employee Hibernate: select employee0_.ID as ID1_1_, employee0_.NAME as NAME2_1_, employee0_.SALARY as SALARY3_1_, employee0_.EMAIL as EMAIL4_1_, employee0_.DEPT_ID as DEPT_ID5_1_ from GG_EMPLOYEE employee0_ 25
在这里两次我都是执行同样的HQL语句进行查询,但是Hibernate却帮我发送了两条select语句,有一条是不是就是多余的啦?这就说明了在默认情况下, 设置的缓存对 HQL 及 QBC 查询时无效的, 但可以通过设置查询缓存的方式使其生效,(注意QBC查询也需要这样去设置)
启动了查询缓存后运行结果为:
Hibernate: select employee0_.ID as ID1_1_, employee0_.NAME as NAME2_1_, employee0_.SALARY as SALARY3_1_, employee0_.EMAIL as EMAIL4_1_, employee0_.DEPT_ID as DEPT_ID5_1_ from GG_EMPLOYEE employee0_ 25 class com.atguigu.hibernate.entities.Employee 25
只发送了一条select语句,那这样是不是大大减轻了我的程序的负担了吧
@Test public void testQueryCache(){ Query query = session.createQuery("FROM Employee e where e.id=1"); query.setCacheable(true); List<Employee> emps = query.list(); System.out.println(emps.size()); System.out.println(emps.iterator().next().getClass()); Employee employee=new Employee(); employee.setEmail("sdkfjsd@qq.com"); employee.setName("jeremy"); employee.setSalary(8000F); session.save(employee); emps = query.list(); System.out.println(emps.size()); //Criteria criteria = session.createCriteria(Employee.class); //criteria.setCacheable(true); }
运行结果:
Hibernate: select employee0_.ID as ID1_1_, employee0_.NAME as NAME2_1_, employee0_.SALARY as SALARY3_1_, employee0_.EMAIL as EMAIL4_1_, employee0_.DEPT_ID as DEPT_ID5_1_ from GG_EMPLOYEE employee0_ where employee0_.ID=10 1 class com.atguigu.hibernate.entities.Employee Hibernate: insert into GG_EMPLOYEE (NAME, SALARY, EMAIL, DEPT_ID) values (?, ?, ?, ?) Hibernate: select employee0_.ID as ID1_1_, employee0_.NAME as NAME2_1_, employee0_.SALARY as SALARY3_1_, employee0_.EMAIL as EMAIL4_1_, employee0_.DEPT_ID as DEPT_ID5_1_ from GG_EMPLOYEE employee0_ where employee0_.ID=10 1
我在进行了第一次HQL查询后又对了数据表进行了增加操作了,此时的数据表已经发生了改变了,此时查询缓存被关闭了(就算更新操作对我HQL语句查询的结果没影响,但是查询缓存还是被关闭了)