现在的位置: 首页 > 算法 > 正文

在Hibernate框架中详谈一级缓存

2016年08月15日 算法 ⁄ 共 2887字 ⁄ 字号 暂无评论

在学习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啦。

 

给我留言

您必须 [ 登录 ] 才能发表留言!

×