Java三大框架之——Hibernate中的三种数据持久状态和缓存机制
Hibernate中的三种状态
瞬时状态:刚创建的对象还没有被Session持久化、缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID。
持久状态:对象经过Session持久化操作,缓存中存在这个对象的数据为持久状态并且数据库中存在这个对象对应的数据为持久状态这个时候有OID。
游离状态:当Session关闭,缓存中不存在这个对象数据而数据库中有这个对象的数据并且有OID为游离状态。
注:OID为了在系统中能够找到所需对象,我们需要为每一个对象分配一个唯一的表示号。在关系数据库中我们称之为关键字,而在对象术语中,则叫做对象标识
(Object identifier-OID).通常OID在内部都使用一个或多个大整数表示,而在应用程序中则提供一个完整的类为其他类提供获取、操作。
Hibernate数据状态图:
需要注意的是:
当对象的临时状态将变为持久化状态。当对象在持久化状态时,它一直位于 Session 的缓存中,对它的任何操作在事务提交时都将同步到数据库,因此,对一个已经持久的对象调用 save() 或 update() 方法是没有意义的。
Student stu = new Strudnet(); stu.setCarId(“200234567”); stu.setId(“100”); // 打开 Session, 开启事务 //将stu对象持久化操作
session.save(stu); stu.setCardId(“20076548”); //再次对stu对象进行持久化操作
session.save(stu); // 无效 session.update(stu); // 无效 // 提交事务,关闭 Session
Hibernate缓存机制
什么是缓存?
缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
缓存有什么好处?
缓存的好处是降低了数据库的访问次数,提高应用性能,减少了读写数据的时间
什么时候适合用缓存?
程序中经常用到一些不变的数据内容,从数据库查出来以后不会去经常修改它而又经常要用到的就可以考虑做一个缓存,以后读取就从缓存来读取,而不必每次都去查询数据库。因为硬盘的速度比内存的速度慢的多。从而提高了程序的性能,缓存的出现就会为了解决这个问题
Hibernate中的缓存
Hibernate中的缓存包括一级缓存(Session缓存)、二级缓存(SessionFactory缓存)和查询缓存。
一级缓存(Session缓存)
由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。Session级缓存是必需的,不允许而且事实上也无法卸除。在Session级缓存中,持久化类的每个实例都具有唯一的OID。
当应用程序调用Session的save()、update()、savaeOrUpdate()、get()或load(),以及调用查询接口的list()、iterate()或filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。
当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。
Session为应用程序提供了两个管理缓存的方法:evict(Object obj):从缓存中清除参数指定的持久化对象。clear():清空缓存中所有持久化对象。
public static void testOneLeveCache(){
Session session=HibernateUtil.getSession();
//获取持久化对象Dept
Dept d1=(Dept)session.get(Dept.class, 10);
//再次获取持久化对象Dept
Dept d2=(Dept)session.get(Dept.class, 10);
session.close();
}
通过Session的get()方法获取到了Dept对象默认会将Dept对象保存到一级缓存中(Session缓存) 当第二次获取的时候会先从一级缓存中查询对应的对象(前提是不能清空或关闭Session否则一级缓存会清空或销毁)如果一级缓存中存在相应的对象就不会到数据库中查询 所以只执行一次查询的查询代码如下:
Hibernate:
select
dept0_.DEPTNO as DEPTNO0_0_,
dept0_.DNAME as DNAME0_0_,
dept0_.LOC as LOC0_0_
from
SCOTT.DEPT dept0_
where
dept0_.DEPTNO=?
如何清除一级缓存?
通过session.clear();//清除所有缓存
session.evict();//清除指定缓存
public static void testOneLeveCache(){
Session session=HibernateUtil.getSession();
SessionFactory sf = HibernateUtil.getSessionFactory();
//获取持久化对象Dept
Dept d1=(Dept)session.get(Dept.class, 10);
session.clear();//清除所有缓存
session.evict(d1);//清除指定缓存
//再次获取持久化对象Dept
Dept d2=(Dept)session.get(Dept.class, 10);
session.close();
}
使用session.evict(Object obj)会删除指定的Bean所以当你查询被你删除二级缓存的Bean时也会执行两条SQL语句
使用Session.clear()清除后会发现执行了两条SQL语句:
Hibernate:
select
dept0_.DEPTNO as DEPTNO0_0_,
dept0_.DNAME as DNAME0_0_,
dept0_.LOC as LOC0_0_
from
SCOTT.DEPT dept0_
where
dept0_.DEPTNO=?
Hibernate:
select
dept0_.DEPTNO as DEPTNO0_0_,
dept0_.DNAME as DNAME0_0_,
dept0_.LOC as LOC0_0_
from
SCOTT.DEPT dept0_
where
dept0_.DEPTNO=?
二级缓存(SessionFactory缓存)
由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。
save、update、saveOrupdate、load、get、list、query、Criteria方法都会填充二级缓存
get、load、iterate会从二级缓存中取数据session.save(user)
如果user主键使用“native”生成,则不放入二级缓存.
第二级缓存是可选的,是一个可配置的插件,默认下SessionFactory不会启用这个插件。Hibernate提供了org.hibernate.cache.CacheProvider接口,它充当缓存插件与Hibernate之间的适配器。
Hibernate的二级缓存策略的一般过程如下:
1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。
2) 把获得的所有数据对象根据ID放入到第二级缓存中。
3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照ID放入到缓存。
4) 删除、更新、增加数据的时候,同时更新缓存。
Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的查询缓存(Query Cache)。
配置二级缓存(SessionFactory缓存):
在hibernate.cfg.xml中配置以下代码
<!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 为hibernate指定二级缓存的实现类 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
指明哪些类需要放入二级缓存,需要长期使用到的对象才有必要放入二级缓存放入二级缓存的方式有两种:
1.在hibernate.cfg.xml中配置
<class-cache class="entity.PetInfo" usage="read-only" /> //不允许更新缓存中的对象
<class-cache class="entity.PetInfo" usage="read-write" /> //允许更新缓存中的对象
2.在Bean.hbm文件中配置
<hibernate-mapping>
<class name="com.bdqn.entity.Dept" table="DEPT" schema="SCOTT" >
<cache usage="read-only"/>//将这个类放入二级缓存
<id name="deptno" type="java.lang.Integer">
<column name="DEPTNO" precision="2" scale="0" />
<generator class="assigned"></generator>
</id>
<property name="dname" type="java.lang.String">
<column name="DNAME" length="14" />
</property>
</class>
</hibernate-mapping>
在ehcache.xml配置文件中可以设置缓存的最大数量、是否永久有效、时间等
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
如何清除二级缓存?
需要用SessionFactory来管理二级缓存代码如下:
sessionFactory.evict(Entity.class);//清除所有Entity sessionFactory.evict(Entity.class,id);//清除指定Entity
比如:
//用SessionFacotry管理二级缓存 SessionFactory factory=HibernateUtils.getSessionFactory(); //evict()把id为1的Student对象从二级缓存中清除. factory.evict(Student.class, 1);
//evict()清除所有二级缓存. factory.evict(Student.class);
什么样的数据适合存放到第二级缓存中?
1) 很少被修改的数据
2) 不是很重要的数据,允许出现偶尔并发的数据
3) 不会被并发访问的数据
4) 常量数据
不适合存放到第二级缓存的数据?
1) 经常被修改的数据
2) 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3) 与其他应用共享的数据。
查询缓存(Query Cache)
hibernate的查询缓存是主要是针对普通属性结果集的缓存, 而对于实体对象的结果集只缓存id。
在一级缓存,二级缓存和查询缓存都打开的情况下作查询操作时这样的:
查询普通属性,会先到查询缓存中取,如果没有,则查询数据库;查询实体,会先到查询缓存中取id,如果有,则根据id到缓存(一级/二级)中取实体,如果缓存中取不到实体,再查询数据库。
在hibernate.cfg.xml配置文件中,开启查询缓存
<!-- 是否开启查询缓存,true开启查询缓存,false关闭查询缓存 -->
<property name="cache.use_query_cache">true</property>
开启查询缓存后还需要在程序中进行启用查询缓存
public static void testQueryCache(){
Session session=HibernateUtil.getSession();
String hql="from Emp as e";
Query query=session.createQuery(hql);
query.setCacheable(true);//启用查询缓存(二级缓存)
List<Emp> empList=query.list();
session.close();
}
查询缓存是基于二级缓存机制如果根据Bean的属性查询可以不开启二级缓存代码如下:
session = HibernateUtils.getSession();
t = session.beginTransaction();
Query query = session.createQuery("select s.name from Student s");
//启用查询缓存
query.setCacheable(true);
List<String> names = query.list();
for (Iterator<String> it = names.iterator(); it.hasNext();) {
String name = it.next();
System.out.println(name);
}
System.out.println("================================");
query = session.createQuery("select s.name from Student s");
//启用查询缓存
query.setCacheable(true);
//没有发出查询语句,因为这里使用的查询缓存
names = query.list();
for (Iterator<String> it = names.iterator(); it.hasNext();) {
String name = it.next();
System.out.println(name);
}
t.commit();
Java三大框架之——Hibernate中的三种数据持久状态和缓存机制的更多相关文章
- Hibernate中的三种数据状态
Hibernate中的三种数据状态(临时.持久.游离) 1.临时态(瞬时态) 不存在于session中,也不存在于数据库中的数据,被称为临时态. 比如:刚刚使用new关键字创建出的对象. 2.持久态 ...
- 浅谈Hibernate中的三种数据状态
Hibernate中的三种数据状态:临时.持久.游离 1.临时态(瞬时态) 不存在于session中,也不存在于数据库中的数据,被称为临时态. 数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器 ...
- Java三大框架之——Hibernate关联映射与级联操作
什么是Hibernate中的关联映射? 简单来说Hibernate是ORM映射的持久层框架,全称是(Object Relational Mapping),即对象关系映射. 它将数据库中的表映射成对应的 ...
- java三大框架——Struts + Hibernate + Spring
Struts主要负责表示层的显示 Spring利用它的IOC和AOP来处理控制业务(负责对数据库的操作) Hibernate主要是数据持久化到数据库 再用jsp的servlet做网页开发的时候有个 w ...
- Java三大框架之——Hibernate
什么是Hibernate? Hibernate是基于ORM(O:对象,R:关系,M:映射)映射的持久层框架,是一个封装JDBC的轻量级框架,主要实现了对数据库的CUPD操作. 注:CRUD是指在做计算 ...
- java三大框架之一hibernate使用入门
综述:Hibernate的作用就是让实体类与数据库映射,使数据持久化,用于替代JDBC,使我们不致于写那么多sql语句代码. 1. 首先在官网www.hibernate.org下载hibernate包 ...
- Java_Web三大框架之Hibernate+jsp+selvect+HQL查询数据
俗话说:"好记性不如烂笔头".本人学习Hibernate也有一个星期了,对Hibernate也有一个初步的了解.下面对Hibernate显示数据做个笔记,使用租房系统的Hibern ...
- Java集合框架Collection(1)ArrayList的三种遍历方法
ArrayList是java最重要的数据结构之一,日常工作中经常用到的就是ArrayList的遍历,经过总结,发现大致有三种,上代码: package com.company; import java ...
- python网络爬虫数据中的三种数据解析方式
一.正则解析 常用正则表达式回顾: 单字符: . : 除换行以外所有字符 [] :[aoe] [a-w] 匹配集合中任意一个字符 \d :数字 [0-9] \D : 非数字 \w :数字.字母.下划线 ...
随机推荐
- java springMVC SSM 操作日志 4级别联动 文件管理 头像编辑 shiro redis
A 调用摄像头拍照,自定义裁剪编辑头像 B 集成代码生成器 [正反双向](单表.主表.明细表.树形表,开发利器)+快速构建表单; 技术:313596790freemaker模版技术 ,0个代码不用写 ...
- Javascript学习笔记
Javascript 2016年12月19日整理 JS基础 Chapter1 JS是一门运行在浏览器客户端的脚本编程语言,前台语言 组成部分 1. ECMAscript JS标准 2. DOM 通过J ...
- CSS三个定位——常规、浮动、绝对定位
.dage { width: 868px; background: #5B8C75; border: 10px solid #A08C5A; margin-top: -125px; margin-le ...
- 【干货分享】流程DEMO-采购预算编制
流程名: 采购预算编制 业务描述: 在月初由计财部进行预算编辑,提交审批后预算生效 流程相关文件: 流程包.xml WebService业务服务.xml WebService.asmx WebSe ...
- CSS3 nth 伪类选择器
考察下面的 HTML 代码片段: <div> <section>section 1</section> <section>section 2</s ...
- ABP(现代ASP.NET样板开发框架)系列之3、ABP分层架构
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之3.ABP分层架构 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...
- Atitit 图像处理 调用opencv 通过java api attilax总结
Atitit 图像处理 调用opencv 通过java api attilax总结 1.1. Opencv java api的支持 opencv2.4.2 就有了对java api的支持1 1. ...
- WCF学习之旅—TcpTrace工具(二十五)
前面的几篇文章,我们学习了怎么开发WCF应用程序与服务,也学习了如何进行WCF的配置.对于Web Service与WCF服务应用,服务端与客户端的通信是通过收发SOAP Message进行,我们如何有 ...
- 【.net 深呼吸】自定义特性(Attribute)的实现与检索方法
在.net的各个语言中,尤其是VB.NET和C#,都有特性这一东东,具体的概念,大家可以网上查,这里老周说一个非标准的概念——特性者,就是对象的附加数据.对象自然可以是类型.类型成员,以及程序集. 说 ...
- SQL多表连接查询(详细实例)
转载博客:joeleo博客(http://www.xker.com/page/e2012/0708/117368.html) 本文主要列举两张和三张表来讲述多表连接查询. 新建两张表: 表1:stud ...