Session缓存原理


为了能够在控制台更好的看到我们的hibernate干了些什么,可以在hibernate.cfg.xml文件中写入如下配置:

<!-- print all generated SQL to the console -->
<property name="hibernate.show_sql">true</property> <!-- format SQL in log and console -->
<property name="hibernate.format_sql">true</property>

在上一篇中,我们就曾说:Session在hibernate中被称为一级缓存,Session接口的原理:

  1. 当应用程序调用Session的CRUD方法、以及调用查询接口的list()、iterate()或filter()方法时,如果在Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中

  2. 当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。

Session缓存的作用:

  1. 减少访问数据库的频率

  2. 保证缓存中的对象与数据库中的对象同步
  3. 当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循环,以及由死循环引起的JVM堆栈溢出异常

Session缓存的应用:

  1. 当应用程序调用Transaction的commit方法时,commit方法会清理缓存,然后再向数据库提交事务 ,这里使用一个例子来简单说明一下

目前数据库表中数据有:

使用JUnit测试下面的这个方法:

@Test
public void get(){
Configuration cfg=new Configuration().configure();
StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service= ssrb.build();
SessionFactory factory=cfg.buildSessionFactory(service);
Session session= factory.openSession();
Transaction tx=session.beginTransaction();
try {
Student stu=(Student)session.get(Student.class, 1);
stu.setName("lisi");
tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
}finally {
session.close();
} }

运行时,我们可以在控制台看到:

再次看看数据库表中的数据:

透过这个案例,我们可以看到调用commit()方法时,hibernate进行了事务提交并把数据永久地保存到了数据库中,变为持久态。

  1. 当应用程序中显示调用session的flush方法时,通过session的setFlushMode(FlushMode fm)方法来设定清理缓存的时间点。

(1)FlushMode.ALWAYS:在session执行查询、commit方法以及flush方法时都会清理缓存;

(2)FlushMode.AUTO:在session执行查询、commit方法以及flush方法时都会清理缓存,这与第一种在本质上没有区别;

(3)FlushMode.COMMIT:在session执行commit方法以及flush方法时都会清理缓存;

(4)FlushMode.MANUAL:只有显示地调用flush方法时才会清理缓存,其他情况都不会清理缓存;

session缓存对象的生命周期:

首先来说一说session缓存对象都有哪些状态吧:

  1. 瞬时(Transient)状态

  2. 持久化(Persistent)状态
  3. 脱管(detached)状态
  4. 移除(removed)状态

这里我们用一个图来说明:

Session的基本操作


在项目的测试包中,新建一个StudentTest2.java文件。

Session接口:

Session接口是Hibernate向应用程序提供的操作数据库的最主要的接口,它提供了基本的保存、查询、更新和删除等方法。

save()方法:

使一个瞬时状态的对象转变为持久化状态的对象。

使用JUnit测试下面的方法:

@Test
public void add() {
Configuration cfg = new Configuration().configure();
// 如果是hibernate4.0以前的版本,使用如下的方式创建SessionFactory对象
// SessionFactory factory=cfg.buildSessionFactory();
StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service = ssrb.build();
SessionFactory factory = cfg.buildSessionFactory(service);
Session session = factory.openSession();
Transaction tx = session.beginTransaction(); try {
//new 一个Student类的对象,在未执行session.save(stu1)方法时,它是瞬时对象
Student stu1 = new Student();
stu1.setName("yu zhiping");
stu1.setAge(22);
session.save(stu1);
tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
} finally {
session.close();
} }

运行,查看控制台的输出信息:

此时,stu1就由一个瞬时状态对象变为了一个持久化状态的对象,并由session来管理,位于session的缓存中。如果在save()方法后再对stu1进行操作,就是对缓存中的数据进行操作,那当我们再次提交事务的时候会清理缓存,session会把缓存中的数据与数据库中的数据进行同步的更新,我们在上面的代码中,位于session.save(stu1);后添加:

stu1.setAge(22);

再次运行该方法,控制台的输出信息是:

执行了两条SQL语句,这说明在调用save()方法后,stu1的确由瞬时态变为了持久态。

get()和load()方法:

都是根据给定的OID,加载一个持久化对象。

 

get()方法和load()方法的异同点:

  1. 都是先根据OID从缓存中获取,存在就直接返回
  2. get()方法:执行SQL从数据库获取
  3. load()方法:返回一个代理对象(延迟加载、懒加载)
  4. 如果数据库中不存在给定OID对应的记录:get()方法返回null;load()方法跑出ObjectNotFoundException异常

get()方法:

