Hibernate一级缓存、二级缓存以及查询缓存的关系
转载自http://blog.csdn.net/maoyeqiu/article/details/50209893
前两天总结了一下二级缓存和查询缓存的关系,但是又有一个新的问题,就是查询缓存缓存到二级缓存的数据,在第三次(第一次缓存中没有数据,查询数据库将对应的ID值存入到二级缓存中去,第二次如果是同一个Session那么将会把数据一级缓存中的数据返回,如果不是同一个Session而是同一个sessionfactory,那么将会把二级缓存中的数据返回,同时将数据放入到一级缓存中去)获取的时候,不使用查询缓存的方法,而是直接使用一级缓存的方法,能不能将缓存的数据获取到呢,我们现在验证一下。
首先开启一级缓存(默认)、二级缓存和查询缓存
- <?xml version="1.0" encoding="utf-8"?>
- <!DOCTYPE hibernate-configuration PUBLIC
- "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
- "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
- <hibernate-configuration>
- <session-factory>
- <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
- <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernatedemo</property>
- <property name="hibernate.connection.password">root</property>
- <property name="hibernate.connection.username">root</property>
- <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
- <property name="show_sql">true</property>
- <property name="hbm2ddl.auto">create</property>
- <property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
- <property name="hibernate.cache.use_query_cache">true</property>
- <!-- 开启二级缓存,其实hibernate默认就是开启的,这里显示的指定一下 -->
- <property name="hibernate.cache.use_second_level_cache">true</property>
- <property name="hibernate.generate_statistics">true</property>
- <mapping class="hibernate.test.dto.DepartmentEntity"></mapping>
- </session-factory>
- </hibernate-configuration>
用到的缓存类
- package hibernate.test.dto;
- @Entity
- @Table(name = "DEPARTMENT", uniqueConstraints = {
- @UniqueConstraint(columnNames = "ID"),
- @UniqueConstraint(columnNames = "NAME") })
- @Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="department")
- public class DepartmentEntity implements Serializable {
- private static final long serialVersionUID = 1L;
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- @Column(name = "ID", unique = true, nullable = false)
- private Integer id;
- @Column(name = "NAME", unique = true, nullable = false, length = 100)
- private String name;
- public Integer getId() {
- return id;
- }
- public void setId(Integer id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
启动查询缓存将返回的实体存入到二级缓存中去
- //此方法向数据库中存入三条数据
- storeData();
- Session session = HibernateUtil.getSessionFactory().openSession();
- session.beginTransaction();
- //开启查询缓存, query.setCacheable(true);开启查询缓存
- Query query = session.createQuery("select s from DepartmentEntity s");
- query.setCacheable(true);
- List<DepartmentEntity> names = query.list();
- for (Iterator<DepartmentEntity> it = names.iterator(); it.hasNext();) {
- String name = it.next().getName();
- System.out.println(name);
- }
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
执行的结果:
hibernate: select department0_.ID as ID0_, department0_.NAME as NAME0_ from DEPARTMENT department0_
Human Resource
Humanne
Jhon
3
我们可以看到,产生了一条查询语句,将三个实体的名字输出,放入二级缓存的数量是3,都是没有问题的。这里比较容易犯的一个错误是查询的结果并不是实体,而是名字或者是其他属性,比如sql我们这么写:select s.name from DepartmentEntity s。存入二级缓存的数据是0,也就是没有存入到二级缓存中去。
再次调用上述方法:
- //开启查询缓存, query.setCacheable(true);开启查询缓存
- Query query = session.createQuery("select s from DepartmentEntity s");
- query.setCacheable(true);
- List<DepartmentEntity> names = query.list();
- for (Iterator<DepartmentEntity> it = names.iterator(); it.hasNext();) {
- String name = it.next().getName();
- System.out.println(name);
- }
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- //同一个Session中再次查询,不会发出SQL语句到数据库
- query = session.createQuery("select s from DepartmentEntity s");
- query.setCacheable(true);
- names = query.list();
- for (Iterator<DepartmentEntity> it = names.iterator(); it.hasNext();) {
- String name = it.next().getName();
- System.out.println(name);
- }
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
执行的结果:
Hibernate: select department0_.ID as ID0_, department0_.NAME as NAME0_ from DEPARTMENT department0_
Human Resource
Humanne
Jhon
3
Human Resource
Humanne
Jhon
3
0
我们可以看到只产生了一条数据库查询语句,第二次直接从缓存中获取(注意,第二次调用的时候依然要写quey.setCacheable(true); ,我们模拟的是同一个方法的多次调用,不然的会产生数据库查询),那么问题来了,这个缓存指的是一级缓存还是二级缓存呢,我们看执行的结果二级缓存的命中是0,也就是说这里并没有用到二级缓存而是直接使用了一级缓存,前提是在同一个Session的情况下,在同一个session下执行的结果都会首先缓存到一级缓存中去,那么我们开一个新的Session会有什么样的不同结果呢
- //开启查询缓存, query.setCacheable(true);开启查询缓存
- Query query = session.createQuery("select s from DepartmentEntity s");
- query.setCacheable(true);
- List<DepartmentEntity> names = query.list();
- for (Iterator<DepartmentEntity> it = names.iterator(); it.hasNext();) {
- String name = it.next().getName();
- System.out.println(name);
- }
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- //同一个Session中再次查询,不会发出SQL语句到数据库
- query = session.createQuery("select s from DepartmentEntity s");
- quey.setCacheable(true);
- names = query.list();
- for (Iterator<DepartmentEntity> it = names.iterator(); it.hasNext();) {
- String name = it.next().getName();
- System.out.println(name);
- }
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
- Session anotherSession = HibernateUtil.getSessionFactory().openSession();
- anotherSession.beginTransaction();
- query = anotherSession.createQuery("select s from DepartmentEntity s");
- query.setCacheable(true);
- names = query.list();
- for (Iterator<DepartmentEntity> it = names.iterator(); it.hasNext();) {
- String name = it.next().getName();
- System.out.println(name);
- }
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
执行结果:
- Hibernate: select department0_.ID as ID0_, department0_.NAME as NAME0_ from DEPARTMENT department0_
- Human Resource
- Humanne
- Jhon
- 3
- Human Resource
- Humanne
- Jhon
- 3
- 0
- Human Resource
- Humanne
- Jhon
- 3
- 3
我们看到运行的结果,三次执行都只是放入二级缓存的实例3个,也就是说二级缓存中只有三个实例。由于二级缓存是sessionfactory级别的当开启查询缓存将数据放入的二级缓存的时候是不受开了几个session影响的,所以尽管我们上边开启了2个session但是依旧是在二级缓存中有3个实体。这里还有一个问题是查询缓存的key值是如何定义的呢,导致了开启了3次查询缓存而只存入3条数据,如果key值不同的话,那么肯定是会存入9条数据,关于这个问题大家可以参考,这里。由于二级缓存是sessionfactory级别的,因此会直接将二级缓存中的数据取出,并存入到一级缓存中去。
我们在sql中只是查询实体的名字,我们来看一下查询缓存是如何缓存的
- //开启查询缓存, query.setCacheable(true);开启查询缓存
- ,Query query = session.createQuery("select s.name from DepartmentEntity s");
- query.setCacheable(true);
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
- //同一个Session中再次查询,不会发出SQL语句到数据库
- query = session.createQuery("select s.name from DepartmentEntity s");
- query.setCacheable(true);
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
- Session anotherSession = HibernateUtil.getSessionFactory().openSession();
- anotherSession.beginTransaction();
- query = anotherSession.createQuery("select s.name from DepartmentEntity s");
- query.setCacheable(true);
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCachePutCount());
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
执行结果:
Hibernate: select department0_.NAME as col_0_0_ from DEPARTMENT department0_
0
0
0
0
0
0
从结果上我们可以看到只有一个数据库查询,然后是六个0,前两个0是没有将数据存入到二级缓存中去,中间两个0并且没有sql数据库查询说明,数据从缓存中获取,而且是一级缓存中的数据,后两个0我们重新开启了一个session,同样没有数据库查询,也就说是调用了二级缓存中的数据,也就说明了查询缓存也是sessionfactory级别的。
我们现在来验证一下我们刚才提出的问题,直接用load获取数据
- DepartmentEntity department = (DepartmentEntity) session.load(DepartmentEntity.class, new Integer(1));
- System.out.println(HibernateUtil.getSessionFactory().getStatistics().getSecondLevelCacheHitCount());
执行结果:
0
从结果来看,没有产生数据库查询二级缓存的命中是0,也就是说数据是从一级缓存中获取的,这就验证了我们一开始提到的答案。
总结:
1、一级缓存是session级别的,二级缓存和查询缓存都是sessionfactory级别的,查询缓存和二级缓存是一起来使用的
2、任何sql执行都会存入到同一个session的一级缓存中去
3、同时开启查询缓存和二级缓存,可以在不同session间共享缓存的结果
4、二级缓存缓存的是实体,不是属性
5、查询缓存的结果如果只是属性,那么查询缓存中存储的是id和属性的值,如果是实体的集合,那么查询缓存存储的只是实体的id,对应的实体会存储到二级缓存中去。
6、不同session间返回数据的顺序是,二级缓存先将数据返回,然后将数据存入本session的一级缓存中去,以便下次调用时的使用
Hibernate一级缓存、二级缓存以及查询缓存的关系相关推荐
- mysql php 缓存机制_mysql数据库查询缓存原理是什么
mysql数据库查询缓存原理是:1.缓存SELECT操作的结果集和SQL语句,key为sql,value为查询结果集:2.如果新的SELECT语句到了,以这个sql为key去缓存中查询,如果匹配,就把 ...
- mysql清除缓存_清空 MySQL 查询缓存
MySQL 查询缓存 在 SQL 调优的过程中,发现原本很慢的一条 SQL(将近 1 分钟) 在第二次运行时, 瞬间就完成了(0.04sec). 这是因为 MySQL 自带的缓存机制,将查询结果进行缓 ...
- 【HIBERNATE框架开发之九】HIBERNATE 性能优化笔记!(遍历、一级/二级/查询/缓存、乐观悲观锁等优化算法)...
本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/hibernate/825.html 1. ...
- Hibernate 一级缓存,二级缓存,查询缓存
概念: 1.什么是缓存呢? 缓存:是计算机领域的概念,它介于应用程序和永久性数据存储源之间. 缓存:一般人的理解是在内存中的一块空间,可以将二级缓存配置到硬盘.用白话来说,就是一个存储数据的容器.我们 ...
- 【Hibernate框架开发之九】Hibernate 性能优化笔记!(遍历、一级/二级/查询/缓存/乐观悲观锁等优化算法)...
1. 循环分页或者循环进行部分读取处理数据的时候,使用 session.clear() ; 2. 对应1+N(N+1)问题使用如下解决方式: 1): 使用createCriteria进行查询 ...
- Hibernate学习——(十二)Hibernate缓存机制(一级、二级、查询)
一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...
- hibernate查询缓存_Hibernate查询缓存如何工作
hibernate查询缓存 介绍 现在,我已经介绍了实体和集合缓存,现在该研究查询缓存的工作原理了. 查询缓存与实体严格相关,它在搜索条件和满足该特定查询过滤器的实体之间绘制关联. 像其他Hibern ...
- Hibernate查询缓存如何工作
介绍 既然我已经介绍了实体和集合缓存,现在该研究查询缓存的工作原理了. 查询缓存与实体严格相关,它在搜索条件和满足该特定查询过滤器的实体之间绘制关联. 像其他Hibernate功能一样,查询缓存也不像 ...
- 【MyBatis框架】查询缓存-一级缓存原理
查询缓存 1.什么是查询缓存 mybatis提供查询缓存,用于减轻数据压力,提高数据库性能. mybaits提供一级缓存,和二级缓存. 缓存模式图如图 一级缓存是SqlSession级别的缓存.在操作 ...
- Hibernate 缓存机制续 - 查询缓存
对于一个应用来说,最多的操作是查询,而并非是写入和更改,如果能将查询缓存起来,那么能够有效提升效率. Hibernate的查询缓存是基于二级缓存的,所以,如果想使用查询缓存,必须先开启二级缓存. 1. ...
最新文章
- IDC公布中国深度学习市场综合份额:百度超越Facebook位列第二
- html5圆形图片轮播,jQuery超酷响应式圆形图片轮播图特效
- java notifier_Java学习笔记---4.Java的分支循环语句
- java concurrenthashmap与阻塞队列
- RuntimeError: Expected object of backend CUDA but got backend CPU for argument #4 'mat1'
- pcap文件解析工具_【免费毕设】PHP网络数据包分析工具的设计与开发(源代码+论文)...
- Android中Spinner的使用
- How to save your Ethereum Dapp users from paying gas for transactions
- decode encode
- 基础算法学习(二)_二叉树及应用赫夫曼编码
- 关于ARCGIS SERVER 9.3的ArcGIS Server Manager出现“/”应用程序中的服务器错误
- 每天进步一点点《ML - 正则化代价函数》
- pgp 私钥需要什么样的保护措施_参与以太坊 2.0 存款合约前需要了解的相应风险...
- CSS变量(自定义属性)实践指南
- SODB、RBSP和EBSP
- qt里的pushButton中的clicked(bool);用法
- Python实战 | 使用代理IP刷CSDN博客访问量
- 移动视频录传-公网对讲APP-MCP常见操作说明
- LeetCode 1114:按序打印
- 系统性思考-思考习惯的养成
热门文章
- 新手学v-text指令
- php6 xml,thinkphp6 常用方法文档
- pythoncontinue函数_Python continue语句
- springboot2.0 图片收集
- mybatis 里面concat()函数t模糊查询
- 2017年杭州java面试题_2017年Java面试题整理
- 水凝胶 静电纺丝_【再生医学前沿】Nature子刊:静电纺丝玩出新花样!静电射流偏转的超快3D打印亚微米结构...
- 大文件上传 之 改版了的SlickUpload.HttpUploadModule(Krystalware.SlickUpload.dll)
- 2Y叔的clusterProfiler-book阅读Chapter 2 Functional Enrichment Analysis Methods
- python 调用 .netcore api_浅谈Python调用XBee的API来进行通讯