collection二级缓存:

不使用集合的二级缓存时:
  运行下面的代码:

  1. @Test
  2. public void testCollectionSecondLevelCache1(){
  3. Department dept = (Department) session.get(Department.class, 3);
  4. System.out.println(dept.getId()+" "+dept.getName());
  5. System.out.println(dept.getEmps().size());
  6.  
  7. transaction.commit();
  8. session.close();
  9.  
  10. session = sessionFactory.openSession();
  11. transaction = session.beginTransaction();
  12.  
  13. Department dept2 = (Department) session.get(Department.class,3);
  14. Set<Employee> emps=dept2.getEmps();
  15. for(Employee employee:emps){
  16. System.out.println(employee.getId()+" " +employee.getName());
  17. }
  18. }

产生的结果如下:

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"/>

代码示例:

使用了集合二级缓存后结果为这个:

  1. Hibernate:
  2. select
  3. department0_.ID as ID1_0_0_,
  4. department0_.NAME as NAME2_0_0_
  5. from
  6. GG_DEPARTMENT department0_
  7. where
  8. department0_.ID=?
  9. 3 B
  10. Hibernate:
  11. select
  12. emps0_.DEPT_ID as DEPT_ID5_0_1_,
  13. emps0_.ID as ID1_1_1_,
  14. emps0_.ID as ID1_1_0_,
  15. emps0_.NAME as NAME2_1_0_,
  16. emps0_.SALARY as SALARY3_1_0_,
  17. emps0_.EMAIL as EMAIL4_1_0_,
  18. emps0_.DEPT_ID as DEPT_ID5_1_0_
  19. from
  20. GG_EMPLOYEE emps0_
  21. where
  22. emps0_.DEPT_ID=?
  23. 3
  24. --------------------------------------------------
  25. 6 FF
  26. 5 EE
  27. 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)方法)的查询缓存

例子说明:
测试代码:

  1. @Test
  2. public void testQueryCache(){
  3. Query query = session.createQuery("FROM Employee");
  4. List<Employee> emps = query.list();
  5. System.out.println(emps.size());
  6. System.out.println(emps.iterator().next().getClass());
  7.  
  8. emps = query.list();
  9. System.out.println(emps.size());
  10. }

运行结果:

  1. Hibernate:
  2. select
  3. employee0_.ID as ID1_1_,
  4. employee0_.NAME as NAME2_1_,
  5. employee0_.SALARY as SALARY3_1_,
  6. employee0_.EMAIL as EMAIL4_1_,
  7. employee0_.DEPT_ID as DEPT_ID5_1_
  8. from
  9. GG_EMPLOYEE employee0_
  10. 25
  11. class com.atguigu.hibernate.entities.Employee
  12. Hibernate:
  13. select
  14. employee0_.ID as ID1_1_,
  15. employee0_.NAME as NAME2_1_,
  16. employee0_.SALARY as SALARY3_1_,
  17. employee0_.EMAIL as EMAIL4_1_,
  18. employee0_.DEPT_ID as DEPT_ID5_1_
  19. from
  20. GG_EMPLOYEE employee0_
  21. 25

在这里两次我都是执行同样的HQL语句进行查询,但是Hibernate却帮我发送了两条select语句,有一条是不是就是多余的啦?这就说明了在默认情况下, 设置的缓存对 HQL 及 QBC 查询时无效的, 但可以通过设置查询缓存的方式使其生效,(注意QBC查询也需要这样去设置)
启动了查询缓存后运行结果为:

  1. Hibernate:
  2. select
  3. employee0_.ID as ID1_1_,
  4. employee0_.NAME as NAME2_1_,
  5. employee0_.SALARY as SALARY3_1_,
  6. employee0_.EMAIL as EMAIL4_1_,
  7. employee0_.DEPT_ID as DEPT_ID5_1_
  8. from
  9. GG_EMPLOYEE employee0_
  10. 25
  11. class com.atguigu.hibernate.entities.Employee
  12. 25

