一、概述

     Session接口是Hibernate向应用程序提供的操纵数据库最主要的接口,它提供了基本的保存、更新、删除和加载Java对象的方法。

     Session具有一个缓存,位于缓存中的对象称为持久化对象,它和数据库相关记录对应。

     Session能够在某些时间点按照缓存中对象的变化来执行相关SQL语句,来同步更新数据库,这一过程称为清理缓存(flush)。

 

二、Session的缓存

1.理解

    如果希望一个Java对象A一直处于生命周期中,就必须保证至少有一个变量引用它,或者可以从其他处于生命周期中的对象B导航到这个对象A,比如在对象B的Java集合属性存放对象A的引用。在Session接口的实现中包含了一系列的Java集合,这些Java集合构成了Session的缓存。只要Session实例没有结束生命周期,存放在它缓存中的对象也不会结束生命周期。

    

 

     当Session的save()方法持久化一个Customer对象时,Customer对象被加入到Session缓存中,以后即使应用程序中的引用变量不再引用Customer对象,只要Session的缓存没有被清空,Customer对象仍然处于生命周期中。

     当Session的get()方法试图从数据库中加载一个Customer对象时,Session先判断缓存中是否已经存在这个Customer对象,如果存在就不需要再到数据库中检索,而直接从缓存中获取这个Customer对象。

	@Test
public void testSessionCache(){
Session session = HibernateUtils.getSession();
//结果是查询了一次数据库,第二次没有查询数据库
News news1 = (News)session.get(News.class,1);
System.out.println(news1);
News news12 = (News)session.get(News.class,1);
System.out.println(news1);
}

 

2.Session缓存的作用

(1)减少访问数据库的频率

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

			//第1次执行Session的get()方法
News n1 = (News)session.get(News.class,1);
//第2次执行Session的get()方法
News n2 = (News)session.get(News.class,1);
System.out.println(n1 == n2); //true

下图显示第一次执行Session的的get()方法

    

下图显示了第二次执行Session的get()方法

    

 

(2)当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循环,以及死循环引起的JVM堆栈溢出异常。

(3)保证数据库中的相关记录与缓存中的相应对象保持同步。

     如下图对象-关系映射建立了表与类之间的静态映射,而Session建立了表与Session缓存中的对象的动态映射

    

     以下程序先把Customer对象加载到Session缓存中,然后修改Session缓存中Customer对象的属性。

			// 开启事务
tx = session.beginTransaction(); Customer c = (Customer)session.get(Customer.class,1);
c.setName("Jack"); // 提交事务
tx.commit();

     执行完后,Session中的Customer对象的name属性与Customer表对应记录的name字段值不一致了。

    

     幸运的是,Session在清理缓存时会自动进行脏检查(dirty-check),如果发现Session缓存中的对象与数据库中相应记录不一致,就会根据对象的最新属性去同步更新数据库,在本例中,Session在提交事务之前执行flush()方法清理缓存,即向数据库提交一条update语句,更新数据库中的name字段的值。

 

3.缓存清理机制

(1)Session如何进行脏检查?    

    当一个Customer对象被加入到Session缓存中时,Session会为Customer对象的值类型的属性复制一份快照。当Session清理缓存时,会先进行脏检查,即比较Customer对象的当前属性与它的快照来判断Customer对象的属性是否发生了变化,如果发生了变化,就称这个对象为“脏对象”,Session会根据脏对象的最新属性来执行相关SQL语句,从而更新到数据库。

     当Session缓存对象的属性每次发生了变化,Session并不会立即执行清理缓存及执行相关SQL语句,而是在特定的时间点才清理缓存,这使得Session能够把几条相关SQL语句合并为一条SQL语句,以便减少访问数据库的次数,从而提高应用程序的数据访问性能。

			tx = session.beginTransaction();

			Customer c = (Customer)session.get(Customer.class,1);
//当Sesion清理缓存时,不必执行两条update语句,而是执行最后一句
c.setName("Jack");
c.setName("Mary"); tx.commit();

 

(2)Session清理缓存的时间点

A: 应用程序显式调用Session的flush()方法。

B: 应用程序调用commit()方法时,在内部先执行flush()方法,再向数据库提交事务。

C: 当应用程序执行一些查询(HQL/Criteria)操作时,如果缓存中的持久化对象已经发生了变化,就会先flush,以保证查询结果为最新的状态。

 

(3)Commit()与flush()方法的区别

     flush 执行SQL语句,但不提交事务。

     commit 方法先调用flush() 方法,然后提交事务. 意味着提交事务意味着对数据库操作永久保存下来。

 

