Hibernate【缓存】知识要点
对象状态
Hibernate中对象的状态:
- 临时/瞬时状态
- 持久化状态
- 游离状态
学习Hibernate的对象状态是为了更清晰地知道Hibernate的设计思想,以及是一级缓存的基础...当然啦,也就一点点知识
临时/瞬时状态
当我们直接new出来的对象就是临时/瞬时状态的..
- 该对象还没有被持久化【没有保存在数据库中】
- 不受Session的管理
持久化状态
当保存在数据库中的对象就是持久化状态了
- 当调用session的save/saveOrUpdate/get/load/list等方法的时候,对象就是持久化状态
- 在数据库有对应的数据
- 受Session的管理
- 当对对象属性进行更改的时候,会反映到数据库中!
我们来测试一下:当对对象属性进行更改的时候,会反映到数据库中!
session.save(idCard);idCard.setIdCardName("我是测试持久化对象");
游离状态
当Session关闭了以后,持久化的对象就变成了游离状态了...
- 不处于session的管理
- 数据库中有对应的记录
一级缓存
Hibernate有一级缓存和二级缓存之分,这里主要讲解一级缓存
什么是一级缓存?
Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效!
只要是持久化对象状态的,都受Session管理,也就是说,都会在Session缓存中!
Session的缓存由hibernate维护,用户不能操作缓存内容; 如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。
为什么要是使用缓存?
减少对数据库的访问次数!从而提升hibernate的执行效率!
测试
我们来看一下Hibernate是怎么减少对数据库访问的次数的。
现在我的User表有这么一条记录:
//把数据放进cacheUser user = (User) session.get(User.class, 1);//发现要修改的字段和cache一样,不执行user.setUserName("你好2");
取数据也是一样的
User user = null;user = (User) session.get(User.class, 1);user = (User) session.get(User.class, 1);
缓存相关的方法
和缓存有关常用的方法有三个:
- session.flush(); 让一级缓存与数据库同步
- session.evict(arg0); 清空一级缓存中指定的对象
session.clear(); 清空一级缓存中缓存的所有对象
clear
User user = null;user = (User) session.get(User.class, 1);//清除缓存,那么下面获取的时候,就不能从缓存里面拿了session.clear();user = (User) session.get(User.class, 1);
- flush
在有缓存的情况下,修改同一条记录的数据,以最后的为准...因此只有一条update
User user = null;user = (User) session.get(User.class, 1);user.setUserName("我是第一");user = (User) session.get(User.class, 1);user.setUserName("我是第二");
我让强制让它和数据库同步的话,就有两条update了
User user = null;user = (User) session.get(User.class, 1);user.setUserName("我是第一");session.flush();user = (User) session.get(User.class, 1);user.setUserName("我是第二");
一般地,我们在批处理的时候会用,因为缓存也是有大小的,如果1000条数据插入进去都要缓存,那么Hibernate可能就崩了...
- 每隔一定记录数,先与数据库同步 flush()
- 再清空缓存 clear()
值得注意的是:不同的Session是不会共享缓存的!
Iterator与list
我们使用HQL查询全部数据的时候,可以使用list()得到所有的数据,也可以使用iterator()得到一个迭代器,再遍历迭代器...那它们有什么区别呢?
。。。。当时看视频的时候说是下图:
但是我在测试的时候:List也可以获取缓存的数据
当然啦,Iterator也是可以获取缓存的数据
因此,在获取数据的时候还是使用list()方便!
懒加载
懒加载就是当使用数据的时候才去获取数据、执行对应的SQL语句...当还没用到数据的时候,就不加载对应的数据!
主要目的就是为了提高Hibernate的性能,提高执行效率!
- get: 及时加载,只要调用get方法立刻向数据库查询
- load:默认使用懒加载,当用到数据的时候才向数据库查询。
懒加载再次体验
User user = (User) session.load(User.class, 1);System.out.println("________");System.out.println(user);
我们可以在对应的配置文件用通常lazy属性来设置
关闭懒加载:
<class name="IdCard" table="IdCard" lazy="false">
lazy有三个属性:
- true 使用懒加载
- false 关闭懒加载
- extra (在集合数据懒加载时候提升效率)【只有在set、list等集合标签中使用】
- 在真正使用数据的时候才向数据库发送查询的sql;
- 如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!
懒加载异常
当Session关闭后,就不能使用懒加载了,否则会报出异常
Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session
报出了这个异常,我们有4种方法解决:
- 方式1: 先使用一下数据
- dept.getDeptName();
- 方式2:强迫代理对象初始化
- Hibernate.initialize(dept);
- 方式3:关闭懒加载
- 设置lazy=false;
- 方式4: 在使用数据之后,再关闭session!
Hibernate二级缓存
前面我们已经讲解过了一级缓存,一级缓存也就是Session缓存,只在Session的范围内有效...作用时间就在Session的作用域中,范围比较小
Hibernate为我们提供了二级缓存功能:二级缓存是基于应用程序的缓存,所有的Session都可以使用
- Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存框架!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码。
- 如果用户觉得hibernate提供的框架框架不好用,自己可以换其他的缓存框架或自己实现缓存框架都可以。
Hibernate二级缓存:存储的是常用的类
配置二级缓存
既然二级缓存是Hibernate自带的,那么我们可以在hibernate.properties文件中找到对应的信息..
- hibernate.cache.use_second_level_cache false【二级缓存默认不开启,需要手动开启】
- hibernate.cache.use_query_cache true 【开启查询缓存】
- choose a cache implementation 【二级缓存框架的实现】
- hibernate.cache.provider_class org.hibernate.cache.EhCacheProvider
- hibernate.cache.provider_class org.hibernate.cache.EmptyCacheProvider
- hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider 默认实现
- hibernate.cache.provider_class org.hibernate.cache.TreeCacheProvider
- hibernate.cache.provider_class org.hibernate.cache.OSCacheProvider
- hibernate.cache.provider_class org.hibernate.cache.SwarmCacheProvider
通过配置文件我们可以发现,二级缓存默认是不开启的,需要我们手动开启,以下步骤:
- 1)开启二级缓存
- 2)指定缓存框架
- 3)指定哪些类加入二级缓存
开启二级缓存
在hibernate.cfg.xml文件中开启二级缓存
<!-- a. 开启二级缓存 --><property name="hibernate.cache.use_second_level_cache">true</property>
指定缓存框架
指定Hibernate自带的二级缓存框架就好了
<!-- b. 指定使用哪一个缓存框架(默认提供的) --><property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
指定哪些类加入二级缓存
<!-- c. 指定哪一些类,需要加入二级缓存 --><class-cache usage="read-write" class="zhongfucheng.aa.Monkey"/><class-cache usage="read-only" class="zhongfucheng.aa.Cat"/>
测试:
我们知道一级缓存是Session的缓存,那么我们在测试二级缓存的时候使用两个Session来测试就好了。如果第二个Session拿到的是缓存数据,那么就证明二级缓存是有用的。
package zhongfucheng.aa;import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;public class App5 {public static void main(String[] args) {//获取加载配置管理类Configuration configuration = new Configuration();//加载类对应的映射文件!configuration.configure().addClass(Animal.class);//创建Session工厂对象SessionFactory factory = configuration.buildSessionFactory();//得到Session对象Session session1 = factory.openSession();//使用Hibernate操作数据库,都要开启事务,得到事务对象Transaction transaction = session1.getTransaction();//开启事务transaction.begin();Monkey monkey = (Monkey) session1.get(Monkey.class,"40283f815be67f42015be67f43240001" );System.out.println(monkey.getName());System.out.println("-----------------------");Session session2 = factory.openSession();Transaction transaction2 = session2.getTransaction();transaction2.begin();Monkey monkey2 = (Monkey) session1.get(Monkey.class, "40283f815be67f42015be67f43240001");System.out.println(monkey2.getName());//提交事务transaction.commit();transaction2.commit();//关闭Sessionsession1.close();session2.close();}
}
得到的是缓存数据!
缓存策略
我们在把Animal类放进二级缓存的时候,用法为只读
也就是说,只能读取,不能写入,我们来看看写入会怎么样:
monkey2.setName("小猴子");
抛出了异常....
usage的属性有4种:
<class-cache usage="read-only"/>
放入二级缓存的对象,只读;<class-cache usage="nonstrict-read-write"/>
非严格的读写<class-cache usage="read-write"/>
读写; 放入二级缓存的对象可以读、写;<class-cache usage="transactional"/>
(基于事务的策略)
集合缓存
如果我们在数据库查询的数据是集合...Hibernate默认是没有为集合数据设置二级缓存的...因此还是需要去读写数据库的信息
接下来,我们就看看把集合设置为二级缓存是什么做的:
- 在hibernate.cgf.xml中配置对象中的集合为二级缓存
<!-- 集合缓存[集合缓存的元素对象,也加加入二级缓存] --><collection-cache usage="read-write" collection="cn.itcast.b_second_cache.Dept.emps"/>
- 测试代码:
public void testCache() {Session session1 = sf.openSession();session1.beginTransaction();// a. 查询一次Dept dept = (Dept) session1.get(Dept.class, 10);dept.getEmps().size();// 集合session1.getTransaction().commit();session1.close();System.out.println("------");// 第二个sessionSession session2 = sf.openSession();session2.beginTransaction();// a. 查询一次dept = (Dept) session2.get(Dept.class, 10); // 二级缓存配置好; 这里不查询数据库dept.getEmps().size();session2.getTransaction().commit();session2.close();}
查询缓存
list()和iterator()会把数据放在一级缓存,但一级缓存只在Session的作用域中有效...如果想要跨Session来使用,就要设置查询缓存
我们在配置文件中还看到了查询缓存这么一条配置..
#hibernate.cache.use_query_cache true 【开启查询缓存】
也就是说,默认的查询数据是不放在二级缓存中的,如果我们想要把查询出来的数据放到二级缓存,就需要在配置文件中开启
<!-- 开启查询缓存 --><property name="hibernate.cache.use_query_cache">true</property>
- 在使用程序查询的时候,也要调用setCacheable()方法,设置为查询缓存。
@Testpublic void listCache() {Session session1 = sf.openSession();session1.beginTransaction();// HQL查询 【setCacheable 指定从二级缓存找,或者是放入二级缓存】Query q = session1.createQuery("from Dept").setCacheable(true);System.out.println(q.list());session1.getTransaction().commit();session1.close();Session session2 = sf.openSession();session2.beginTransaction();q = session2.createQuery("from Dept").setCacheable(true);System.out.println(q.list()); // 不查询数据库: 需要开启查询缓存session2.getTransaction().commit();session2.close();}
如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y
更多的文章可往:文章的目录导航
Hibernate【缓存】知识要点相关推荐
- 记录Hibernate的缓存知识
一.Hibernate缓存的作用 Hibernate是一个持久层框架,Hibernate要经常访问物理数据库.为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能,Hibernate的缓 ...
- hazelcast 使用_使用HazelCast进行Hibernate缓存:JPA缓存基础知识
hazelcast 使用 HazelCast的最大功能之一就是对Hibernate第二级缓存的支持 . JPA具有两个级别的缓存. 一级缓存在事务期间缓存对象的状态. 通过两次查询相同的对象,您必须获 ...
- 入门Java你需要了解的几个知识要点!
很多Java编程初学者在刚接触Java语言程序的时候,不知道该学习掌握哪些必要的基础知识.本文小千总结了入门Java你需要知道的几个基础知识要点,希望能够对刚入门的Java新手有帮助. 一.先了解什么 ...
- Java虚拟机必学之四大知识要点,附学习资料
转载自 Java虚拟机必学之四大知识要点,附学习资料 作为一位 Java 程序员,在尽情享受 Java 虚拟机带来好处的同时,我们还应该去了解和思考"这些技术特性是如何实现的", ...
- Hibernate缓存级别教程
开始使用Hibernate的人们常见的问题之一就是性能,如果您没有太多的Hibernate经验,您会发现应用程序变慢的速度. 如果启用sql跟踪,您将看到有多少查询被发送到数据库,而这些查询几乎不需要 ...
- Hibernate缓存 - 第一级缓存
Hibernate缓存 - 第一级缓存 欢迎使用Hibernate缓存 - 一级缓存示例教程.最近我们研究了Hibernate架构,hibernate映射以及如何使用HQL以面向对象的方式触发SQL查 ...
- 【计算机网络】计算机网络体系结构总结——基本知识要点汇总
halo~我是bay_Tong桐小白 本文内容是桐小白个人对所学知识进行的总结和分享,知识点会不定期进行编辑更新和完善,了解最近更新内容可参看更新日志,欢迎各位大神留言.指点 计算机网络体系结构总结- ...
- 2011年计算机三级考试PC技术知识要点(32)
2011年计算机三级考试PC技术知识要点(32) 2011年02月19日 [b]二.输出设备[/b] 1.显示器 显示器是PC机必不可少的一种输出设备,其作用是将数字信息号转化为光信 号,最终将文字与 ...
- 【计算机组成原理】输入输出(I/O)系统总结——基本知识要点汇总
halo~我是bay_Tong桐小白 本文内容是桐小白个人对所学知识进行的总结和分享,知识点会不定期进行编辑更新和完善,了解最近更新内容可参看更新日志,欢迎各位大神留言.指点 [此部分内容与总线部分的 ...
- java编程基础_Java编程语言基础知识要点
Java编程语言基础知识要点 Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程.下面小编整理了Java编程语言基础知识要点,希望对大家有帮 ...
最新文章
- Linxu安装Tomcat与Jdk并卸载自带OpenJdk
- Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发
- 高效能人士的七个习惯_《高效能人士的七个习惯》导图和读后感
- javascript第三天(2)
- SmartFox中的類型轉換
- Spring获取前台参数的几种方式
- [转]秒杀全网!研发、运营必备实用工具网站
- linux罗技键盘驱动下载,罗技m590驱动-罗技m590无线鼠标驱动下载 v8.10.154官方版-下载啦...
- 上网本之必备网络工具推荐
- 逻辑思维题一:条件组合覆盖
- rpm 如何安装mysql_如何使用rpm安装MySQL
- 马斯克发起投票:是否应该出售特斯拉10%的股票?超5成粉丝赞成
- matlab单位函数定义,MATLAB 函数(一)
- vb整合多个excel表格到一张_如何使用VB实现多个excel表格合并在一个EXCEL表格里面...
- New情报:APT28,TA505 黑产组织,VenusLocker Ransomware组织,ROKRAT远控
- Android 判断是否是刘海屏
- 获取android已安装的应用PackageInfo启动第三方APP应用
- 如何分析PARSEC源码
- 【BUG】org.json.JSONException: A JSONObject text must begin with ‘{‘ at character 1 of {
- <漫漫Android路>AOSP源码获取编译及问题处理
热门文章
- java实现avg函数_PostgreSQL avg()函数
- 196.删除重复的电子邮箱
- iis启动服务时提示在本地计算机 无法启动iis admin服务,无法启动IIS Express Web服务器...
- php网站推送消息到公众号,公众号php推送消息
- linux php5.3安装教程,Linux下安装MySql+Apache2+PHP5.3.1教程_PHP教程
- 字符串中拼接v-for_C#中几种拼接字符串的方法
- rs485如何使用_气体检测仪rs485和4-20ma接线方式有什么区别,该如何选择最优的接线方式...
- jar命令成功完成 java -jar 命令却提示“没有主清单属性”!
- 机器学习系列(5)_从白富美相亲看特征预处理与选择(上)
- org.apache.hadoop.hbase.mapreduce.Driver 导入数据到HBASE table