序言

        前一篇文章知道了什么是hibernate,并且创建了第一个hibernate工程,今天就来先谈谈hibernate的一级缓存和它的三种状态,先要对着两个有一个深刻的了解,才能对后面我要讲解的一对多,一对一、多对多这种映射关系更好的理

                                               --WZY

一、一级缓存和快照

    什么是一级缓存呢?

      很简单,每次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属性,就会报异常

      在这里,推荐一个博文,如果还想看更多的例子,就进去这个文章里面看,http://www.cnblogs.com/xiaoluo501395377/p/3380270.html

        

  

hibernate(二)一级缓存和三种状态解析的更多相关文章

  1. Hibernate学习(二)———— 一级缓存和三种状态解析

    一.一级缓存和快照 什么是一级缓存呢? 很简单,每次hibernate跟数据库打交道时,都是通过session来对要操作的对象取得关联,然后在进行操作,那么具体的过程是什么样的呢? 1.首先sessi ...

  2. hibernate - 一级缓存和三种状态解析

    转载自:http://www.cnblogs.com/whgk/p/6103038.html 一.一级缓存和快照 什么是一级缓存呢? 很简单,每次hibernate跟数据库打交道时,都是通过sessi ...

  3. Hibernate一级缓存和三种状态

    Hibernate一级缓存又称session缓存,生命周期很短,跟session生命周期相同. 三种状态:1.transient(瞬时态):刚new出来的对象,既不在数据库中,也不在session管理 ...

  4. Hibernate学习2--对象的三种状态以及映射关系的简单配置

    上篇hibernate的博客总体简单梳理了对象持久化的一些思想以及hibernate中对象持久化化的方法,下面说说对象持久化过程的三种状态. 一.hibernate缓存的概念 1.session与缓存 ...

  5. Hibernate中Java对象的三种状态

                                                                                     Hibernate中Java对象的三种 ...

  6. Hibernate的工作流程以及三种状态(面试题)

    Hibernate的工作流程以及三种状态 部分转载自:http://www.cnblogs.com/fifiyong/p/6390699.html Hibernate的工作流程: 1. 读取并解析配置 ...

  7. Hibernate学习笔记2.5(Hibernate核心开发接口和三种状态)

    1.configuration(配置信息管理,产生sessionfactory) sessionfactory管理一系列的连接池 opensession 永远打开新的,需要手动close getcur ...

  8. Hibernate的工作流程以及三种状态

    Hibernate的工作流程: 1. 读取并解析配置文件 2.读取并解析映射信息,创建SessionFactory 3. 打开Sesssion 4.创建事务Transation 5. 持久化操作 6. ...

  9. Hibernate 系列 07 - Hibernate中Java对象的三种状态

    引导目录: Hibernate 系列教程 目录 1. Java对象的三种状态 当应用通过调用Hibernate API与框架发生交互时,需要从持久化的角度关注应用对象的生命周期. 持久化声明周期是Hi ...

随机推荐

  1. 最近在研究备份和虚拟磁带库(LEGATO + MHVTL + SCST + LanFree)

    最近在研究备份和虚拟磁带库(LEGATO + MHVTL + SCST + LanFree) 有些小成功,MHVTL已经搞定,SCST + LANFREE 正在继续实验中,接着就是LEGATO. 最终 ...

  2. Unicode explorer

    It can be cumbersome to work out some of the details of this by hand, so you can use the little Java ...

  3. 【Maven】Eclipse 使用Maven创建SpringMVC Web项目

    创建环境 系统:win 10 软件:eclipse,maven. 创建步骤 创建一个Maven Web项目,可以参照:[Maven]Eclipse 使用Maven创建Java Web项目 添加spri ...

  4. 如何在命令行里运行python脚本

    python是一款应用非常广泛的脚本程序语言,谷歌公司的网页就是用python编写.python在生物信息.统计.网页制作.计算等多个领域都体现出了强大的功能.python和其他脚本语言如java.R ...

  5. 【Java学习笔记】泛型

    泛型: jdk1.5出现的安全机制 好处: 1.将运行时期的问题ClassCastException转到了编译时期. 2.避免了强制转换的麻烦. <>: 什么时候用? 当操作的引用数据类型 ...

  6. VS2010中使用GDAL(一)

    初次使用visual studio 对工具不熟悉,有些步骤可以配置的 (1)在VS2005中新建win32控制台程序 testGDALconsole,(向导中附加选项不能选为空项目) 将C:\GDAL ...

  7. ElasticSearch学习笔记-01 简介、安装、配置与核心概念

    一.简介 ElasticSearch是一个基于Lucene构建的开源,分布式,RESTful搜索引擎.设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便.支持通过HTTP使用JSON进 ...

  8. CF - 405B - Domino Effect

    my english is poor 给你一列全部站立的骨牌,同时向左或向右推其中的几个 保证推得方式为: ...左,右,左,右,左... 即不存在两个相邻的又往相同方向推倒的 刚开始是从左往右一个一 ...

  9. 如何优化cocos2d程序的内存使用和程序大小:第一部分

    译者: 在我完成第一个游戏项目的时候,我深切地意识到“使用cocos2d来制作游戏的开发者们,他们大多会被cocos2d的内存问题所困扰”.而我刚开始接触cocos2d的时候,社区里面的人们讨论了一个 ...

  10. nginx+php 安装手册

    http://www.cnblogs.com/hxl2009/archive/2013/06/11/3131627.html  [mysql安装] php 安装 1: wget http://ftp. ...