对象状态

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【缓存】知识要点相关推荐

  1. 记录Hibernate的缓存知识

    一.Hibernate缓存的作用 Hibernate是一个持久层框架,Hibernate要经常访问物理数据库.为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能,Hibernate的缓 ...

  2. hazelcast 使用_使用HazelCast进行Hibernate缓存:JPA缓存基础知识

    hazelcast 使用 HazelCast的最大功能之一就是对Hibernate第二级缓存的支持 . JPA具有两个级别的缓存. 一级缓存在事务期间缓存对象的状态. 通过两次查询相同的对象,您必须获 ...

  3. 入门Java你需要了解的几个知识要点!

    很多Java编程初学者在刚接触Java语言程序的时候,不知道该学习掌握哪些必要的基础知识.本文小千总结了入门Java你需要知道的几个基础知识要点,希望能够对刚入门的Java新手有帮助. 一.先了解什么 ...

  4. Java虚拟机必学之四大知识要点,附学习资料

    转载自  Java虚拟机必学之四大知识要点,附学习资料 作为一位 Java 程序员,在尽情享受 Java 虚拟机带来好处的同时,我们还应该去了解和思考"这些技术特性是如何实现的", ...

  5. Hibernate缓存级别教程

    开始使用Hibernate的人们常见的问题之一就是性能,如果您没有太多的Hibernate经验,您会发现应用程序变慢的速度. 如果启用sql跟踪,您将看到有多少查询被发送到数据库,而这些查询几乎不需要 ...

  6. Hibernate缓存 - 第一级缓存

    Hibernate缓存 - 第一级缓存 欢迎使用Hibernate缓存 - 一级缓存示例教程.最近我们研究了Hibernate架构,hibernate映射以及如何使用HQL以面向对象的方式触发SQL查 ...

  7. 【计算机网络】计算机网络体系结构总结——基本知识要点汇总

    halo~我是bay_Tong桐小白 本文内容是桐小白个人对所学知识进行的总结和分享,知识点会不定期进行编辑更新和完善,了解最近更新内容可参看更新日志,欢迎各位大神留言.指点 计算机网络体系结构总结- ...

  8. 2011年计算机三级考试PC技术知识要点(32)

    2011年计算机三级考试PC技术知识要点(32) 2011年02月19日 [b]二.输出设备[/b] 1.显示器 显示器是PC机必不可少的一种输出设备,其作用是将数字信息号转化为光信 号,最终将文字与 ...

  9. 【计算机组成原理】输入输出(I/O)系统总结——基本知识要点汇总

    halo~我是bay_Tong桐小白 本文内容是桐小白个人对所学知识进行的总结和分享,知识点会不定期进行编辑更新和完善,了解最近更新内容可参看更新日志,欢迎各位大神留言.指点 [此部分内容与总线部分的 ...

  10. java编程基础_Java编程语言基础知识要点

    Java编程语言基础知识要点 Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程.下面小编整理了Java编程语言基础知识要点,希望对大家有帮 ...

最新文章

  1. Linxu安装Tomcat与Jdk并卸载自带OpenJdk
  2. Windows异常学习笔记(二)—— 内核异常处理流程用户异常的分发
  3. 高效能人士的七个习惯_《高效能人士的七个习惯》导图和读后感
  4. javascript第三天(2)
  5. SmartFox中的類型轉換
  6. Spring获取前台参数的几种方式
  7. [转]秒杀全网!研发、运营必备实用工具网站
  8. linux罗技键盘驱动下载,罗技m590驱动-罗技m590无线鼠标驱动下载 v8.10.154官方版-下载啦...
  9. 上网本之必备网络工具推荐
  10. 逻辑思维题一:条件组合覆盖
  11. rpm 如何安装mysql_如何使用rpm安装MySQL
  12. 马斯克发起投票:是否应该出售特斯拉10%的股票?超5成粉丝赞成
  13. matlab单位函数定义,MATLAB 函数(一)
  14. vb整合多个excel表格到一张_如何使用VB实现多个excel表格合并在一个EXCEL表格里面...
  15. New情报:APT28,TA505 黑产组织,VenusLocker Ransomware组织,ROKRAT远控
  16. Android 判断是否是刘海屏
  17. 获取android已安装的应用PackageInfo启动第三方APP应用
  18. 如何分析PARSEC源码
  19. 【BUG】org.json.JSONException: A JSONObject text must begin with ‘{‘ at character 1 of {
  20. <漫漫Android路>AOSP源码获取编译及问题处理

热门文章

  1. java实现avg函数_PostgreSQL avg()函数
  2. 196.删除重复的电子邮箱
  3. iis启动服务时提示在本地计算机 无法启动iis admin服务,无法启动IIS Express Web服务器...
  4. php网站推送消息到公众号,公众号php推送消息
  5. linux php5.3安装教程,Linux下安装MySql+Apache2+PHP5.3.1教程_PHP教程
  6. 字符串中拼接v-for_C#中几种拼接字符串的方法
  7. rs485如何使用_气体检测仪rs485和4-20ma接线方式有什么区别,该如何选择最优的接线方式...
  8. jar命令成功完成 java -jar 命令却提示“没有主清单属性”!
  9. 机器学习系列(5)_从白富美相亲看特征预处理与选择(上)
  10. org.apache.hadoop.hbase.mapreduce.Driver 导入数据到HBASE table