只发送了一条select语句,那这样是不是大大减轻了我的程序的负担了吧

  还有一个需要注意的问题 查询缓存和一级/二级缓存不同,查询缓存的生命周期 ,是不确定的,当前关联的表发生改变时,查询缓存的生命周期结束。
例如运行下面测试代码:

  1. @Test
  2. public void testQueryCache(){
  3. Query query = session.createQuery("FROM Employee e where e.id=1");
  4. query.setCacheable(true);
  5.  
  6. List<Employee> emps = query.list();
  7. System.out.println(emps.size());
  8. System.out.println(emps.iterator().next().getClass());
  9.  
  10. Employee employee=new Employee();
  11.  
  12. employee.setEmail("sdkfjsd@qq.com");
  13. employee.setName("jeremy");
  14. employee.setSalary(8000F);
  15. session.save(employee);
  16.  
  17. emps = query.list();
  18. System.out.println(emps.size());
  19.  
  20. //Criteria criteria = session.createCriteria(Employee.class);
  21. //criteria.setCacheable(true);
  22. }

运行结果:

  1. Hibernate:
  2. select
  3. employee0_.ID as ID1_1_,
  4. employee0_.NAME as NAME2_1_,
  5. employee0_.SALARY as SALARY3_1_,
  6. employee0_.EMAIL as EMAIL4_1_,
  7. employee0_.DEPT_ID as DEPT_ID5_1_
  8. from
  9. GG_EMPLOYEE employee0_
  10. where
  11. employee0_.ID=10
  12. 1
  13. class com.atguigu.hibernate.entities.Employee
  14. Hibernate:
  15. insert
  16. into
  17. GG_EMPLOYEE
  18. (NAME, SALARY, EMAIL, DEPT_ID)
  19. values
  20. (?, ?, ?, ?)
  21. Hibernate:
  22. select
  23. employee0_.ID as ID1_1_,
  24. employee0_.NAME as NAME2_1_,
  25. employee0_.SALARY as SALARY3_1_,
  26. employee0_.EMAIL as EMAIL4_1_,
  27. employee0_.DEPT_ID as DEPT_ID5_1_
  28. from
  29. GG_EMPLOYEE employee0_
  30. where
  31. employee0_.ID=10
  32. 1

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

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

查询缓存会自动关闭,这一点需要记住

hibernate的二级缓存----collection和query的二级缓存的更多相关文章

  1. Hibernate缓存简介和对比、一级缓存、二级缓存详解

    一.hibernate缓存简介 缓存的范围分为3类:  1.事务范围(单Session即一级缓存)     事务范围的缓存只能被当前事务访问,每个事务都有各自的缓存,缓存内的数据通常采用相互关联的对象 ...

  2. Java三大框架之——Hibernate中的三种数据持久状态和缓存机制

    Hibernate中的三种状态   瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID. 持久状态:对象经过 ...

  3. Hibernate第七篇【对象状态、一级缓存】

    前言 本博文主要讲解Hibernate的细节-->对象的状态和一级缓存- 对象状态 Hibernate中对象的状态: - 临时/瞬时状态 - 持久化状态 - 游离状态 学习Hibernate的对 ...

  4. mybatis由浅入深day02_7.4mybatis整合ehcache_7.5二级缓存应用场景_7.6二级缓存局限性

    7.4 mybatis整合ehcache EhCache 是一个纯Java的进程内缓存框架,是一种广泛使用的开源Java分布式缓存,具有快速.精干等特点,是Hibernate中默认的CacheProv ...

  5. 缓存机制总结(JVM内置缓存机制,MyBatis和Hibernate缓存机制,Redis缓存)

    一.JVM内置缓存(值存放在JVM缓存中) 我们可以先了解一下Cookie,Session,和Cache Cookie:当你在浏览网站的时候,WEB 服务器会先送一小小资料放在你的计算机上,Cooki ...

  6. org.hibernate.exception.SQLGrammarException: could not execute query

    SSH项目中出现了 org.hibernate.exception.SQLGrammarException: could not execute query 错误,仔细检查后发现,是把createQu ...

  7. hibernate学习(5)——对象状态与一级缓存

    1.对象状态 1.1   状态介绍 hibernate 规定三种状态:瞬时态.持久态.脱管态 瞬时态:transient,session没有缓存对象,数据库也没有对应记录.没有与hibernate关联 ...

  8. org.hibernate.exception.JDBCConnectionException: could not execute query

    最近在做一个项目,测试的时候是没有问题的,但是放到服务器上以后,第二天就会出现下面的异常.重启Tomcat服务器后就正常了,但是下一天还是会出现同样的异常..... 我就查了一些资料最终把问题给解决了 ...

  9. Android二级缓存之物理存储介质上的缓存DiskLruCache

     Android二级缓存之物理存储介质上的缓存DiskLruCache Android DiskLruCache属于物理性质的缓存,相较于LruCache缓存,则DiskLruCache属于And ...

