• 在Hibernate框架中详谈一级缓存


    在学习Hibernate的过程中我们肯定会碰上一个名词---缓存,一直都听说缓存机制是Hibernate中的一个难点,它分为好几种,有一级缓存二级缓存查询缓存

    今天呢,我就跟大家分享分享我所理解的一级缓存

    要想完美的体现出缓存机制的话,我想通过查询语句生成的sql应该就能够很清楚的看到

    那些Hibernate的配置信息我就不展示了,直接看关键代码

    场景:我要查询同一个对象,查询两次,观察在不同的情况下,sql语句的生成情况

    我事先准备了一个HibernateUtil工具类,具体如下

    package util;
    
    import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;
    
    public class HibernateUtil {
        //初始化一个ThreadLocal对象
        private static final ThreadLocal sessionTL =new ThreadLocal();
        private static Configuration configuration;
        private final static SessionFactory sessionFactory;
        static {
            try{
                configuration=new Configuration().configure();
                sessionFactory=configuration.buildSessionFactory();
            }catch(Throwable ex){
                ex.printStackTrace();
                throw new ExceptionInInitializerError(ex);
            }
            
        }
        
        //获取session
        public static Session currentSession(){
            Session session=(Session)sessionTL.get();
            if(session==null){
                session=sessionFactory.openSession();
                sessionTL.set(session);
            }
            return session;
        }
        
        //关闭session
        public static void closeSession(){
            Session session= (Session)sessionTL.get();
            sessionTL.set(null);
            session.close();
         }
    }

    正常我们访问DB端时应该是访问几次就发送几次sql,如下所示

        //查询学生信息
        public static void select(){
            
            //由班级查询该班级学生信息
            Session session=HibernateUtil.currentSession();
            Grade grade=(Grade) session.get(Grade.class, 14);
            //输出班级信息
            System.out.println(grade.getGname());
            Grade grade2=(Grade) session.get(Grade.class, 17);
            //输出班级信息
            System.out.println(grade2.getGname());
        }

    结果应该是这样

     

    那么问题就来了,我们现在有如下几个场景

    场景一:使用同一个session连续查询两次同一个对象

    //查询学生信息
        public static void select(){
            
            //由班级查询该班级学生信息
            Session session=HibernateUtil.currentSession();
            Grade grade=(Grade) session.get(Grade.class, 14);
            //输出班级信息
            System.out.println(grade.getGname());
            Grade grade2=(Grade) session.get(Grade.class, 14);
            //输出班级信息
            System.out.println(grade2.getGname());
        }

    这个时候我们不难发现,此时我查询的是同一个对象,按照正常理解,我查询了两遍应该向DB端发送两条sql语句才对,下面看看实际的sql数

    这个时候可能有的小伙伴就有疑问了,我们后面再解释这种情况,我们先接着看第二种场景

    场景二:在第一次查询完毕后,关闭session对象,重新开启一个session然后继续查询同一个对象

    //查询学生信息
        public static void select(){
            
            //由班级查询该班级学生信息
            Session session=HibernateUtil.currentSession();
            Grade grade=(Grade) session.get(Grade.class, 14);
            //输出班级信息
            System.out.println(grade.getGname());
            //关闭session
            HibernateUtil.closeSession();
            //重新获取session
            session=HibernateUtil.currentSession();
            Grade grade2=(Grade) session.get(Grade.class, 14);
            //输出班级信息
            System.out.println(grade2.getGname());
        }

    这个时候我们查询的任然是同一个对象,结果却如下图

    那么,通过以上两个场景的模拟,有些小伙伴可能已经明白是怎么回事了,可能有些小伙伴们还有些迷糊,下面我就讲讲我的看法吧~

    总结:1:当我没有关闭session时用的同一个session两次访问同一个对象时,只会向DB端发送一条sql语句
        * 原因:因为我第一次访问数据库的时候Hibernate会自动的将我查询出来的结果保留一份查询出来的对象到一级缓存
              并且这个额对象是根据OID唯一标识的,也可以理解为数据库中的主键值,然后当我再一次访问一个对象时,Hibernate
            机制会自动的先去一级缓存中查找看有没有OID与我要查询的OID相同的对象,如果有的话,则直接从一级缓存中 拿数据
              如果没有相同的OID则说明缓存中没有我要的记录,那么就会直接去访问DB端了,这样的话,又会重新发送一条sql
        2:当我第一次查询完数据后立即关闭session,这时重新开启一个session来访问同一个对象,这时我们会发现它居然向数据库发送了两条Sql语句。这是为什么呢?
        * 原因:其实原因很简单,因为我们虽然说是访问的同一个对象,但是我们随即就关闭了这个session而重新开启了一个session,

            此时我们访问时的session是不一致的也就是说是两个不同的session发出的请求,这样理解的话,我们就不难理解了。

              所以总结出,一级缓存是一个会话级别的缓存,当一次回话结束后该会话里的缓存则会全部的销毁,所有我们自然就只能重新发送一条sql啦。

  • 相关阅读:
    进程、线程、协程
    python垃圾回收机制
    python变量存储和深浅拷贝
    Linux常用命令
    二叉树四种遍历,节点个数,深度
    装饰器
    ArrayList、Vector
    集合、Collection、迭代器、List
    卖票
    关于Thread和Runnable
  • 原文地址:https://www.cnblogs.com/liujiayun/p/5769872.html
Copyright © 2020-2023  润新知