hibernate - 一级缓存和三种状态解析
转载自:http://www.cnblogs.com/whgk/p/6103038.html
一、一级缓存和快照
什么是一级缓存呢?
很简单,每次hibernate跟数据库打交道时,都是通过session来对要操作的对象取得关联,然后在进行操作,那么具体的过程是什么样的呢?
1、首先session将一个对象加入自己的管理范围内,其实也就是把该对象放入自己的一级缓存中,例如,session.save(xxx);这个语句就是将xxx保存在自己的一级缓存中,等待事务提交后,hibernate才真正的发sql语句,对数据库进行操作。注意:session进行操作的时候,是将对象加入自己的一级缓存,并不是就直接跟数据库打交道了。
2、在一级缓存中会做些什么事情呢?为什么能够知道是发insert、还是update又或者delete呢?那这里就要提到一个快照的概念了,讲讲内部是什么原理。
举例来说明问题吧。
session.save()
User user = new User();
user.setUsername("xiaoming");
user.setPassword("123"); session.save(user);//加入了一级缓存,这其中做了什么事情呢?看图
user.setUsername("baibai");//那这里改了user的属性,具体会发生什么事情呢
//提交事务
tx.commit();
//关闭session,持久化对象就会变为脱管状态。
session.close();
发送的sql语句
//insert语句
Hibernate:
insert
into
user
(username, password, c_id)
values
(?, ?, ?)
//update语句
Hibernate:
update
user
set
username=?,
password=?,
c_id=?
where
id=?
session.get()
//通过图中分析,通过select语句查询,并且user会在session的一级缓存中,
User user =(User)session.get(User.class, "8");
//会发出update语句。
user.setUsername("heihei");
分析图
结果
//select语句
Hibernate:
select
user0_.id as id0_0_,
user0_.username as username0_0_,
user0_.password as password0_0_,
user0_.c_id as c4_0_0_
from
user user0_
where
user0_.id=?
//update语句
Hibernate:
update
user
set
username=?,
password=?,
c_id=?
where
id=?
在举一个例子说明有一级缓存的存在,对于缓存来说,肯定有对缓存的一些操作,比如evict(xx)清除xx缓存、clear():清除一级缓存中所有数据、flush()刷出一级缓存(也就是不用事务提交缓存就刷出来了,就会发sql语句,事务提交也是一个刷出缓存的方法,) 就用上面这个get的例子
session.evict()
//通过图中分析,通过select语句查询,并且user会在session的一级缓存中,
User user =(User)session.get(User.class, "15");
//将user移除session一级缓存
session.evict(user);
//不会发出update语句。
user.setUsername("heihei");
结果就发送一条select查询语句
Hibernate:
select
user0_.id as id0_0_,
user0_.username as username0_0_,
user0_.password as password0_0_,
user0_.c_id as c4_0_0_
from
user user0_
where
user0_.id=?
总结一下:通过上面的例子和讲解,我们应该知道,并不是session一操作对象,就立马会发sql语句,而是先将其保存到自己内部的一级缓存中,如果不手动刷出缓存,就会等待事务提交时刷出缓存,然后再进行发送sql语句,对数据库进行操作。并且其中有一个快照区需要知道是干嘛的,理解了快照区,就可以知道每次会发送几条sql语句。注意一点,session每次操作的是在一级缓存中的对象,不会操作快照区中的对象,快照区只是用来当作比较的一个地方,当对象加入一级缓存之后,外部在怎么改变,也只是改变快照区中的数据,并不是改变一级缓存中对象的属性。这点就记清楚。如果还不是很清楚,等下面在带你们看几个例子,就瞬间明白了。
二、hibernate中对象的三种状态
瞬时状态transient、持久状态(托管)persistent、游离(脱管)detached状态
注意:托管、脱管要分清楚,分不清楚就用持久和游离
瞬时状态:使用new操作符初始化的对象的状态就是瞬时的,
1、在数据库表中,没有任何一条数据与它对应
2、不在session的缓存中
持久状态:在session的缓存中,
1、在session的缓存中(注意,很多书上都觉得持久化状态都在数据库表中有相应记录,这个是错误的,比如一个瞬时状态的对象刚被session.save(),事务还没提交,此时瞬时状态就已经变为持久化状态了,但是在数据库中还没有记录)
2、在数据库中可能有记录。
脱管状态:从session的缓存中移除出来了
1、是从session缓存中出来的,也就是从持久状态转变而来的,没有别的方式能到达游离(脱管)状态,只有这一种。
2、不在session的管理范围内
3、在数据库中有记录
根据上面的文字性描述,可能还不太理解,那现在根据我画的图和官方给予的图来加深印象吧。
误区1、很多书上觉得通过id值就可以判断对象是在哪个状态,比如说,没有id值,就是瞬时状态,有id并且在session管理范围内,就是持久状态,有id不在session范围内就是脱管状态,
解释:从上面的解释来看,瞬时状态变为脱管状态,只要加上id就行了,但是从官方图来说,瞬时状态不能直接变为游离状态,而游离状态可以通过delete直接到达瞬时状态(其实说直接,也是先将游离状态的对象加入到session缓存中变为持久状态,然后delete,在变为瞬时状态而已。),那么上面所用的通过有没有id值来判断三种状态就是有偏差的,可以这么理解,瞬时状态在数据库中就一定没有对应的记录,而游离状态一定是通过持久状态转变而来的,并且在数据库中可能有记录(没有记录是因为多线程,有别的程序把那条记录给删除了,所以一般就觉得是有记录的),所以瞬时状态和游离状态的区分点就在:从什么转变而来的,如果直接new的,那么就是瞬时状态对象,如果从持久态转变的,那么就是游离状态。
误区2:很多书上或者博客中会说识别是不是持久化状态,是看在session缓存内,还有就是在数据库中有记录。
解释:这里的前半句对,但是后半句错误,持久状态可能在数据库中有记录,也可能在数据库中没有记录,说说没有记录的时候吧,就是当session.save保存瞬时状态时,事务还没有提交,对象还只是在session的一级缓存中,数据库中就没有该记录,但此时它就已经是持久状态对象了。
误区3:认为session一操作,就会发出sql语句,这个上面已经说明白了,应该很清楚了。
小总结一下:怎么区分这三种状态
1、如果是在session缓存中,那么就一定是持久状态
2、如果是刚new出来的对象,那么就肯定是瞬时状态
3、如果是从session缓存中出来的,也就是通过一些session.clear、ecivt等操作,清除了缓存的,那么就是游离状态,
只有瞬时状态能确定数据库中没有对应记录,其他两个状态,都是不确定数据库中是否有对应记录
一切都以官方给出的图为准,其他的快速识别状态的方法,我认为是不可取的,自己还是没弄明白其中的道理,也就永远没把握自己是不是对的。
讲了那么久的理论,现在就通过那张官方给的图,让我们来实验试验各种状态间的转换吧。
1、怎么变成瞬时状态、和如何从瞬时状态变为持久状态?
User user = new User();//瞬时状态
user.setUsername("aaa");//瞬时状态
session.save(user);//持久状态,这里使用saceOrUpdate也一样。将user放在session的一级缓存中,快照区也有一份
//提交事务
tx.commit();//事务提交之后,才发送sql语句
//关闭session
session.close();//session关闭后,user就变为游离(脱管)状态了
2、怎么直接变为持久状态
//从数据库中查询id为7的用户,并且此时user在session的一级缓存中,快照区也有一份一样的
User user = (User) session.get(User.class, "7"); //提交事务
tx.commit();
//关闭session,持久化对象就会变为脱管状态。
session.close();
3、持久状态变为瞬时状态
//并且user会在session的一级缓存中,持久状态,快照区也有一份一样的
User user =(User)session.get(User.class, "15");
//将user移除session一级缓存,并且从数据库中删除该记录,快照区中的对象也删除了,所以变成瞬时状态而不是变成游离状态
session.delete(user);
//不会发出update语句。改变的只是瞬时状态的属性
user.setUsername("heihei");
4、持久状态变为游离状态
//并且user会在session的一级缓存中,持久状态,快照区中也有一份一样的
User user =(User)session.get(User.class, "15");
//将user移除session一级缓存,并没有删除数据库记录,所以变为了游离状态,清除缓存,那么快照区中也没了
session.evict(user);
//不会发出update语句。改变的只是游离状态的属性,没影响
user.setUsername("heihei");
5、游离状态变为持久状态
//并且user会在session的一级缓存中,持久状态,快照区有一份一样的
User user =(User)session.get(User.class, "15");
//将user移除session一级缓存,并没有删除数据库记录,所以变为了游离状态。快照区中也没了
session.evict(user);
//不会发出update语句。改变的只是游离状态的属性,没影响
user.setUsername("heihei");
//会发出update语句进行更新,重新回到持久状态。加入到一级缓存中。快照区中也有一份一样的。
session.update(user);
//猜一下这里会不会发两条update语句?如果觉得是两条的话,就没记住我说的话,肯定是一条update语句呀,自己可以看上面讲解快照区时的图片,这里改变了快照区中user的属性,
//因为上面用的是update方法,快照区会先跟一级缓存中的对比,如果有不一样,那么就发送update语句,而不会先发一个update然后再对比,不一样在发update,跟insert不一样。
user.setUsername("sss");
6、游离状态变为瞬时状态
这个也没什么好讲的,上面已经分析过了,游离状态直接变为瞬时状态其实也就是先进过持久状态,然后再变为瞬时状态。
三、经过上面的学习,现在深入一点,让你知道会发送多少条sql语句。
1、Test01
session = HibernateUtil.openSession();
session.beginTransaction();
User user = new User();
user.setUsername("aaa");
user.setPassword("aaa");
user.setBorn(new Date());
//以上u就是Transient(瞬时状态),表示没有被session管理并且数据库中没有
//执行save之后,被session所管理,而且,数据库中已经存在,此时就是Persistent状态
session.save(user);
//此时u是持久化状态,已经被session所管理,当在提交时,会把session中的对象和快照区的对象进行比较
//如果两个对象中的值不一致就会继续发出相应的sql语句
user.setPassword("bbb");
//此时会发出2条sql,一条用户做插入,一条用来做更新
session.getTransaction().commit();
Hibernate: insert into t_user (born, password, username) values (?, ?, ?)
Hibernate: update t_user set born=?, password=?, username=? where id=?
Test02
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
session = HibernateUtil.openSession();
session.beginTransaction();
User u = new User();
u.setBorn(new Date());
u.setUsername("zhangsan");
u.setPassword("zhangsan");
session.save(u);
u.setPassword("222");
//该条语句没有意义
session.save(u);
u.setPassword("zhangsan111");
//没有意义
session.update(u);
u.setBorn(sdf.parse("1988-12-22"));
//没有意义
session.update(u);
session.getTransaction().commit();
没有意义是什么意思呢?记得我一开始说的那个注意点嘛,所有的操作都会先存放在session的一级缓存中,当对象进入一级缓存中,在怎么改变属性,都只改变快照区中对象的属性,在用session进行操作,还是操作的一级缓存中的对象,记住了这一点,那么上面的程序就简单了,u保存到了缓存中,u改变属性,session在save u没一点意义,并且连续改改,也只是改快照区中的属性,等到事务提交的时候,在做对比和进行相应的操作。
Hibernate: insert into t_user (born, password, username) values (?, ?, ?)
Hibernate: update t_user set born=?, password=?, username=? where id=?
Test03
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
session = HibernateUtil.openSession();
session.beginTransaction();
User u = new User();
u.setId(5);
//完成update之后也会变成持久化状态
session.update(u);
u.setBorn(sdf.parse("1998-12-22"));
u.setPassword("lisi");
u.setUsername("lisi");
//会抛出异常
u.setId(333);
session.getTransaction().commit();
这个例子会报异常,就是上面我说过的,在一级缓存中的对象,如果改变快照区中的id属性,就会报异常
hibernate - 一级缓存和三种状态解析的更多相关文章
- hibernate(二)一级缓存和三种状态解析
序言 前一篇文章知道了什么是hibernate,并且创建了第一个hibernate工程,今天就来先谈谈hibernate的一级缓存和它的三种状态,先要对着两个有一个深刻的了解,才能对后面我要讲解的一对 ...
- Hibernate学习(二)———— 一级缓存和三种状态解析
一.一级缓存和快照 什么是一级缓存呢? 很简单,每次hibernate跟数据库打交道时,都是通过session来对要操作的对象取得关联,然后在进行操作,那么具体的过程是什么样的呢? 1.首先sessi ...
- Hibernate一级缓存和三种状态
Hibernate一级缓存又称session缓存,生命周期很短,跟session生命周期相同. 三种状态:1.transient(瞬时态):刚new出来的对象,既不在数据库中,也不在session管理 ...
- 一级缓存、二级缓存、延迟加载、hibernate session 域 pojo三种状态
1.一级缓存(session缓存 ).二级缓存 意义:提高hibernate查询效率. 缺点:可能会因并发,产生数据不一致. 本质:基于session 的缓存,利用hiber ...
- Hibernate持久化对象的三种状态深入理解
关于OID hibernate缓存是一个map,他会根据OID作为缓存对象的key,我们的映射文件中<id>标签指定的属性值会作为OID 持久化对象的三种状态 为了方便理解,Hiberna ...
- 【SSH系列】-- Hibernate持久化对象的三种状态
在上一篇博文中,小编主要简单的介绍了[SSH系列]--hibernate基本原理&&入门demo,今天小编来继续介绍hibernate的相关知识, 大家知道,Java对象的生命周期,是 ...
- Hibernate之对象的三种状态
Hibernate之Java对象的三种状态 一.简述 本博文大部分的思想和内容引子CSND上名为 FG2006 这位大神的文章,连接地址为:http://blog.csdn.net/fg2006/ar ...
- Hibernate中对象的三个状态解析
Hibernate 将操作的对象分为三种状态: 1. 瞬时 (Transient )/临时状态/自由状态 持久 (Persistent) 脱管 (Detached) 瞬时对象特征: 第一.不处于 Se ...
- hibernate一级缓存及对象的状态
hibernate中实体类对象的状态 在hibernate中实体类对象有三种状态 (1)瞬时态(临时态) 瞬时态:即我们自己创建一个对象,还没有保存到数据库就叫临时态,其实也可以说是对像没有id值,跟 ...
随机推荐
- PyQt4测试安装ok的程序
# -*- coding: utf-8 -*- """ ------------------------------------------------- File Na ...
- Cookie用法简介
java操作Cookie---javax.servlet.http.Cookie 1.增加一个Cookie Cookie cookie = new Cookie("username" ...
- Ajax在jQuery中的应用---加载异步数据
Ajax是Asynchronous JavaScript and XML的缩写,其核心是通过XMLHttpRequest对象,以一种异步的方式,向服务器发送数据请求,并通过该对象接收请求返回的数据,从 ...
- 基于IG的特征评分方法
本文简单介绍了熵.信息增益的概念,以及如何使用信息增益对监督学习的训练样本进行评估,评估每个字段的信息量. 1.熵的介绍 在信息论里面,熵是对不确定性的测量.通俗来讲,熵就是衡量随机变量随 ...
- Docker容器技术-基础命令
一.基础命令 1.运行一个镜像 [root@bogon ~]# docker run debian echo "Hello World" Unable to find image ...
- nodejs爬虫selenium
6.元素操作 查找元素 使用操作如何找到页面元素Webdriver的findElement方法可以用来找到页面的某个元素,最常用的方法是用id和name查找.下面介绍几种比较常用的方法. By ID假 ...
- matplotlib模块之plot画图
关于matplotlib中一些常见的函数,https://www.cnblogs.com/TensorSense/p/6802280.html这篇文章讲的比较清楚了,https://blog.csdn ...
- [Android]开源中国源码分析之二---DrawerLayout
从启动界面到主界面之后的效果如图所示,采用的是v4包下的DrawerLayout, activity_main.xml文件如下: <!-- A DrawerLayout is intended ...
- JQuery 操作 iframe
JQuery访问iframe内的元素 $("iframe#Main", top.document).contents().find("#id"); JQuery ...
- 在Java项目中部署使用Memcached[转]
在项目中使用到Memcached主要的目的是,通过缓存数据库查询结果,减少数据库访问次数,从而提高动态.数据库驱动网站的速度.提高可扩展性.Memcached是一个高性能的分布式内存对象缓存系统,基于 ...