Hibernate旅程(九)Hibernate缓存机制--查询缓存

本文深入探讨了Hibernate的一级缓存、二级缓存及针对条件查询的QueryCache策略,详细介绍了如何配置查询缓存,及其对性能的影响,包括如何在不同场景下使用query.list()和query.iterate()方法,并通过实例演示了缓存的开启与关闭对查询效率的具体影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Hibernate查询缓存


我们介绍了Hibernate一级缓存二级缓存hibernate二级缓存时针对Id查询的缓存策略,对于条件查询则毫无作用。因此hibernate提供了针对条件查询的QueryCache(查询策略)。


下面来看session控制的查询缓存。


一、查询缓存配置

1、          hibernate.cfg.xml中加入查询缓存的策略,<propertyname="hibernate.cache.use_query_cache">true</property>      启用查询缓存的策略,默认是false

 

二、关闭二级缓存,采用query.list()查询普通属性

代码如下所示。

public voidtestCache1() {
      Session session = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Listnames = session.createQuery("select s.name from Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<names.size(); i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         System.out.println("-------------------------------------------------------");
         //不会发出查询语句,因为启用查询缓存
         names= session.createQuery("select s.name from Student s")
                      .setCacheable(true)
                      .list();
         for (int i=0;i<names.size(); i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
   }



我们可以看到控制台输出语句,仅输出一次:Hibernate: select student0_.name as col_0_0_ fromt_student student0_

 

由此可知,我们开启了查询缓存,第一次进行查询的时候,已经把结果放到querycache中,当第二次再次做出相同的查询的时候,就不再向数据库发重复的sql语句了。


三、关闭二级缓存,启用查询缓存,采用query.list()查询普通属性

代码就如下所示。

public voidtestCache2() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Listnames = session.createQuery("select s.name from Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<names.size(); i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
      System.out.println("-------------------------------------------------------");
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         //不会发出查询语句,因为查询缓存和session的生命周期没有关系
         Listnames = session.createQuery("select s.name from Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<names.size(); i++) {
            Stringname = (String)names.get(i);
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
   }    


运行结果如下所示。

控制台打印结果:

select student0_.name as col_0_0_ fromt_student student0_

班级0的学生0

班级0的学生1

班级0的学生2

班级0的学生3

班级0的学生4

班级0的学生5…

我们可以看出,同样,只打印一次查询语句,如果没有开启查询缓存的话,并且关闭二级缓存的情况下,还会去数据库再查询一遍,而我们的程序中没有再去重复的去数据库中查询的原因是,当开启query缓存的时候,查询缓存的生命周期与session无关。

四、关闭二级缓存,开启查询,采用query.iterate()查询普通属性

代码如下所示。

public voidtestCache3() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Iteratoriter = session.createQuery("select s.name from Student s")
                         .setCacheable(true)
                         .iterate();
         while(iter.hasNext()){
            Stringname = (String)iter.next();
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
      System.out.println("-------------------------------------------------------");
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         //会发出查询语句,query.iterate()查询普通属性它不会使用查询缓存
         //查询缓存只对query.list()起作用
         Iteratoriter = session.createQuery("select s.name from Student s")
                      .setCacheable(true)
                      .iterate();
         while(iter.hasNext()){
            Stringname = (String)iter.next();
            System.out.println(name);
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
   }


显控制台显示结果打印了两次sql语句。

-------------------------------------------------------

Hibernate: select student0_.name as col_0_0_from t_student student0_

根据这样的结果我们发现,quer.iterate()查询普通属性它是不会使用查询缓存,查询缓存只对query.list()起作用。


五、关闭二级缓存,关闭查询缓存,采用query.list()查询实体

 

代码如下所示。

public voidtestCache4() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         List students =session.createQuery("select s from Student s")
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
      System.out.println("-------------------------------------------------------");
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         //会发出查询语句,默认query.list()每次执行都会发出查询语句
         List students =session.createQuery("select s from Student s")
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
   } 


   显示结果如下所示。

控制台上打印两次sql语句。

Hibernate:select student0_.id as id0_, student0_.name as name0_, student0_.classesid asclassesid0_ from t_student student0_

班级0的学生0

班级0的学生1

班级0的学生2

班级0的学生3

班级0的学生4

由此可知,不开启查询缓存,默认query.list每次执行都会发出查询语句。

六、关闭二级缓存,开启查询缓存,采用query.list()查询实体

代码如下所示。

Session session = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Liststudents = session.createQuery("select s from Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
      System.out.println("-------------------------------------------------------");
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
        
         //会发出n条查询语句,因为开启了查询缓存,关闭了二级缓存,那么查询缓存就会缓存实体对象的id
         //第二次执行query.list(),将查询缓存中的id依次取出,分别到一级缓存和二级缓存中查询相应的实体
         //对象,如果存在就使用缓存中的实体对象,否则根据id发出查询学生的语句
         Liststudents = session.createQuery("select s from Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }


控制台打印sql如下图所示。


 

 

在第一次查询的时候,发出一条sql语句查询出结果,因为我们开启了查询缓存,会把第一次查询出的实体结果集的id放到查询缓存中,第二次再次执行query.list()的时候,会把id拿出来,到相应的缓存去找,因为是跨session,在二级缓存中找不到,所以每次都会发出查询语句,二级缓存中不存在,有多少个id就会发出查询语句多少次。

 

七、开启二级缓存,开启查询缓存,采用query.list()查询实体

代码如下所示。

/**
    * 开启查询,开启二级缓存,采用query.list()查询实体
    *
    * 在两个session中发query.list()查询
    */
   public voidtestCache6() {
      Sessionsession = null;
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
         Liststudents = session.createQuery("select s from Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
         session.getTransaction().commit();
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
      System.out.println("-------------------------------------------------------");
      try {
         session= HibernateUtils.getSession();
         session.beginTransaction();
        
         //不再发出查询语句,因为配置了二级缓存和查询缓存
         Liststudents = session.createQuery("select s from Student s")
                         .setCacheable(true)
                         .list();
         for (int i=0;i<students.size(); i++) {
            Studentstudnet = (Student)students.get(i);
            System.out.println(studnet.getName());
         }
      }catch(Exceptione) {
         e.printStackTrace();
         session.getTransaction().rollback();
      }finally {
         HibernateUtils.closeSession(session);
      }
     
   }    


结果如下所示

Hibernate: select student0_.id as id0_,student0_.name as name0_, student0_.classesid as classesid0_ from t_studentstudent0_

只发出一次sql请求,当我们第一次执行query.list()会放到二级缓存中,和query缓存中。当我们第一次执行查询时,会找到相应的id到缓存中查找,在二级缓存中存在,则直接从二级缓存中取出数据,不再向数据库中发出sql语句。


八、查询缓存总结

查询缓存是缓存普通属性结果集的,对实体对象的结果集会缓存id。查询缓存的生命周期,当关联的表发生修改时,查询缓存的生命周期结束。

而开启缓存的时候,我们就要去维护缓存,如果缓存和内存中的数据不一致的话,和数据不同步,可能给用户显示的是脏数据了。所以根据需要使用缓存机制。

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值