@Test
public void get(){
Configuration cfg=new Configuration().configure();
StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service= ssrb.build();
SessionFactory factory=cfg.buildSessionFactory(service);
Session session= factory.openSession();
Transaction tx=session.beginTransaction();
try {
Student stu=(Student)session.get(Student.class, 1);
System.out.println(stu.getId());
tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
}finally {
session.close();
} }

执行的结果是:

查询了数据库表,再看看load()方法:

@Test
public void load(){
Configuration cfg=new Configuration().configure();
StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service= ssrb.build();
SessionFactory factory=cfg.buildSessionFactory(service);
Session session= factory.openSession();
Transaction tx=session.beginTransaction();
try {
Student stu=(Student)session.load(Student.class, 1);
System.out.println(stu.getId());
tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
}finally {
session.close();
} }

执行的结果:

为什么没有在数据库中查询呢?这就是load()方法的特点:懒加载、延迟加载,只有访问非对象关系表示符OID属性以外的其他属性时load()方法才会发起select语句,我们把上面的方法稍微修改一下:

Student stu=(Student)session.load(Student.class, 1);
System.out.println(stu.getName());//获取name属性
tx.commit();

在次执行,看看控制台的信息:

特别注意,在使用load()方法时,千万不要在session关闭后对非对象关系表示符属性以外的其他属性的访问,否则会跑出异常。

delete()方法

使一个持久化对象变成移除状态,从数据库中移除它的持久化状态。

看看delete()方法的定义:

@Test
public void delete(){
Configuration cfg=new Configuration().configure();
StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service= ssrb.build();
SessionFactory factory=cfg.buildSessionFactory(service);
Session session= factory.openSession();
Transaction tx=session.beginTransaction();
try {
Student stu=(Student)session.load(Student.class, 1);
session.delete(stu);
tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
}finally {
session.close();
} }

测试该方法,看看控制台的输出信息:

可以看到,有两条sql语句,第一条就是get()方法的select语句,第二条就是delete()的删除语句。

update()方法

使一个脱管对象重附到新的session中,成为持久化对象。

看看update()方法的代码:

@Test
public void update(){
Configuration cfg=new Configuration().configure();
StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service= ssrb.build();
SessionFactory factory=cfg.buildSessionFactory(service);
Session session= factory.openSession();
Transaction tx=session.beginTransaction();
try {
Student stu=(Student)session.load(Student.class, 2);
stu.setAge(50);
session.update(stu);
tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
}finally {
session.close();
} }

执行本方法,可以看到如下结果:

在使用update()方法时,如果操作的是托管对象,它也依然会把托管对象变为持久化对象,然后再执行update语句,当清理缓存的时候,再把缓存中的数据同步更新到数据库。

merge()方法

将给定实例的状态复制到具有相同标识符的持久化实例上,并返回这个持久化实例;

常用来代替update()方法、saveOrUpdate()方法。

先看看使用merge()方法操作瞬时态对象:

@Test
public void merge(){
Configuration cfg=new Configuration().configure();
StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service= ssrb.build();
SessionFactory factory=cfg.buildSessionFactory(service);
Session session= factory.openSession();
Transaction tx=session.beginTransaction();
try {
Student stu=new Student();
stu.setName("wangwu");
stu.setAge(22);
session.merge(stu);
            tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
}finally {
session.close();
} }

看看执行的结果:

可以看出,它执行了一条insert语句,向数据库中添加了一条语句,再看看操作持久化状态的对象,又会是怎样的结果呢?

@Test
public void merge(){
Configuration cfg=new Configuration().configure();
StandardServiceRegistryBuilder ssrb=new StandardServiceRegistryBuilder().applySettings(cfg.getProperties());
ServiceRegistry service= ssrb.build();
SessionFactory factory=cfg.buildSessionFactory(service);
Session session= factory.openSession();
Transaction tx=session.beginTransaction();
try {
Student stu=(Student)session.get(Student.class, 3);
stu.setAge(23);
session.merge(stu);
tx.commit();
} catch (Exception e) {
// TODO: handle exception
tx.rollback();
}finally {
session.close();
} }

控制台打印的信息如下:

可以看出,使用merge()方法时,它会根据对象的状态来确定是执行insert语句还是update语句,至此,session的几个基本的方法就搞定了。好累好累,弄了一个下午!

