zoukankan      html  css  js  c++  java
  • 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方法会清理缓存,然后再向数据库提交事务 ,这里使用一个例子来简单说明一下

       目前数据库表中数据有:

    QQ截图20150804152751

    使用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();
            }
            
        }

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

    QQ截图20150804153235

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

    QQ截图20150804153455

    透过这个案例,我们可以看到调用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)状态

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



    图片1

    Session的基本操作


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

    Session接口:

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

    save()方法:

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

    图片2

    使用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();
            }
    
        }

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

    QQ截图20150804155044

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

    stu1.setAge(22);

     

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

    QQ截图20150804160332

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

    get()和load()方法:

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

    图片3图片4 

    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();
            }
            
        }

    执行的结果是:

    QQ截图20150804162245

    查询了数据库表,再看看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();
            }
            
        }

     

     

    执行的结果:

    QQ截图20150804161557

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

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

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

    QQ截图20150804162651

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

    delete()方法

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

    图片1

    看看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();
            }
            
        }

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

    QQ截图20150804163731

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

    update()方法

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

    图片2

    看看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();
            }
            
        }

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

    QQ截图20150804164403

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

    merge()方法

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

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

    图片3

    先看看使用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();
            }
            
        }

    看看执行的结果:

    QQ截图20150804165500

    可以看出,它执行了一条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();
            }
            
        }

    控制台打印的信息如下:

    QQ截图20150804170109

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

  • 相关阅读:
    Luogu 1080 【NOIP2012】国王游戏 (贪心,高精度)
    Luogu 1314 【NOIP2011】聪明的质检员 (二分)
    Luogu 1315 【NOIP2011】观光公交 (贪心)
    Luogu 1312 【NOIP2011】玛雅游戏 (搜索)
    Luogu 1525 【NOIP2010】关押罪犯 (贪心,并查集)
    Luogu 1514 引水入城 (搜索,动态规划)
    UVA 1394 And Then There Was One / Gym 101415A And Then There Was One / UVAlive 3882 And Then There Was One / POJ 3517 And Then There Was One / Aizu 1275 And Then There Was One (动态规划,思维题)
    Luogu 1437 [HNOI2004]敲砖块 (动态规划)
    Luogu 1941 【NOIP2014】飞扬的小鸟 (动态规划)
    HDU 1176 免费馅饼 (动态规划)
  • 原文地址:https://www.cnblogs.com/doctorJoe/p/4700693.html
Copyright © 2011-2022 走看看