zoukankan      html  css  js  c++  java
  • Hibernate-查询缓存

    Hibernate 查询缓存

    一级缓存和二级缓存都只是存放实体对象的,如果查询实体对象的普通属性的数据,只能放到查询缓存里
    
    查询缓存还存放查询实体对象的id。

    查询缓存的生命周期不确定,当它关联的表发生修改,查询缓存的生命周期就结束。这里表的修改指的是通过hibernate修改,并不是通过数据库客户端软件登陆到数据库上修改。

    hibernate的查询缓存默认是关闭的,如果要使用就要到hibernate.cfg.xml文件里配置:

    <property name="hibernate.cache.use_query_cache">true</property>

    并且必须在程序中手动启用查询缓存,在query接口中的setCacheable(true)方法来启用。

    //关闭二级缓存,没有开启查询缓存,采用list方法查询普通属性
    //同一个sessin,查询两次
    List names = session.createQuery("select s.name from Student s").list();
    for (int i=0; i<names.size(); i++) {
      String name = (String)names.get(i);
      System.out.println(name);  
    }
    System.out.println("-----------------------------------------");
    //会发出sql语句
    names = session.createQuery("select s.name from Student s").setCacheable(true).list();
    for (int i=0; i<names.size(); i++) {
      String name = (String)names.get(i);
      System.out.println(name);
    }

    上面代码运行,由于没有使用查询缓存,而一、二级缓存不会缓存普通属性,所以第二次查询还是会发出sql语句到数据库中查询。

    现在开启查询缓存,关闭二级缓存,并且在第一次的list方法前调用setCacheable(true),并且第二次list查询前也调用这句代码,可以写出下面这样:

    List names = session.createQuery("select s.name from Student s").setCacheable(true).list();

    其它代码不变,运行代码后发现第二次list查询普通属性没有发出sql语句,也就是说没有到数据库中查询,而是到查询缓存中取数据。

    //开启查询缓存,关闭二级缓存,采用list方法查询普通属性
    
    //在两个session中调用list方法
    
    try {
    
    session = HibernateUtils.getSession();
    
    session.beginTransaction();
    
    List names = session.createQuery("select s.name from Student s")
    
    .setCacheable(true)
    
    .list();
    
    for (int i=0; i<names.size(); i++) {
    
    String name = (String)names.get(i);
    
    System.out.println(name);
    
    }
    
    session.getTransaction().commit();
    
    }catch(Exception e) {
    
    e.printStackTrace();
    
    session.getTransaction().rollback();
    
    }finally {
    
    HibernateUtils.closeSession(session);
    
    }
    
    System.out.println("----------------------------------------");
    
    try {
    
    session = HibernateUtils.getSession();
    
    session.beginTransaction();
    
    //不会发出查询语句,因为查询缓存和session的生命周期没有关系
    
    List names = session.createQuery("select s.name from Student s")
    
    .setCacheable(true)
    
    .list();
    
    for (int i=0; i<names.size(); i++) {
    
    String name = (String)names.get(i);
    
    System.out.println(name);
    
    }
    
    session.getTransaction().commit();
    
    }catch(Exception e) {
    
    e.printStackTrace();
    
    session.getTransaction().rollback();
    
    }finally {
    
    HibernateUtils.closeSession(session);
    
    }

    运行结果是第二个session发出的list方法查询普通属性,没有发出sql语句到数据库中查询,而是到查询缓存里取数据,这说明查询缓存和session生命周期没有关系

    //开启缓存,关闭二级缓存,采用iterate方法查询普通属性
    
    //在两个session中调用iterate方法查询

    运行结果是第二个session的iterate方法还是发出了sql语句查询数据库,这说明iterate迭代查询普通属性不支持查询缓存

    //关闭查询缓存,关闭二级缓存,采用list方法查询实体对象
    
    //在两个session中调用list方法查询

    运行结果第一个session调用list方法查询实体对象会发出sql语句查询数据,因为关闭了二级缓存,所以第二个session调用list方法查询实体对象,还是会发出sql语句到数据库中查询。

    //开启查询缓存,关闭二级缓存
    
    //在两个session中调用list方法查询实体对象

    运行结果第一个session调用list方法查询实体对象会发出sql语句查询数据库的。第二个session调用list方法查询实体对象,却发出了很多sql语句查询数据库,这跟N+1的问题是一样的,发出了N+1条sql语句。为什么会出现这样的情况呢?这是因为我们现在查询的是实体对象,查询缓存会把第一次查询的实体对象的id放到缓存里,当第二个session再次调用list方法时,它会到查询缓存里把id一个一个的拿出来,然后到相应的缓存里找(先找一级缓存找不到再找二级缓存),如果找到了就返回,如果还是没有找到,则会根据一个一个的id到数据库中查询,所以一个id就会有一条sql语句。

    注意:如果配置了二级缓存,则第一次查询实体对象后,会往一级缓存和二级缓存里都存放。如果没有二级缓存,则只在一级缓存里存放。(一级缓存不能跨session共享)

    //开启查询缓存,开启二级缓存
    
    //在两个session中调用list方法查询实体对象

    运行结果是第一个session调用list方法会发出sql语句到数据库里查询实体对象,因为配置了二级缓存,则实体对象会放到二级缓存里,因为配置了查询缓存,则实体对象所有的id放到了查询缓存里。第二个session调用list方法不会发出sql语句,而是到二级缓存里取数据。

    查询缓存意义不大,查询缓存说白了就是存放由list方法或iterate方法查询的数据。我们在查询时很少出现完全相同条件的查询,这也就是命中率低,这样缓存里的数据总是变化的,所以说意义不大。除非是多次查询都是查询相同条件的数据,也就是说返回的结果总是一样,这样配置查询缓存才有意义。

  • 相关阅读:
    Linux 打包文件 及 备份数据库
    YII事务
    MySQL两种存储引擎: MyISAM和InnoDB 简单总结
    mysql锁表查询和解锁操作
    Yii+MYSQL锁表防止并发情况下重复数据的方法
    B/S和C/S的区别及应用【转】
    Yii2.0的乐观锁与悲观锁
    【事务】脏读、不可重复读、幻读解释
    利用非阻塞的文件排他锁
    自定义实例化class
  • 原文地址:https://www.cnblogs.com/hwaggLee/p/4502240.html
Copyright © 2011-2022 走看看