Hibernate缓存研究
1. 什么是缓存?
数据库的缓存指的是应用程序和物理数据源之间的数据。即把物理数据源的数据复制到缓存。有了缓存,可以降低应用程序对物理数据源的访问频率,从而提高效率。缓存的介质一般是内存,也可以是硬盘。
Hibernate的缓存有三种类型:一级缓存、二级缓存和查询缓存。
2. 一级缓存
一级缓存即Session缓存,由Session自动进行管理,不需要程序进行干预。一级缓存根据对象的ID进行加载和缓存。如下面的代码:
@Overridepublic void testCache() {// TODO Auto-generated method stubSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction(); Course c = (Course) session.get(Course.class, 1);System.out.println("Name:" + c.getName());c = (Course) session.get(Course.class, 1);System.out.println("Name:" + c.getName());tx.commit();session.close();}
运行结果:
Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Name:计算机原理 Name:计算机原理
第1次查询时生成了SQL语句,并将查询出来的对象放在一级缓存里面,第2次查询时,在一级缓存里面直接找到了这个对象,就不需要再次生成SQL语句了。
再看一个例子:
@Overridepublic void testCache() {// TODO Auto-generated method stubSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction(); Course c = (Course) session.get(Course.class, 1);System.out.println("Name:" + c.getName());tx.commit();session.close();session = sessionFactory.openSession();tx = session.beginTransaction(); c = (Course) session.get(Course.class, 1);System.out.println("Name:" + c.getName());tx.commit();session.close();}
由于一级缓存是Session级别的缓存,所以Session关闭以后,一级缓存也就不存在了,第2次查询也要生成SQL语句:
Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Name:计算机原理 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Name:计算机原理
3. 二级缓存
二级缓存即SessionFactory缓存,和一级缓存类似,也是根据对象的ID进行加载和缓存,区别就在于一级缓存只在Session内有效,而二级缓存在SessionFactory内有效。在访问某个ID的对象时,先到一级缓存里面去找,如果没有找到就到二级缓存里面去找。二级缓存包括EHCache,OSCache,SwarmCache和JBossCache等。这里以EHCache作为例子。
二级缓存需要程序进行管理。首先,配置Maven下载相关的Jar,在pom文件里面添加:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>4.1.0.Final</version> </dependency><dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.8.3</version> </dependency>
创建EHCache配置文件ehcache.xml:
<ehcache><diskStore path="E:\Eclipse\MyWorkspace\Cache"/><defaultCachemaxElementsInMemory="10000"eternal="true"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="true"/><cache name="com.hzhi.course.entity.Course"maxElementsInMemory="10000"eternal="true"timeToIdleSeconds="300"timeToLiveSeconds="600"overflowToDisk="true"/> </ehcache>
defaultCache是默认的设置,下面一个cache指明了对哪一个类进行二级缓存。里面设置了最大缓存的对象数量,是否永久有效、最大空闲秒数、最大生存秒数、内存满时是否写到硬盘,写到硬盘的路径等等。
修改需要缓存的类的hbm文件:
<class name="com.hzhi.course.entity.Course" table="clas"><cache usage="read-only"/>......</class>
usage设置了并发访问策略,一般设置成read-only。
修改applicationContext.xml中的SessionFactory的配置,增加二级缓存的一些属性:
<!-- SessionFactory --><bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"><property name="dataSource" ><ref local="dataSource"/></property><!-- 配置Hibernate的属性 --><property name="hibernateProperties"><props><prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop><prop key="hibernate.show_sql">true</prop><prop key="hibernate.format_sql">true</prop><prop key="hibernate.connection.isolation">8</prop><!-- 二级缓存 --><prop key="hibernate.cache.use_second_level_cache">false</prop><prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> <prop key="hibernate.cache.provider_configuration_file_resource_path">WEB-INF/ehcache.xml</prop> </props></property> ...... </bean>
运行下面的例子:
@Overridepublic void testCache() {// TODO Auto-generated method stubSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction(); Course c = (Course) session.get(Course.class, 1);System.out.println("Name:" + c.getName());tx.commit();session.close();session = sessionFactory.openSession();tx = session.beginTransaction(); c = (Course) session.get(Course.class, 1);System.out.println("Name:" + c.getName());tx.commit();session.close();}
结果:
Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Name:计算机原理 Name:计算机原理
虽然关闭了Session,但是二级缓存仍然存在,所以只生成了一次SQL语句。
下面的例子:
@Overridepublic void testCache() {// TODO Auto-generated method stubSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction(); Query query = session.createQuery("from Course"); Iterator iter = query.iterate(); while(iter.hasNext()){ System.out.println(((Course)iter.next()).getName()); }tx.commit();session.close();session = sessionFactory.openSession();tx = session.beginTransaction(); query = session.createQuery("from Course"); iter = query.iterate(); while(iter.hasNext()){ System.out.println(((Course)iter.next()).getName()); }tx.commit();session.close();}
结果:
Hibernate: selectcourse0_.ID as col_0_0_ fromclas course0_ Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 计算机原理 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 计算机网络 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 数据库原理 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? C语言 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 大学英语A Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Java Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Linux Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 高等数学 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 语文 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 大学物理 Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 软件工程 Hibernate: selectcourse0_.ID as col_0_0_ fromclas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程
当使用Query的list()方法时,只生成一次SQL语句查询出所有的对象,使用iterate()方法时,会先得到所有对象的ID,然后根据每个ID生成一次SQL语句查询。第二个Session里面使用的也是iterate()方法,首先生成一次SQL语句,得到ID,然后根据ID查找对象,由于开启了二级缓存,在二级缓存里面找到了对象,所以就直接输出了,并没有再根据每个ID生成SQL语句。
不论是一级缓存还是二级缓存,都只能缓存对象,不能缓存属性的值。下面的例子:
@Overridepublic void testCache() {// TODO Auto-generated method stubSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction(); Query query = session.createQuery("select c.name from Course c"); List<String> names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); query = session.createQuery("select c.name from Course c"); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); tx.commit();session.close();}
运行结果:
Hibernate: selectcourse0_.NAME as col_0_0_ fromclas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- Hibernate: selectcourse0_.NAME as col_0_0_ fromclas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ----------
虽然开启了二级缓存,但是查询的结果不是对象,是属性,所以并没有缓存,第2次查询仍然生成了查询语句。要解决这个问题,就需要查询缓存。
3. 查询缓存
在配置了二级缓存的基础上,可以设置查询缓存,在SessionFactory的设置里面加上一行:
<prop key="hibernate.cache.use_query_cache">true</prop>
即打开了查询缓存。查询缓存也是SessionFactory级别的缓存,在整个SessionFactory里面都是有效的。
关闭二级缓存,运行下面的例子,在Query后面添加setCacheable(true)打开查询缓存:
@Overridepublic void testCache() {// TODO Auto-generated method stubSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction(); Query query = session.createQuery("select c.name from Course c"); query.setCacheable(true); List<String> names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); query = session.createQuery("select c.name from Course c"); query.setCacheable(true); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); tx.commit();session.close();}
结果:
Hibernate: selectcourse0_.NAME as col_0_0_ fromclas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ----------
由于两次查询的HQL语句是一致的,所以只生成一次SQL语句。但是如果把第二次查询改一下:
System.out.println("----------"); query = session.createQuery("select c.name from Course c where c.id > 5"); query.setCacheable(true); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------");
结果:
Hibernate: selectcourse0_.NAME as col_0_0_ fromclas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- Hibernate: selectcourse0_.NAME as col_0_0_ fromclas course0_ wherecourse0_.ID>5 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ----------
由于HQL语句变了,所以第二次也生成了SQL语句。
查询缓存可以缓存属性,也可以缓存对象,但是当缓存对象时,只缓存对象的ID,不会缓存整个对象。下面的例子:
@Overridepublic void testCache() {// TODO Auto-generated method stubSession session = sessionFactory.openSession();Transaction tx = session.beginTransaction(); Query query = session.createQuery("from Course");query.setCacheable(true);List<Course> list = query.list();for (int i=0; i<list.size(); i++){System.out.println(list.get(i).getName()); }System.out.println("----------"); tx.commit();session.close();session = sessionFactory.openSession();tx = session.beginTransaction(); query = session.createQuery("from Course"); query.setCacheable(true);list = query.list();for (int i=0; i<list.size(); i++){System.out.println(list.get(i).getName()); }System.out.println("----------"); tx.commit();session.close();}
结果:
Hibernate: selectcourse0_.ID as ID0_,course0_.NAME as NAME0_,course0_.COMMENT as COMMENT0_ fromclas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? Hibernate: selectcourse0_.ID as ID0_0_,course0_.NAME as NAME0_0_,course0_.COMMENT as COMMENT0_0_ fromclas course0_ wherecourse0_.ID=? 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ----------
由于开了查询缓存,没有开二级缓存,虽然使用的是list()方法一次查询出了所有的对象,但是查询缓存只缓存了对象ID,没有缓存整个对象。所以在第2个Session里面"from Course"这个HQL由于和前面的相同,并没有生成SQL语句,但是由于没有开二级缓存,没有缓存整个对象,只能根据每个ID去生成一次SQL语句。虽然两次用的都是list()方法,但是第一次是生成SQL语句去一次查询出所有的对象,而第二次是根据查询缓存里面的ID一个一个的生成SQL语句。
如果同时打开查询缓存和二级缓存,第2个Session里面就不用再根据ID去生成SQL语句了:
Hibernate: selectcourse0_.ID as ID0_,course0_.NAME as NAME0_,course0_.COMMENT as COMMENT0_ fromclas course0_ 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ---------- 计算机原理 计算机网络 数据库原理 C语言 大学英语A Java Linux 高等数学 语文 大学物理 软件工程 ----------
转载于:https://www.cnblogs.com/mstk/p/6363351.html
Hibernate缓存研究相关推荐
- hazelcast 使用_使用HazelCast进行Hibernate缓存:JPA缓存基础知识
hazelcast 使用 HazelCast的最大功能之一就是对Hibernate第二级缓存的支持 . JPA具有两个级别的缓存. 一级缓存在事务期间缓存对象的状态. 通过两次查询相同的对象,您必须获 ...
- Hibernate缓存 - 第一级缓存
Hibernate缓存 - 第一级缓存 欢迎使用Hibernate缓存 - 一级缓存示例教程.最近我们研究了Hibernate架构,hibernate映射以及如何使用HQL以面向对象的方式触发SQL查 ...
- Hibernate缓存原理与策略 Hibernate缓存原理:
Hibernate缓存原理: 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键.简单来讲Hibernate就是对JDBC进行封装,以实现内部状态的管理,OR关系的映射等 ...
- Hibernate 缓存机制
转载:http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html 一.why(为什么要用Hibernate缓存?) Hibernate是一个 ...
- Hibernate 缓存
我这里使用的是Hibernate5.2.0版本 Hibernate缓存分为一级缓存(有的也叫Session缓存)和二级缓存. 一级缓存(Session) 一级缓存的生命周期和session的生命周期一 ...
- 【大话Hibernate】hibernate缓存详解
为什么要用hibernate缓存? hibernate是一个持久层框架,经常访问物理数据库.为了降低应用程序对物理数据源访问的次数,从而提高应用程序的运行性能,我们想到使用hibernate缓存机制. ...
- (11) Hibernate 缓存机制
一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...
- 初识Hibernate 缓存
生活就像一杯咖啡,让你我慢慢的品尝,品尝它的苦涩和甘甜...... 一.什么是Hibernate缓存. 解析:白话来说就是缓存数据的容器 官方标准点缓存:是计算机领域的概念,它介于应用程序和永久性数据 ...
- Hibernate缓存级别教程
开始使用Hibernate的人们常见的问题之一就是性能,如果您没有太多的Hibernate经验,您会发现应用程序变慢的速度. 如果启用sql跟踪,您将看到有多少查询被发送到数据库,而这些查询几乎不需要 ...
- hibernate缓存机制与N+1问题
在项目中遇到的趣事 本文基于hibernate缓存机制与N+1问题展开思考, 先介绍何为N+1问题 再hibernate中用list()获得对象: 1 /** 2 * 此时会发出一条sql,将30个学 ...
最新文章
- BS-GX-017基于SSM实现的在线考试管理系统
- leaflet的入门开发(一)
- mooc_java 集合框架中 学生所选课程2MapHashMap
- vscode Go 1.11.4 编译错误 need Delve built by Go 1.11 or later
- IDEA MySql之增删改查
- Spark的新方案UnifiedMemoryManager内存管理模型分析
- 设计模式12——中介者模式
- 美团搜索推荐多业务商品排序探索与实践
- tile布局的ButtonBar
- Java的括号使用规则_java编码规范
- ubuntu系统打开.chm文件方式
- UltraCompare Crack,重复文件查找器
- php revel,golang,revel_Revel 的路由问题,golang,revel - phpStudy
- Jmeter插件安装perfmon(服务器资源监控工具)
- 华为服务器显示乱码,本地正常 服务器乱码
- 堆排序算法(java实现)
- 推荐系统工业界顶会论文总结——WSDM 2021
- MODBUS-RS485布线的8条准则
- LoadRunner教程(3)-LoadRunner创建一个测试脚本
- Unity3D学习(7)之物理引擎的应用与代码复用
热门文章
- 树莓派_树莓派初体验
- FISCO BCOS 微众银行 WeDPR 隐私解决方案 资料汇总
- 区块链 智能合约中获取不了时间戳 随机数怎么办
- 区块链 什么是RLP编码
- kubernetes Container、Pod、Replicaset、Service、Deployment、Lable、Statefulset关系和区别
- HTML日志查看器,在浏览器中查看Tomcat日志文件
- jquery ajax修改密码,提交form表单---修改密码 ajax、jQuery
- css布局的漂浮、position定位
- matlab 数字基带,基于MATLAB的数字基带传输的 FIR滤波器的设计
- 关于点击锁(防止多次点击)