三、Hibernate的的三种状态

1.概述

     Hibernate有以下三种状态:

     临时状态(transient): 刚用new语句创建,还没有被持久化,并且不处于Session的缓存中。

     持久化状态(persistent): 已经被持久化,并且处于Session缓存中。

     游离状态(detached): 已经被持久化,但不再处于Session缓存中。

    

 

2.临时对象的特征

     (1)使用代理主键的情况下,OID通常为null。

     (2)不在Session的缓存中。

     (3)数据库没有相应的记录。

 

3.持久化对象的特征

     (1)OID不为null。

     (2)位于Session的缓存中。

     (3)持久化对象和数据库的相关记录对应。

     (4)Session在flush()缓存时,会根据持久化对象的属性变化,来同步更新数据库。

 

4.游离对象的特征

     (1)OID不为null。

     (2)不再处于Session的缓存中。

     (3)一般情况下,游离对象是由持久化对象转变而来的,所以数据库还肯存在与它相对应的记录。

 

5.对象的状态转换图

    

 

四、Session的相关API

1.save()和persist()方法

     Session的save()方法完成以下操作:

     (1)使一个临时对象变为持久化对象。

     (2)为对象分配OID。

     (3)在flush时,会发送一条insert语句。

     注意:

           A: 在执行save()方法之前,设置对象的id是无效的。

           B: 持久化对象的id是不能修改的,不然会抛异常。

	@Test
public void testSave(){ Session session = HibernateUtils.getSession();
Transaction tx = null; try{
// 开启事务
tx = session.beginTransaction(); News news = new News();
news.setTitle("DDD");
news.setAuthor("Jack");
news.setDate(new Date()); //在save之前设置id是无效的
news.setId(100);
System.out.println(news); session.save(news); System.out.println(news); //持久化对象的id是不能修改的,下面这句话报异常
news.setId(200); // 提交事务
tx.commit();
}catch(RuntimeException e){
// 回滚事务
tx.rollback();
throw e;
}finally{
// 释放资源
session.close();
}
}

     persist()方法也会执行insert语句,但是它和save()方法有点区别:

     在调用persist()方法之前,若对象有id,则不会执行insert语句,会报异常。

	@Test
public void testPersist(){ Session session = HibernateUtils.getSession();
Transaction tx = null; try{
// 开启事务
tx = session.beginTransaction(); News news = new News();
news.setTitle("CCC");
news.setAuthor("C");
news.setDate(new Date()); news.setId(100); System.out.println(news); //这句话会抛异常
session.persist(news); System.out.println(news); // 提交事务
tx.commit();
}catch(RuntimeException e){
// 回滚事务
tx.rollback();
throw e;
}finally{
// 释放资源
session.close();
}
}

 

2.get()和load()方法

     Session的get()和load()方法都能根据给定的OID从数据库加载一个持久化对象。

它们有以下区别:

(1)get()使用的是立即检索策略

    load()使用的是延迟检索策略,即load()方法返回的是只要一个id属性的代理对象,只有真正使用该对象时,才会发生SQL语句。

(2)get()如果查询不存在的记录会返回null

    load()如果查询不存在的记录则会抛异常,ObjectNotFoundException。

 

3.update()方法

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

     (1)把游离对象变为持久化对象。

     (2)无论游离对象是否和表一致,都会发生一条update语句。

			News news = new News();
news.setTitle("CCC");
session.save(news);
tx.commit(); //清理缓存,提交事务
session.close(); //此时news对象变为游离对象 Session session2 = HibernateUtils.getSession();
Transaction tx2 = session2.beginTransaction();
news.setTitle("DDD");
session2.update(news);//news对象和session2关联
news.setTitle("EEE");
tx2.commit();
session2.close();

 

4.saveOrUpdate()方法

     功能如下:

    

     (1)如果传入的是游离对象就执行update()方法。

     (2)如果传入的是临时对象就执行save()方法。

     (3)如果传入的是持久化对象,那就直接返回。

     saveOrUpdate()方法如何判断对象是临时对象还是游离对象?如果满足下列情况之一,Hibernate就把它作为临时对象,否则就作为游离对象。

     (1)OID为null。

     (2)映射文件中为<id>设置了unsaved-value属性, 并且Java对象的OID取值与这个unsaved-value 属性值匹配。

 

5.delete()方法

     (1)只要OID和数据表中一条记录对应 ,就计划执行删除操作。

     (2)若OID在数据表中没有对应记录,则抛异常。

     (3)可以设置Hibernate配置文件 hibernate.use_identifier_rollback为true,使对象删除后,把其OID置为null。

