hibernate学习系列-----(3)Session 缓存和持久化生命周期以及Session 基本操作

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的几个基本的方法就搞定了。好累好累,弄了一个下午!

时间: 2024-11-03 06:56:09

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

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

在上一篇文章hibernate学习系列-----(1)开发环境搭建中,大致总结了hibernate的开发环境的搭建步骤,今天,我们继续了解有关hibernate的知识,先说说这篇文章的主要内容吧: Configuration类 SessionFactory接口 Session接口 Transaction接口 Query和Criteria接口 下面就进行分类别地详细说明: Configuration类 功能描述:Configuration类负责管理Hibernate的配置信息作并根据配置信息启动H

Spark源码系列(四)图解作业生命周期

这一章我们探索了Spark作业的运行过程,但是没把整个过程描绘出来,好,跟着我走吧,let you know! 我们先回顾一下这个图,Driver Program是我们写的那个程序,它的核心是SparkContext,回想一下,从api的使用角度,RDD都必须通过它来获得. 下面讲一讲它所不为认知的一面,它和其它组件是如何交互的. Driver向Master注册Application过程 SparkContext实例化之后,在内部实例化两个很重要的类,DAGScheduler和TaskSched

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

iOS系列 基础篇 03 探究应用生命周期 目录: 1. 非运行状态 - 应用启动场景 2. 点击Home键 - 应用退出场景 3. 挂起重新运行场景 4. 内存清除 - 应用终止场景 5. 结尾 本篇主要探讨的是iOS应用中各种状态的跃迁过程,建议大家通过修改AppDelegate.swift,在每个过程中添加日志输出代码,从而观察其变化. 作为应用程序的委托对象,AppDelegate类在应用程序生命周期的不同阶段会回调不同的方法. 首先,咱们先来了解一下iOS应用的不同状态和他们之间的关系

Android学习路线(十四)Activity生命周期——停止和重启(Stopping and Restarting)一个Activity

先占个位置,下次翻译~ :p Properly stopping and restarting your activity is an important process in the activity lifecycle that ensures your users perceive that your app is always alive and doesn't lose their progress. There are a few of key scenarios in which

Android学习路线(十五)Activity生命周期——重新创建(Recreating)一个Activity

先占个位置,下次翻译~ :p There are a few scenarios in which your activity is destroyed due to normal app behavior, such as when the user presses the Back button or your activity signals its own destruction by calling finish(). The system may also destroy your

Android学习路线(十二)Activity生命周期——启动一个Activity

先占个位置,过会儿来翻译,:p Unlike other programming paradigms in which apps are launched with a main()method, the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle. Th

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

一.hibernate一级缓存 *  hibernate创建每个Session对象时,都会给该Session分配一块独立的缓冲区,用于存放Session查询出来的对象,这个分配给session的缓存区也叫session级缓存.session取数据时,会优先向缓存区取数据,如果存在就直接取,不存在就去数据库查询,降低了数据库访问次数. * 一级缓冲是默认开启的,查询时会自动使用.每个session是独立的,save.update.delete.操作都会出发缓存更新. 二.缓存的管理 * sessi

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

紧接着上一篇,今天继续hibernate的学习总结,来聊一聊hibernate的基本查询方法,先说说HQL(hibernate Query Language):它是官方推荐的查询语言.在开始写代码之前,看看需要做哪些准备工作吧,首先,在我们的学生类中新增一个属性"clazz",其实不加也可以,接着,我们需要重写Student.java类中的toString()方法,代码如下: /** * 重写toString方法 */ @Override public String toString(

Hibernate持久化生命周期——三态

通过前几篇博客的大概介绍,我们发现hibernate将业务实体持久化到数据库的工作原理的实现,是通过"映射xml"来衔接的.那么这个xml的由来是哪? 映射文件(hbm)合理的存在的前提就是"有与之对应的实体的存在"--业务实体. 今天这篇博客就来说说实体到数据库的过程,这是一个从代码到数据的持久化过程,就是hibernate实现ORM持久化的生命周期. 一.持久化对象生命周期 下图是hibernate持久化的一个状态图,从图中可以看出,ORM这个过程经历了三个状态