首页 > 代码库 > hibernate的二级缓存----collection和query的二级缓存

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   BHibernate:     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      FF5      EE7      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_25class com.atguigu.hibernate.entities.EmployeeHibernate:     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_25class com.atguigu.hibernate.entities.Employee25

只发送了一条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=101class com.atguigu.hibernate.entities.EmployeeHibernate:     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=101


我在进行了第一次HQL查询后又对了数据表进行了增加操作了,此时的数据表已经发生了改变了,此时查询缓存被关闭了(就算更新操作对我HQL语句查询的结果没影响,但是查询缓存还是被关闭了)

如果查询缓存没有被关闭,那已是发送一条select语句和一条insert语句,但是现在是发送了两条select语句,一条insert语句 ,所以证明了,当查询缓存相关的表更新后,
查询缓存会自动关闭,这一点需要记住

hibernate的二级缓存----collection和query的二级缓存