hibernate学习系列-----(3)Session 缓存和持久化生命周期以及Session 基本操作的更多相关文章

  1. hibernate学习系列-----(2)hibernate核心接口和工作机制

    在上一篇文章hibernate学习系列-----(1)开发环境搭建中,大致总结了hibernate的开发环境的搭建步骤,今天,我们继续了解有关hibernate的知识,先说说这篇文章的主要内容吧: C ...

  2. iOS系列 基础篇 04 探究视图生命周期

    iOS系列 基础篇 04 探究视图生命周期 视图是应用的一个重要的组成部份,功能的实现与其息息相关,而视图控制器控制着视图,其重要性在整个应用中不言而喻. 以视图的四种状态为基础,我们来系统了解一下视 ...

  3. iOS系列 基础篇 03 探究应用生命周期

    iOS系列 基础篇 03 探究应用生命周期 目录: 1. 非运行状态 - 应用启动场景 2. 点击Home键 - 应用退出场景 3. 挂起重新运行场景 4. 内存清除 - 应用终止场景 5. 结尾 本 ...

  4. HIbernate学习笔记3 之 缓存和 对象的三种状态

    一.hibernate一级缓存 *  hibernate创建每个Session对象时,都会给该Session分配一块独立的缓冲区,用于存放Session查询出来的对象,这个分配给session的缓存区 ...

  5. hibernate学习系列-----(4)hibernate基本查询上篇:HQL基本查询

    紧接着上一篇,今天继续hibernate的学习总结,来聊一聊hibernate的基本查询方法,先说说HQL(hibernate Query Language):它是官方推荐的查询语言.在开始写代码之前 ...

  6. Servlet学习笔记(1)--第一个servlet&&三种状态对象(cookie,session,application)&&Servlet的生命周期

    servlet的404错误困扰了两天,各种方法都试过了,翻书逛论坛终于把问题解决了,写此博客来纪念自己的第一个servlet经历. 下面我会将自己的编写第一个servlet的详细过程提供给初学者,大神 ...

  7. java之hibernate之session中对象的生命周期

    1. session是用来执行对象的crud操作,并且session是对象事务工厂.session是线程级别的,所以生命周期比较短. 2.session中对象的生命周期图: 3.session中对象的 ...

  8. Hibernate入门(3)- 持久对象的生命周期介绍

    在hibernate中对象有三种状态:瞬时态(Transient). 持久态(Persistent).脱管态或游离态(Detached).处于持久态的对象也称为PO(Persistence Objec ...

  9. Android学习笔记(五)——活动的生命周期

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 为了能写出流畅连贯的程序,我们需要了解一下活动的生命周期. 一.返回栈 Android 中的活动是可以层叠的. ...

随机推荐

  1. TestNG测试执行顺序

    1.preserve-order属性,之前一直认为preserve-order属性是控制配置方法的执行顺序的,其实不是,preserve-order主要是控制test下节点classes执行顺序的 例 ...

  2. HDU1263 map二维运用

    #include <iostream> #include <cstdio> #include <cstring> #include <map> #inc ...

  3. 知问前端——对话框UI(二)

    dialog()方法的事件 除了属性设置外,dialog()方法也提供了大量的事件,这些事件可以给各种不同状态时的对话框提供回调函数,这些回调函数中的this值等于对话框内容的div对象,不是整个对话 ...

  4. 装多个版本jdk后,eclipse无法正常启动

    需要在eclipse.ini中plugins/org.eclipse.equinox.launcher_1.3.0.v20140415-2008.jar后面指定jdk的路径. 指定jdk所在路径 -v ...

  5. 使用select2插件并添加拼音首字母检索

    项目中要使用下拉检索的时候要支持拼音首字母.本来拼音可以写后台,这里放前台了. 放代码 1. pinyin.js ,最后为了使用方便,直接为string对象添加了扩展方法 /* File Create ...

  6. 由做网站操作日志想到的HttpModule应用

    背景 在以前的Web项目中,记录用户操作日志,总是在方法里,加一行代码,记录此时用户操作类型与相关信息.该记录日志的方法对原来的业务操作侵入性较强,也比较零散,不便于查看和管理.那么有没有更加通用点的 ...

  7. Windows环境Vim编辑器如何执行Ruby代码

    1.下载 Ruby 1.8.5(2006-8-25) for Windows: 在网页http://www.rubychina.net/downloads/ 上找到  --〉Ruby on Windo ...

  8. jsp/el和jstl动态页面

    一.JSP技术 1.jsp脚本和注释 jsp脚本: 1)<%java代码%> ----- 内部的java代码翻译到service方法的内部 2)<%=java变量或表达式> - ...

  9. js面试总结

    <div id="app"> <button onClick="app()">点击1</button> <button ...

  10. Ubuntu14.04安装配置LAMP环境(php5.6)

    sudo apt-get install python-software-properties sudo apt-get update sudo apt-get install vim sudo ap ...