摘自 http://blog.csdn.net/csh624366188/article/details/7612142

    Hibernate 的Session就是其中的一个,它提供了基本的增,删,改,查方法.而且具有一个缓存机制,能够按照某个时间点,按照缓存中的持久化对象属性的变化来更新数据库,这就是Session的缓存清理过程.

在Hibernate中对象分为三个状态,临时,持久化,游离.如果我们希望JAVA里的一个对象一直存在,就必须有一个变量一直引用着这个对象.当这个变量没了.对象也就被JVM回收了.这篇博客我们就带大家一起来看一下session的缓存机制,也就是hibernate的一级缓存,还有hibernate三种对象状态的详细情况。

当Session的save()方法持久化一个Customer对象时,Customer对象被加入到Session的缓存中,以后即使应用程序中的引用变量不再引用Customer对象,只要Session的缓存还没有被清空,Customer对象仍然处于生命周期中。 当Session的load()方法试图从数据库中加载一个Customer对象时,Session先判断缓存中是否已经存在这个Customer对象,如果存在,就不需要再到数据库中检索。 这样就大大提高了hibernate查询的时间效率,只有当事务提交,session关闭之后,session缓存才会失效.

下面我们来通过一段代码来理解一下session缓存:

 tx = session.beginTransaction();
Customer c1=new Customer(“zhangsan",new HashSet());
//Customer对象被持久化,并且加入到Session的缓存中
session.save(c1);
Long id=c1.getId();
//c1变量不再引用Customer对象
c1=null;
//从Session缓存中读取Customer对象,使c2变量引用Customer对象
Customer c2=(Customer)session.load(Customer.class,id);
tx.commit();
//关闭Session,清空缓存
session.close();
//访问Customer对象
System.out.println(c2.getName());
// c2变量不再引用Customer对象,此时Customer对象结束生命周期。
c2=null;

session调用save保存一个对象时,这个对象就被加载到session缓存当中,其实调用save方法这里有个细节,很多人都忽略了这个细节,就是save方法有一个返回值,返回一个seriaseble接口类型的数据,我们知道像基本数据类型的包装类型都实现了这个接口,其实这个返回值我们可以理解为保存对象的id我们在很多时候都能用到这个返回值,这是一个应该注意的地方。当对象被save到缓存中时,我们就可以调用对象的getid方法来获得他的id了。在上面的示例中我们可以看到,虽然c1被复位null了,但是此时在session缓存里面还是有一个变量指向着该对象,所以该对象才不被垃圾回收器回收,当我们在此利用该对象的id去用load查询时,其实还是去到session缓存去找并且返回该对象,当session关闭后。缓存清空。

下面我们在来看一个例子,来看一下get和load的另一个不同点:

 tx = session.beginTransaction();
Customer c1=(Customer)session.load(Customer.class,new Long(1));
Customer c2=(Customer)session.load(Customer.class,new Long(1));
System.out.println(c1==c2); // true or false ??
tx.commit();
session.close();

很明显,这个示例最后打印出来的是true,因为他们获得的是同一个实例,我们具体来分析一下,我们在运行这段代码时,细心的童鞋应该会发现,利用load去查询对象时,没有生成sql语句,这是为什么呢?既然查询到结果了,为什么没有生成出来sql语句呢。这就是我们要说的load和get方法的第二个不同的地方了,load方法在查询时,其实是获得的该对象的一个代理的对象,当我们用到查询到的对象时,他才会去数据库进行查询,如上,如果我们调用c1.getName方法,这时就会打印出sql语句来,这时候他才真正的去数据库查询,而get方法,他在执行get的方法的时候就会去数据库查询,产生sql语句。

Session缓存的作用

(1)减少访问数据库的频率。应用程序从内存中读取持久化对象的速度显然比到数据库中查询数据的速度快多了,因此Session的缓存可以提高数据访问的性能。

(2)保证缓存中的对象与数据库中的相关记录保持同步。当缓存中持久化对象的状态发生了变化,Session并不会立即执行相关的SQL语句,这使得Session能够把几条相关的SQL语句合并为一条SQL语句,以便减少访问数据库的次数,从而提高应用程序的性能。

Session的清理缓存

清理缓存是指按照缓存中对象的状态的变化来同步更新数据库,下面我们还是具体来看一段代码:以下程序代码对Customer的name属性修改了两次:

 tx = session.beginTransaction();
Customer customer=(Customer)session.load(Customer.class,
new Long(1));
customer.setName("Jack");
customer.setName("Mike");
tx.commit();

当Session清理缓存时,只需执行一条update语句: update CUSTOMERS set NAME= 'Mike'…… where ID=1;

其实第一次调用setName是无意义的,完全可以省略掉。

Session缓存在什么时候才清理呢?我们来看一下:

Session会在下面的时间点清理缓存: 

1.当应用程序调用org.hibernate.Transaction的commit()方法的时候,commit()方法先清理缓存,然后再向数据库提交事务。 

2.当应用程序显式调用Session的flush()方法的时候,其实这个方法我们几乎很少用到,因为我们一般都是在完成一个事务才去清理缓存,提交数据更改,这样我们直接提交事务就可以。

Hibernate中java对象的三种状态:

1、临时状态(transient):刚刚用new语句创建,还没有被持久化,不处于Session的缓存中。处于临时状态的Java对象被称为临时对象。

2、持久化状态(persistent):已经被持久化,加入到Session的缓存中。处于持久化状态的Java对象被称为持久化对象。

3、游离状态(detached):已经被持久化,但不再处于Session的缓存中。处于游离状态的Java对象被称为游离对象。

持久化状态和临时状态的不同点在于:

1、对象持久化状态时,他已经和数据库打交道了,在数据库里面存在着该对象的一条记录。

2、持久化状态的对象存在于session的缓存当中。

3、持久化状态的对象有自己的OID。

游离状态的对象与持久化状态的对象不同体现在游离状态的对象已经不处于session的缓存当中,并且在数据库里面已经不存在该对象的记录,但是他依然有自己的OID。

对象的状态转换

我们一起来分析一下这个状态转换图,首先一个对象被new出来之后,他是出于临时状态的,然后调用save或者saveOrUpdate方法把对象转换为持久化状态,这里的saveOrUpdate方法其实是一个偷懒的方法,我们以前用的所有的save方法的地方都可以修改为该方法,这个方法是在保存数据之前先查看一下这个对象是什么状态,如果是临时状态就保存,如果是游离状态就进行更新。持久化状态转换成游离状态可以是在session关闭或者被清理缓存时,在或者就是调用evict方法,这个方法就是强行把对象从session缓存中清除。游离状态装换为持久化状态可以调用update方法,其实update方法主要的功能就是把对象从游离状态装换成持久化状态的,因为一般的更新其实不用这个方法也可以。

下面我们举一个具体实例的看一下状态转换过程:

这个图需要大家仔细的理解一下,他很好的体现了对象生命周期的进程和对象状态的转换。

下面我们在用一个示例来看一下session的update方法是怎么把一个游离状态的对象装换成持久化的:

 Customer customer=new Customer();
customer.setName("Tom");
Session session1=sessionFactory.openSession();
Transaction tx1 = session1.beginTransaction();
session1.save(customer);
tx1.commit();
session1.close(); //此时Customer对象变为游离对象
Session session2=sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
customer.setName(“zhangsan") //在和session2关联之前修改Customer对象的属性
session2.update(customer);
customer.setName(“lisi"); //在和session2关联之后修改Customer对象的属性
tx2.commit();
session2.close();

当session1保存完对象,然后事务关闭时,对象就变为游离状态了,此时我们在打开一个session,利用update方法,在把对象和session关联起来,然后修改他的属性,提交事务之后,游离状态的对象一样可以修改保存到数据库中,这里虽然修改了两次对象的属性,但只会发送一条sql语句,因为update在修改对象数据时,只有在事务提交时,他才会发送sql语句进行提交。所以只有最后一条修改信息管用。

总结一下Session的update()方法完成以下操作:

(1)把Customer对象重新加入到Session缓存中,使它变为持久化对象。

(2)计划执行一个update语句。值得注意的是,Session只有在清理缓存的时候才会执行update语句,并且在执行时才会把Customer对象当前的属性值组装到update语句中。因此,即使程序中多次修改了Customer对象的属性,在清理缓存时只会执行一次update语句。

Web应用程序客户层和业务逻辑层之间传递临时对象和有利对象的过程:


Session的二级缓存 

Hibernate提供了两级缓存,第一级缓存是Session的缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必须的,不允许而且事实上也无法被卸除。在第一级缓存中,持久化类的每个实例都具有惟一的OID。 第二级缓存是一个可插拔的缓存插件,它由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个进程对应,因此第二级缓存是进程范围的缓存。这个缓存中存放的是对象的散装数据。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。

Hibernate二级缓存结构

[转]session缓存机制和三种对象状态的更多相关文章

  1. 全面剖析Smarty缓存机制一[三种缓存方式]

    今天主要全面总结下Smarty模板引擎中强大的缓存机制,缓存机制有效减少了系统对服务器的压力,而这也是很多开发者喜欢Smarty的原因之一,由于篇幅较大,便于博友阅读,这篇文章将剖析Smarty缓存的 ...

  2. PHP 中Session 反序列化机制的三种方法

    �php.ini中存在三项配置项: session.save_path="" --设置session的存储路径 session.save_handler=""- ...

  3. Hibernate中的三种数据状态

    Hibernate中的三种数据状态(临时.持久.游离) 1.临时态(瞬时态) 不存在于session中,也不存在于数据库中的数据,被称为临时态. 比如:刚刚使用new关键字创建出的对象. 2.持久态 ...

  4. 浅谈Hibernate中的三种数据状态

    Hibernate中的三种数据状态:临时.持久.游离 1.临时态(瞬时态) 不存在于session中,也不存在于数据库中的数据,被称为临时态. 数据库中没有数据与之对应,超过作用域会被JVM垃圾回收器 ...

  5. 命令stat anaconda-ks.cfg会显示出文件的三种时间状态(已加粗):Access、Modify、Change。这三种时间的区别将在下面的touch命令中详细详解:

    7.stat命令 stat命令用于查看文件的具体存储信息和时间等信息,格式为"stat 文件名称". stat命令可以用于查看文件的存储信息和时间等信息,命令stat anacon ...

  6. 【Hibernate框架】对象的三种持久化状态

    一.综述 hibernate中的对象有三种状态,分别是TransientObjects(瞬时对象).PersistentObjects(持久化对象)和DetachedObjects(托管对象也叫做离线 ...

  7. jQuery缓存机制(三)

    缓存机制提供的入口有: $.data([key],[value]) // 存取数据 $.hasData(elem) // 是否有数据 $.removeData([key]) // 删除数据 $.acc ...

  8. session处理超时的三种方式

    1.      在web容器中设置(此处以tomcat为例) 在tomcat-5.0.28\conf\web.xml中设置,以下是tomcat 5.0中的默认配置: <!-- ========= ...

  9. DELPHI中的消息处理机制(三种消息处理方法的比较,如何截断消息)

    DELPHI中的消息处理机制 Delphi是Borland公司提供的一种全新的WINDOWS编程开发工具.由于它采用了具有弹性的和可重用的面向对象Pascal(object-orientedpasca ...

随机推荐

  1. 101+ Manual and Automation Software Testing Interview Questions and Answers

    101+ Manual and Automation Software Testing Interview Questions and Answers http://www.softwaretesti ...

  2. matlab 字符分割

    http://blog.csdn.net/gotomic/article/details/7898307 注意到以'.'分割时,写成'\.'.前者代表其他含义.可通过help regexp来查询. 例 ...

  3. js之阻止事件冒泡(待修改)和阻止默认事件

    阻止默认事件(event.stopPropagation()): <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional// ...

  4. js对数组的操作函数

    js数组的操作 用 js有很久了,但都没有深究过js的数组形式.偶尔用用也就是简单的string.split(char).这段时间做的一个项目,用到数组的地方很多, 自以为js高手的自己居然无从下手, ...

  5. css样式兼容不同浏览器问题解决办法

    在网站设计的时候,应该注意css样式兼容不同浏览器问题,特别是对完全使用DIV CSS设计的网,就应该更注意IE6 IE7 FF对CSS样式的兼容,不然,你的网乱可能出去不想出现的效果! 所 有浏览器 ...

  6. 三 GPU 并行编程的运算架构

    前言 GPU 是如何实现并行的?它实现的方式较之 CPU 的多线程又有什么分别?本文将做一个较为细致的分析. GPU 并行计算架构 GPU 并行编程的核心在于线程,一个线程就是程序中的一个单一指令流, ...

  7. 跟开涛老师学shiro -- INI配置

    之前章节我们已经接触过一些INI配置规则了,如果大家使用过如spring之类的IoC/DI容器的话,Shiro提供的INI配置也是非常类似的,即可以理解为是一个IoC/DI容器,但是区别在于它从一个根 ...

  8. c# 多语言实现 与 InitializeCulture

    在实现多语言的时候,我们会使用GetGlobalResourceObject,在服务器控件中显示多语言文本要使用<%$ Resources:Common, Export %>, 但是在设置 ...

  9. 不容易系列之(3)—— LELE的RPG难题

    有排成一行的n个方格,用红(Red).粉(Pink).绿(Green)三色涂每个格子,每格涂一色,要求任何相邻的方格不能同色,且首尾两格也不同色.求全部的满足要求的涂法. 思路:运用递归算法. a[1 ...

  10. 关于display的那些事儿!

    关于display的那些事儿! display,display,display!嘿嘿嘿!display这一CSS属性,还是相当神奇的哦!给它设置不同的值,被修饰的标签相应的就随之变换了自身的属性特性, ...