随机推荐

  1. vim手记

    1.normal 模式进入edit模式 i(a,o),进入 command 模式 :,回到normal模式Esc(ctrl+c,ctrl+[)2.help urs_toc 进入帮助文档目录,退出目录: ...

  2. C数据结构-栈和队列,括号匹配举例---ShinePans

    1.栈和队列是两种特殊的线性表             运算操作被限定仅仅能在表的一端或两端插入,删除元素,故也称它们为限定的线性表结构 2.栈的基本运算 1).Stackinit(&s) 构 ...

  3. Git Manual / Git使用手册 / Git, GitLab, Git Bash, TortoiseGit (建议全文复制到Word文档中通过导航窗格查看)

    Git使用手册 目录 1     引言 2     Git.GitLab简介 2.1      Git 2.2      GitLab 2.3      Git基本概念 3     运行环境 4    ...

  4. 05、Windows Store app 的图片裁切(更新)

    在 Win Phone Silverlight api 中,有一个 PhotoChooserTask 选择器,指定宽.高属性,在选择图片的时候, 可以进行裁切,代码: PhotoChooserTask ...

  5. 《Google软件测试之道》- Google软件测试介绍

    <Google软件测试之道>- Google软件测试介绍 2015-05-21 目录 1 质量与测试  2 角色  3 组织结构  4 爬.走.跑  5 测试类型  相关链接 与Micro ...

  6. 在linux下监控文件是否被删除或创建的命令

    You can use auditd and add a rule for that file to be watched: auditctl -w /path/to/that/file -p wa ...

  7. Ubuntu 16.04安装有道词典

    以前用Ubuntu 14.04 的时候,直接下载有道词典官方deb安装包,就安装好了,现在换成Ubuntu 16.04因为有些依赖问题就无法安装成功.于是Google之,成功解决,也顺便熟悉了一下dp ...

  8. [pwm]PWM的输入捕捉模式

    对于stm32来说,输入捕捉模式有两种: 普通输入捕捉模式:经常用来测量脉冲宽度和频率,例如测量脉冲宽度,TIM5_CH1来捕获高电平脉宽,首先先设置输入捕获为上升沿触发,然后记录下发生上升沿时TIM ...

  9. EAGAIN、EWOULDBLOCK、EINTR与非阻塞 长连接

    EAGAIN.EWOULDBLOCK.EINTR与非阻塞 长连接 EWOULDBLOCK用于非阻塞模式,不需要重新读或者写 EINTR指操作被中断唤醒,需要重新读/写 在Linux环境下开发经常会碰到 ...

  10. Entity Framework(四):使用DbModelBuilder API创建表结构

    DbContext类有一个OnModelCreating方法,它用于流利地配置领域类到数据库模式的映射.下面我们以fluent API的方式来定义映射.首先,先将Product类注释掉,重新编写该类, ...