Hibernate基础学习(三)—Session的更多相关文章

  1. Hibernate基础学习2

    Hibernate基础学习2 测试hibernate的一级缓存,事务以及查询语句 1)Hibernate的一些相关概念 hibernate的一级缓存 1)缓存是为了提高该框架对数据库的查询速度 2)一 ...

  2. Python入门基础学习 三

    Python入门基础学习 三 数据类型 Python区分整型和浮点型依靠的是小数点,有小数点就是浮点型. e记法:e就是10的意思,是一种科学的计数法,15000=1.5e4 布尔类型是一种特殊的整形 ...

  3. Python基础学习三

    Python基础学习三 1.列表与元组 len()函数:可以获取列表的元素个数. append()函数:用于在列表的最后添加元素. sort()函数:用于排序元素 insert()函数:用于在指定位置 ...

  4. Django基础学习三_路由系统

    今天主要来学习一下Django的路由系统,视频中只学了一些皮毛,但是也做下总结,主要分为静态路由.动态路由.二级路由 一.先来看下静态路由 1.需要在project中的urls文件中做配置,然后将匹配 ...

  5. Hibernate学习三----------session详解

    © 版权声明:本文为博主原创文章,转载请注明出处 如何获取session对象 1. openSession 2. getCurrentSession - 如果使用getCurrentSession需要 ...

  6. Hibernate基础学习(五)—对象-关系映射(下)

    一.单向n-1 单向n-1关联只需从n的一端可以访问1的一端. 域模型: 从Order到Customer的多对一单向关联.Order类中定义一个Customer属性,而在Customer类不用存放Or ...

  7. Hibernate基础学习(四)—对象-关系映射(上)

    一.映射对象标识符      Java语言按内存地址来识别或区分同一个类的不同对象,而关系数据库按主键值来识别或区分同一个表的不同记录.Hibernate使用对象标识符(OID)来建立内存中的对象和数 ...

  8. hibernate基础学习

    转载自:http://blog.csdn.net/fb281906011/article/details/17628111 一:下载hibernate:http://hibernate.org/orm ...

  9. Hibernate基础学习(二)—Hibernate相关API介绍

    一.Hibernate的核心接口      所有的Hibernate应用中都会访问Hibernate的5个核心接口.      (1)Configuration接口: 配置Hibernate,启动Hi ...

随机推荐

  1. JS特效——图片水平滚动

    具体源码如下: <!doctype html> <html lang="en"> <head> <meta http-equiv=&quo ...

  2. Ognl值栈对象及struts标签

    用户每次访问struts的action,都会创建一个Action对象.值栈对象.ActionContext对象:然后把Action对象放入值栈中: 最后再把值栈对象放入request中,传入jsp页面 ...

  3. angular destroy & jquery destroy

    destroy的目的是为了内存溢漏,这对性能会造成影响. angular scope在处理element 移除时,会触发destroy, 而调用逻辑和jquery使用的一样. 在ck editor 中 ...

  4. Nginx rewrite(重读)

    Nginx Rewrite规则相关指令  Nginx Rewrite规则相关指令有if.rewrite.set.return.break等,其中rewrite是最关键的指令.一个简单的Nginx Re ...

  5. Angular控制器

    这里使用的是angular-1.0.1.min.js Angular的前端渲染 <div> <ul> <li ng-repeat="i in [1,2,3]&q ...

  6. Visual Studio 2017正式版发布全纪录

    又是一年发布季,微软借着Visual Studio品牌20周年之际,于美国太平洋时间2017年3月7日9点召开发布会议,宣布正式发布新一代开发利器Visual Studio 2017.同时发布的还有 ...

  7. WeMall微信商城源码插件会员卡代码详情

    WeMall微信商城源码插件会员卡代码是用于商业推广的比较有效的方式,分享了部分比较重要的代码,供技术员学习参考 Index_index.html <html> <head> ...

  8. Maven项目搭建(一):Maven初体验

    今天给大家介绍一个项目管理和综合工具:Maven. Maven: maven读作 ['meivin],本意是指可以被信任的领域专家,致力于传播知识(来自于http://en.wikipedia.org ...

  9. Django通用视图执行过程

    使用通用视图后,Django请求处理过程(以ListView为例):在我们自定义的视图中: class IndexView(ListView): template_name = 'blog/index ...

  10. 学学简单的-------------javaScript基础

    首先知道什么是JavaScript? JavaScript是一种描述性语言,也是一种基于对象和事件驱动的.并具有安全性的脚本语言. 2.JavaScript由三部分组成:①ecmascript ②Bo ...