文档章节

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

jj_soft
 jj_soft
发布于 2016/06/04 15:24
字数 1715
阅读 4
收藏 0

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

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语句查询的结果没影响,但是查询缓存还是被关闭了)

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

© 著作权归作者所有

jj_soft
粉丝 1
博文 96
码字总数 74097
作品 0
广州
程序员
私信 提问
hibernate总结

Hibernate的核心: 类: SessionFactory Session 配置文件: classpath:hibernate.cfg.xml classpath:hibernate.properties - 可选的 缓存: 一级缓存 Session 二级缓存 SessionFactory 必须要......

CarlDing
2016/06/27
31
0
全面讲解Hibernate缓存

在向大家详细介绍Hibernate二级缓存之前,首先让大家了解下一级缓存,然后全面介绍Hibernate二级缓存。 Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的...

dong.li
2012/04/24
462
0
基础图解之mybatis的一级缓存和二级缓存

参考博客: spring管理hibernate,mybatis,一级缓存失效原因 https://www.cnblogs.com/zhangyu0217----/p/7574704.html Mybatis和mybatis-spring一级缓存 https://blog.csdn.net/lvbaolin12......

莫库什勒
2019/04/18
28
0
Hibernate缓存策略详解

Hibernate缓存策略 1. 数据缓存 1.1. 概述 缓存是数据库数据临时容器,它包含了库表数据的临时拷贝,位于数据库与数据访问层之间。 ORM 在进行数据读取时,会根据其缓存管理策略,首先在内存...

提广乾
2012/09/11
188
0
hibernate一级缓存和二级缓存的区别

缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写...

ddtt
2011/12/22
350
0

没有更多内容

加载失败,请刷新页面

加载更多

dynamic-connectivity 动态连通性问题之 quick-union 算法

quick-union 的思想是:若对象 p 的 root_id 和对象 q 的 root_id 相等,则认为 p 和 q 连通。 若要将对象 p 和对象 q 连通(已知两对象未连通),则将 p 的 root_id 的值设为 q 的 root_id ...

Phpythoner_Alei
今天
40
0
OSChina 周六乱弹 —— 实在选不出来就唱国歌

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @花间小酌 :#今日歌曲推荐# 分享阿冗的单曲《你的答案》。--祝大家在2020年都找到自己答案。 《你的答案》- 阿冗 手机党少年们想听歌,请使劲...

小小编辑
今天
25
1
Maven打包可执行Jar包的方法

在使用Java开发中,会使用到将工程打包成可执行的jar包的情况,那么在maven中怎么将项目中的依赖包都添加到jar中呢。在pom.xml中添加一下插件: <build><plugins><plugin><ar...

CapJes
今天
13
0
使用vue 开发地图类系统(openlayers.js)的注意。

使用vue 开发地图类系统的注意。 1、使用地图应该创建的对象 少使用 vue 的data 和计算属性(comments)存数据或是vuex。 为什么要要注意这个问题呢? 答:这个就要了解到vue的实现原理 。原理...

DY-Tao
昨天
10
0
web移动端学习:高德地图demo(一)

在高德地图开发中申请开发者资格,然后在控制台中新建应用,获得KEY; 新建模板HTML文件; <!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>地图demo</title><scri......

dxiya
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部