在学习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啦。
共同学习,写下你的评论
评论加载中...
作者其他优质文章