对象状态

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表有这么一条记录:

		//把数据放进cache
User 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(); //关闭Session
session1.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("------"); // 第二个session
Session 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()方法,设置为查询缓存。

@Test
public 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. 总结了零基础学习Java编程语言的几个基础知识要点

    很多Java编程初学者在刚接触Java语言程序的时候,不知道该学习掌握哪些必要的基础知识.本文总结了零基础学习Java编程语言的几个基础知识要点. 1先了解什么是Java的四个方面   初学者先弄清这 ...

  3. Hibernate 缓存机制浅析

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

  4. hibernate缓存机制(转)

    原文出处:http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html 一.why(为什么要用Hibernate缓存?) Hibernate是 ...

  5. 【转】hibernate缓存:一级缓存和二级缓存

    什么是缓存? 缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能.Hibernate在进行 ...

  6. Hibernate缓存(转)

    来自:http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html 一.why(为什么要用Hibernate缓存?) Hibernate是一个 ...

  7. 初识Hibernate 缓存

    生活就像一杯咖啡,让你我慢慢的品尝,品尝它的苦涩和甘甜...... 一.什么是Hibernate缓存. 解析:白话来说就是缓存数据的容器 官方标准点缓存:是计算机领域的概念,它介于应用程序和永久性数据 ...

  8. Hibernate缓存原理与策略

    Hibernate缓存原理: 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键.简单来讲Hibernate就是对JDBC进行封装,以实现内部状态的管理,OR关系的映射等 ...

  9. [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  10. Hibernate缓存原理与策略 Hibernate缓存原理:

    Hibernate缓存原理: 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键.简单来讲Hibernate就是对JDBC进行封装,以实现内部状态的管理,OR关系的映射等 ...

随机推荐

  1. php 压缩函数gzencode gzdeflate gzcompress

    gzencode 默认使用ZLIB_ENCODING_GZIP编码,使用gzip压缩格式,实际上是使用defalte 算法压缩数据,然后加上文件头和adler32校验 gzdeflate 默认使用ZL ...

  2. [Swift]UIKit学习之警告框:UIAlertController和UIAlertView

    Important: UIAlertView is deprecated in iOS 8. (Note that UIAlertViewDelegate is also deprecated.) T ...

  3. [转]用JavaScript在浏览器中创建下载文件

    前端很多项目中,都有文件下载的需求,特别是JS生成文件内容,然后让浏览器执行下载操作(例如在线图片编辑.在线代码编辑.iPresst等. 但受限于浏览器,很多情况下我们都只能给出个链接,让用户点击打开 ...

  4. 插入排序实现&&选择排序实现

    萌新刚刚开始学习算法,第一步是学习排序,毕竟算法的四大块"排序,查找,图,字符串"里面,排序是第一位的(PS:今天才知道算法提供的只是一个程序编写思路,一直以为是一个函数,难怪传入 ...

  5. 一个简单清晰的Redis操作类

    <?php /** * redis处理的二次封装 * */ class Redis{ private $_redis; private $_config; public function __c ...

  6. CentOS下安装配置cmake

    安装环境:CentOS-6.4   安装方式:源码编译安装  软件:cmake-2.8.5.tar.gz 下载地址暂时不提供,去百度搜一下准有 安装前提 系统中已经安装了gcc. ncurses-de ...

  7. mongodb Decimal Spring data mongodb Decimal128 SpringMvc 序列化字符串 json converter

    Mongodb 3.4 就开始支持Decimal 类型,解决double的精度问题,但是不太好用,MapReduce的时候Array.sum 也不能计算 Decimal.比较坑,但是聚合可以用 Spr ...

  8. hbase存储优化

    1.上面的2张图主要说明hbase的存储特点 (1).每个值(每条记录的每一个列的值)的存储,都完整的存储了rowkey.column family.column.版本(时间戳),以及该列的值. 这样 ...

  9. Ironic中pxe driver和agent driver的区别

    历史问题: 以pxe_ipmitool 和agent_ipmitool为例,看起来似乎前者不使用ironic-python-agent,后者使用,但是实际上两者都使用ironic-python-age ...

  10. Python多进程----从入门到放弃

    Python多进程 (所有只写如何起多进程跑数据,多进程数据汇总处理不提的都是耍流氓,恩,就这么任性) (1)进程间数据问题,因为多进程是完全copy出的子进程,具有独立的单元,数据存储就是问题了 ( ...