Hibernate深入Session

来源:互联网 发布:mac软件卸载不了 编辑:程序博客网 时间:2024/06/15 14:06

session概述

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

session的产生方式

session的产生方法一

这里写图片描述

session的产生方法二

这里写图片描述
配置hibernate.cfg.xml文件
这里写图片描述
测试session的产生方式
这里写图片描述

package cn.itcast.hibernate0909.session;import java.lang.annotation.Target;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.junit.Test;import cn.itcast.hibernate0909.onetomany.doubl.Classes;/** * *  hibernate中的crud操作是利用session来完成的 * *  hibernate中的事务是依赖于session环境的 * *  session的产生的方式 *      *  sessionFactory.openSession *         每次都会新创建一个session,只要新创建一个session,hibernate都会打开应用程序和数据库的连接 *         所以这种方式效率比较低 *      *  sessionFactory.getCurrentSession *         *  如果当前线程中没有session,先openSession,然后把session存放到当前线程中 *         *  从当前线程中得到session *         *  crud操作必须有事务环境 *         *  不用手动去close掉 * *  session的一级缓存 * @author Administrator * */public class SessionTest {    private static SessionFactory sessionFactory;    static{        Configuration configuration = new Configuration();        //加载配置文件        configuration.configure("cn/itcast/hibernate0909/session/hibernate.cfg.xml");        //采用了工厂模式创建sessionFactory        sessionFactory = configuration.buildSessionFactory();    }    private void testSession(String name){        Session session = sessionFactory.getCurrentSession();        //Transaction transaction = session.beginTransaction();        Classes classes = (Classes)session.get(Classes.class, 1L);        //classes.setCname(name);        //transaction.commit();        //session.close();    }    @Test    public void test(){        SessionTest sessionTest = new SessionTest();        sessionTest.testSession("aaa");    }}

junit测试结果
这里写图片描述

session产生方式总结

 * *  hibernate中的crud操作是利用session来完成的 * *  hibernate中的事务是依赖于session环境的 * *  session的产生的方式 *      *  sessionFactory.openSession *         每次都会新创建一个session,只要新创建一个session,hibernate都会打开应用程序和数据库的连接 *         所以这种方式效率比较低 *      *  sessionFactory.getCurrentSession *         *  如果当前线程中没有session,先openSession,然后把session存放到当前线程中 *         *  从当前线程中得到session *         *  crud操作必须有事务环境 *         *  不用手动去close掉 * *  session的一级缓存

理解session的缓存

  • 在 Session 接口的实现中包含一系列的 Java 集合, 这些 Java 集合构成了 Session 缓存. 只要 Session实例没有结束生命周期, 存放在它缓存中的对象也不会结束生命周期
  • 当session的save()方法持久化一个对象时,该对象被载入缓存,以后即使程序中不再引用该对象,只要缓存不清空,该对象仍然处于生命周期中。当试图load()对象时,会判断缓存中是否存在该对象,有则返回。没有在查询数据库

session.get方法

这里写图片描述
junit测试结果:
这里写图片描述
可以看出只查询了一次数据库

session.save方法

这里写图片描述
junit测试结果:
这里写图片描述
可以看出并没有发出select语句去查询班级

session.update方法

这里写图片描述

junit测试结果:
这里写图片描述
这里写图片描述
可以看出第二次查询并没有发出select语句去查询班级

清理session的缓存

  • Session 具有一个缓存, 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点,
    按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为清理缓存(flush)
  • 默认情况下 Session 在以下时间点清理缓存:
    • 当应用程序调用 Transaction 的 commit()方法的时,
      该方法先清理缓存(session.flush()),然后在向数据库提交事务(tx.commit())
    • 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生了变化,会先清理缓存,以保证查询结果能够反映持久化对象的最新状态
    • 显式调用 Session 的 flush() 方法.
  • 区别:

    flush: 进行清理缓存(此时缓存中的数据并不丢失)的操作,让缓存和数据库同步 执行一些列sql语句,但不提交事务,;
    commit:先调用flush() 方法,然后提交事务. 则意味着提交事务意味着对数据库操作永久保存下来。
    reresh:刷新,让session和数据库同步,执行查询,把数据库的最新信息显示出来,更新本地缓存的对象状态.
    clear:清空缓存,等价于list.removeAll();

session.flush方法

这里写图片描述

junit测试结果:
这里写图片描述

这里写图片描述

这里写图片描述
junit测试结果:
这里写图片描述
这里写图片描述

session.flush方法总结

 session.flush方法      hibernate内部会去检查session缓存中的所有的对象      如果该对象是持久化对象,并且该对象的ID在数据库中有对应的记录,并且该对象的属性     有变化,则会自动发出update语句,如果该对象的属性没有变化,则不发出update语句    检查持久化对象中是否有关联的对象,如果有关联的对象,并且设置了级联操作,这个时候    会检查级联对象的id在数据库中有没有对应的记录,如果有,则发出update语句,如果没有,则 发出insert语句    如果有维护关系的代码,则还会改变关系    全部检查完成以后,就发出sql语句,把一级缓存中的内容同步到数据库中

session.reflush方法总结

这里写图片描述
junit测试结果:
这里写图片描述

利用Session缓存读取持久化对象的数据

1   Customer c = new Customer(“TOM”,new HashSet());2   session.save(c); //customer对象被持久化,并且加入到session的缓存中 3   Long id = c.getId();4   c = null; //c变量不再引用customer对象 5   //从session缓存中读取customer对象,使c2变量引用customer对象6   Customer c2 = (Customer)session.load(Customer.class,id);7   tx.commit();  //缓存中的对象和数据库同步8   session.close(); //关闭session 清空缓存9   System.out.println(c2.getName()); //访问customer对象10 C2 = null; //C2对象不再引用customer对象,customer对象结束生命周期 

缓存的作用:
1。减少访问数据库的频率。
2。保证缓存中的对象与数据库中的相关记录保持同步。

Session执行批量操作

可以写一个for循环,Session可以批量插入上万条数据。如下面的代码:

            For(int i=0;i<10000;i++){                Session.save(object);            }

这样写的代码会产生一个什么问题?会使一万个对象的缓存全部存在于内存中,这样做加大了内存的压力。所以应该定期清理session的缓存,也就是flush一下,这样内存才能保证足够的空间。

这里写图片描述

Session.load与session.get方法

不同场合的不同解决方案

场合一:当用户要取数据库的一张表的一个字段,这个字段很可能就是一个字符,总而言之长度是比较短的。
场合二:当用户要取数据库的一张表的一个字段的值,而这个值很可能是blob类型,也许存取的是一个很大的视频文件。
两种场合的取数据的方法一样吗?是用load还是用get方法?

一级缓存的测试源码

package cn.itcast.hibernate0909.session.cache;import java.util.Set;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.junit.Test;import cn.itcast.hibernate0909.onetomany.doubl.Classes;import cn.itcast.hibernate0909.onetomany.doubl.Student;/** * 1、一级缓存的生命周期 *     一级缓存在session中存放,只要打开session,一级缓存就存在了,当session关闭的时候,一级缓存就不存在了 * 2、一级缓存是依赖于谁存在的 *     依赖于session存在的 * 3、怎么样把数据存放到一级缓存中 *     利用session.get、update、save * 4、怎么样从一级缓存中获取数据 *     利用session.get方法可以获取数据 * 5、怎么样把缓存中的数据同步到数据库 *     * 只要是一个持久化状态的数据就在一级缓存中 *     * 利用session.flush方法 * 6、怎么样把数据库的数据同步到一级缓存中 *     session.reflesh方法   只能同步一个对象 * 7、一级缓存的特性 *    也叫session级别的缓存 *    session中存放私有数据 *    可以通过新建session和从当前线程中获取session保证数据的安全性 * 8、从一级缓存中清楚某一个对象 *    session.evcit方法  并且把一个对象从持久化状态转化成脱管状态 * 9、清空一级缓存中所有的数据 * @author Administrator * */public class OneCacheTest {    private static SessionFactory sessionFactory;    static{        Configuration configuration = new Configuration();        //加载配置文件        configuration.configure("cn/itcast/hibernate0909/session/hibernate.cfg.xml");        //采用了工厂模式创建sessionFactory        sessionFactory = configuration.buildSessionFactory();    }    /**     * session.get方法     *     * 通过该方法得到的对象是一个持久化对象     *     * 通过该方法可以把该对象存放到一级缓存中(session缓存中)     */    @Test    public void testGet(){        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        Classes classes = (Classes)session.get(Classes.class, 1L);        session.get(Classes.class, 1L);        transaction.commit();    }    /**     * session.save方法     *    *  可以把一个对象变成持久化状态的对象     *    *  可以把一个对象放入到一级缓存中     */    @Test    public void testSave(){        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        Classes classes = new Classes();        classes.setCname("重点班");        classes.setDescription("高材生");        session.save(classes);        Classes classes2 = (Classes)session.get(Classes.class, classes.getCid());        transaction.commit();    }    /**     * session.update方法     *    *  能把一个对象的状态转化成持久化状态     *    *  能把一个对象存放到一级缓存中     */    @Test    public void testUpdate(){        /**         * 1、利用get方法获取         * 2、利用session.evict方法清空         * 3、再利用update方法         * 4、再用get方法获取         */        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        Classes classes = (Classes)session.get(Classes.class, 2L);        session.evict(classes);//用session.evict方法清空        classes.setDescription("aaa");        session.update(classes);        Classes classes2 = (Classes)session.get(Classes.class,2L);        transaction.commit();    }    @Test    public void testFlush(){        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        //持久化状态的数据        Classes classes = (Classes)session.get(Classes.class, 1L);        Set<Student> students = classes.getStudents();        for(Student student:students){            student.setClasses(null);        }        Student student = new Student();        student.setSname("菜肉哥!");        student.setDescription("厉害!!!!!");        Student student2 = new Student();        student2.setSname("包子哥!");        student2.setDescription("真厉害!!!!!");//      student.setClasses(classes);//      student2.setClasses(classes);        students.add(student);        students.add(student2);        /**         * session.flush方法         *   *  hibernate内部会去检查session缓存中的所有的对象         *   *  如果该对象是持久化对象,并且该对象的ID在数据库中有对应的记录,并且该对象的属性         *      有变化,则会自动发出update语句,如果该对象的属性没有变化,则不发出update语句         *   *  检查持久化对象中是否有关联的对象,如果有关联的对象,并且设置了级联操作,这个时候         *      会检查级联对象的id在数据库中有没有对应的记录,如果有,则发出update语句,如果没有,则         *      发出insert语句         *   *  如果有维护关系的代码,则还会改变关系         *   *  全部检查完成以后,就发出sql语句,把一级缓存中的内容同步到数据库中         */        session.flush();        transaction.commit();    }    @Test    public void testFlush2(){        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        Student student1 = (Student)session.get(Student.class, 1L);        Student student2 = (Student)session.get(Student.class, 2L);        student1.getClasses().setCname("aaa");        student2.getClasses().setDescription("asdf");        session.flush();        transaction.commit();    }    @Test    public void testReflesh(){        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        Classes classes = (Classes)session.get(Classes.class, 1L);        classes.setCname("bbb");        //把一个对象对应的数据库的数据重新更新到一级缓存中        session.refresh(classes);        session.clear();//清空一级缓存中的所有的数据        classes = (Classes)session.get(Classes.class, 1L);        System.out.println(classes.getCname());        transaction.commit();    }    /**     * 批量操作     */    @Test    public void testBatchSave(){        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        for(int i=0;i<100000;i++){            if(i%50==0){                session.flush();                session.clear();            }            Classes classes = new Classes();            classes.setCname(i+"aaa");            session.save(classes);        }        transaction.commit();    }}

延迟加载

类的延迟加载

lazy 为true或者为false
这里写图片描述
这里写图片描述
这里写图片描述
断点debug运行发现在classes.getCname();发出sql语句

lazy 设置为false重新测试
这里写图片描述
这里写图片描述
断点debug运行发现在session.load(Classes.class, 1L);就发出了sql语句

集合的延迟加载

True false extra
extra为更进一步的延迟加载策略。
当调用getStudents()时不会加载hql语句,当加载student的属性的时候才会发出SQL语句
调用getStudents().size()方法的时候,会触发类似于:Hibernate: select count(id) from T_Student where classid =? 这样的SQL查询语句(这是一种很聪明的做法,如果lazy=”true”,getStudents().size()将会使得hibernate加载所有集合的数据到内存中)。
调用getStudents().contains()方法的时候(即判断是否包含某个对象),会触发类似于:select 1 from T_Student where classid =? and id =? 这样的SQL查询语句。


lazy=”true”
这里写图片描述
断点debug运行
这里写图片描述

lazy=”false”
这里写图片描述
断点debug运行
这里写图片描述

lazy=“extra”
这里写图片描述
这里写图片描述

单端关联

False proxy no-proxy
proxy:当前对象的単值相关对象只有在调用它的主键外的其他属性的get方法时才加载它。
no-proxy:当前对象的単值相关对象只有在调用它的属性时才加载,需要字节码增强。

懒加载的测试源码

package cn.itcast.hibernate0909.lazy;import java.util.Set;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import org.junit.Test;/** * 懒加载 *    针对数据库中的大数据,不希望特别早的加载到内存中,当用到它的时候才加载 *    类的懒加载 *    集合的懒加载     *    单端关联的懒加载 * @author Administrator * */public class LazyTest {    private static SessionFactory sessionFactory;    static{        Configuration configuration = new Configuration();        //加载配置文件        configuration.configure("cn/itcast/hibernate0909/lazy/hibernate.cfg.xml");        //采用了工厂模式创建sessionFactory        sessionFactory = configuration.buildSessionFactory();    }    /**     * 类的懒加载     *    *  在默认情况下,类就是执行懒加载     *    *  只有使用了load方法以后才能用懒加载     *    *  如果在相应的映射文件中,设置<class>的lazy="false"懒加载将失去效果     */    @Test    public void testLoad(){        Session session = sessionFactory.getCurrentSession();        Transaction transaction = session.beginTransaction();        Classes classes = (Classes)session.load(Classes.class, 1L);        String cname = classes.getCname();//发出sql语句        System.out.println(cname);        transaction.commit();    }    /**     * 集合的懒加载     *   针对一多对的情况或者多对多的情况     *     根据一方加载set集合,决定在什么时候给set集合填充数据     *     true     *        在遍历集合中的每一个元素的时候发出sql语句     *     false     *        在得到集合的时候,发出sql语句     *     extra     *        students.size()这个时候用extra仅仅能够得到大小     */    @Test    public void testCollectionLazy(){        Session session = sessionFactory.openSession();        Classes classes = (Classes)session.load(Classes.class, 2L);        Set<Student> students = classes.getStudents();        System.out.println(students.size());        session.close();    }    /**     * 单端关联     *   根据多的一方加载一的一方     *     false     *     proxy  就相当于true     *     no-proxy     *      根据多的一方加载一的一方数据量特别少,所以怎么样都行     */}
2 0
原创粉丝点击