Hibernate 深入Session

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
     *      根据多的一方加载一的一方数据量特别少,所以怎么样都行
     */

}
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值