zoukankan      html  css  js  c++  java
  • hibernate的二级缓存----collection和query的二级缓存

    collection二级缓存:

    不使用集合的二级缓存时:
      运行下面的代码:

    @Test
        public void testCollectionSecondLevelCache1(){
            Department dept = (Department) session.get(Department.class, 3);
            System.out.println(dept.getId()+"   "+dept.getName());
            System.out.println(dept.getEmps().size()); 
            
            transaction.commit();
            session.close();
            
            session = sessionFactory.openSession();
            transaction = session.beginTransaction();
            
            Department dept2 = (Department) session.get(Department.class,3);
            Set<Employee> emps=dept2.getEmps();
            for(Employee employee:emps){
                System.out.println(employee.getId()+"      " +employee.getName());
            }
        }

    产生的结果如下:

    Hibernate:
    select
    department0_.ID as ID1_0_0_,
    department0_.NAME as NAME2_0_0_
    from
    GG_DEPARTMENT department0_
    where
    department0_.ID=?
    3 B
    Hibernate:
    select
    emps0_.DEPT_ID as DEPT_ID5_0_1_,
    emps0_.ID as ID1_1_1_,
    emps0_.ID as ID1_1_0_,
    emps0_.NAME as NAME2_1_0_,
    emps0_.SALARY as SALARY3_1_0_,
    emps0_.EMAIL as EMAIL4_1_0_,
    emps0_.DEPT_ID as DEPT_ID5_1_0_
    from
    GG_EMPLOYEE emps0_
    where
    emps0_.DEPT_ID=?
    3
    --------------------------------------------------
    Hibernate:
    select
    department0_.ID as ID1_0_0_,
    department0_.NAME as NAME2_0_0_
    from
    GG_DEPARTMENT department0_
    where
    department0_.ID=?
    Hibernate:
    select
    emps0_.DEPT_ID as DEPT_ID5_0_1_,
    emps0_.ID as ID1_1_1_,
    emps0_.ID as ID1_1_0_,
    emps0_.NAME as NAME2_1_0_,
    emps0_.SALARY as SALARY3_1_0_,
    emps0_.EMAIL as EMAIL4_1_0_,
    emps0_.DEPT_ID as DEPT_ID5_1_0_
    from
    GG_EMPLOYEE emps0_
    where
    emps0_.DEPT_ID=?
    5 EE
    7 GG
    6 FF

    1如果Session没有关闭的话应该是发送两条select语句的吧,因为Session的缓存中已经初始化了department和employee对象啦,但是Session关闭后,Session的一级缓存没有了吧,所以此时的department和employee对象都是游离对象,当需要要再次获得时必须发送select语句给数据吖

    但是如果我们启用了集合的二级缓存呢??

    集合二级缓存的操作步骤:

    I. 配置对集合使用二级缓存

    <collection-cache usage="read-write" collection="com.atguigu.hibernate.entities.Department.emps"/>

    也可以在 .hbm.xml 文件中进行配置

    <set name="emps" table="GG_EMPLOYEE" inverse="true" lazy="true">
    <cache usage="read-write"/>
    <key>
    <column name="DEPT_ID" />
    </key>
    <one-to-many class="com.atguigu.hibernate.entities.Employee" />
    </set>

    II. 注意: 还需要配置集合中的元素对应的持久化类也使用二级缓存! 否则将会多出 n 条 SQL 语句.(集合缓存依赖于对持久化类的二级缓存)

    例如在Hibernate.cfg.xml文件中配置集合的二级缓存:

    <class-cache usage="read-write" class="com.atguigu.hibernate.entities.Employee"/>
    <class-cache usage="read-write" class="com.atguigu.hibernate.entities.Department"/>
    <collection-cache usage="read-write" collection="com.atguigu.hibernate.entities.Department.emps"/>

    代码示例:

    使用了集合二级缓存后结果为这个:

    Hibernate: 
        select
            department0_.ID as ID1_0_0_,
            department0_.NAME as NAME2_0_0_ 
        from
            GG_DEPARTMENT department0_ 
        where
            department0_.ID=?
    3   B
    Hibernate: 
        select
            emps0_.DEPT_ID as DEPT_ID5_0_1_,
            emps0_.ID as ID1_1_1_,
            emps0_.ID as ID1_1_0_,
            emps0_.NAME as NAME2_1_0_,
            emps0_.SALARY as SALARY3_1_0_,
            emps0_.EMAIL as EMAIL4_1_0_,
            emps0_.DEPT_ID as DEPT_ID5_1_0_ 
        from
            GG_EMPLOYEE emps0_ 
        where
            emps0_.DEPT_ID=?
    3
     -------------------------------------------------- 
    6      FF
    5      EE
    7      GG

    查询缓存:

    查询缓存是二级缓存的一种用法 
    查询缓存(Query Cache):  
    对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把 查询结果存放在二级缓存中。以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能。  
    查询缓存适用于以下场合: 1在应用程序运行时经常使用的查询语句。 2 很少对与查询语句关联的数据库数据进行插入、删除或更新操作。 

    在hibernate的使用中,大家多数时间都在讨论一级缓存和二级缓存,而往往忽略了查询缓存。其实hibernate的查询缓存在使用过程中也起着同样重要的作用。hibernate的查询缓存是主要是针对普通属性结果集的缓存, 而对于实体对象的结果集只缓存id。在一级缓存,二级缓存和查询缓存都打开的情况下作查询操作时这样的:
    查询普通属性---》会先到查询缓存中取,如果没有,则查询数据库;
    查询实体---》 会先到查询缓存中取id,如果有,则根据id到缓存(一级/二级)中取实体,如果缓存中取不到实体,再查询数据库。

     实现步骤:
    1查询缓存是属于二级缓存的一个子类别,所以查询缓存依赖于二级缓存,所以在使用查询缓存之前,必须配置好二级缓存,二级缓存上面有说,这里就不提了
    2在 hibernate 配置文件中声明开启查询缓存

    <property name="cache.use_query_cache">true</property>
    3调用 Query 或 Criteria 的 setCacheable(true) 方法,启用当前(就是在你需要的查询语句后执行 setCacheable(true)方法)的查询缓存

    例子说明:
    测试代码:

    @Test
        public void testQueryCache(){
            Query query = session.createQuery("FROM Employee");
            List<Employee> emps = query.list();
            System.out.println(emps.size());
            System.out.println(emps.iterator().next().getClass());
            
            emps = query.list();
            System.out.println(emps.size());
            }

    运行结果:

    Hibernate: 
        select
            employee0_.ID as ID1_1_,
            employee0_.NAME as NAME2_1_,
            employee0_.SALARY as SALARY3_1_,
            employee0_.EMAIL as EMAIL4_1_,
            employee0_.DEPT_ID as DEPT_ID5_1_ 
        from
            GG_EMPLOYEE employee0_
    25
    class com.atguigu.hibernate.entities.Employee
    Hibernate: 
        select
            employee0_.ID as ID1_1_,
            employee0_.NAME as NAME2_1_,
            employee0_.SALARY as SALARY3_1_,
            employee0_.EMAIL as EMAIL4_1_,
            employee0_.DEPT_ID as DEPT_ID5_1_ 
        from
            GG_EMPLOYEE employee0_
    25

    在这里两次我都是执行同样的HQL语句进行查询,但是Hibernate却帮我发送了两条select语句,有一条是不是就是多余的啦?这就说明了在默认情况下, 设置的缓存对 HQL 及 QBC 查询时无效的, 但可以通过设置查询缓存的方式使其生效,(注意QBC查询也需要这样去设置)
    启动了查询缓存后运行结果为:

    Hibernate: 
        select
            employee0_.ID as ID1_1_,
            employee0_.NAME as NAME2_1_,
            employee0_.SALARY as SALARY3_1_,
            employee0_.EMAIL as EMAIL4_1_,
            employee0_.DEPT_ID as DEPT_ID5_1_ 
        from
            GG_EMPLOYEE employee0_
    25
    class com.atguigu.hibernate.entities.Employee
    25

    只发送了一条select语句,那这样是不是大大减轻了我的程序的负担了吧

      还有一个需要注意的问题 查询缓存和一级/二级缓存不同,查询缓存的生命周期 ,是不确定的,当前关联的表发生改变时,查询缓存的生命周期结束。
    例如运行下面测试代码:
    @Test
        public void testQueryCache(){
            Query query = session.createQuery("FROM Employee e where e.id=1");
            query.setCacheable(true);
            
            List<Employee> emps = query.list();
            System.out.println(emps.size());
            System.out.println(emps.iterator().next().getClass());
            
            Employee employee=new Employee();
            
            employee.setEmail("sdkfjsd@qq.com");
            employee.setName("jeremy");
            employee.setSalary(8000F);
            session.save(employee);
            
            emps = query.list();
            System.out.println(emps.size());
            
            //Criteria criteria = session.createCriteria(Employee.class);
            //criteria.setCacheable(true);
        }

    运行结果:

    Hibernate: 
        select
            employee0_.ID as ID1_1_,
            employee0_.NAME as NAME2_1_,
            employee0_.SALARY as SALARY3_1_,
            employee0_.EMAIL as EMAIL4_1_,
            employee0_.DEPT_ID as DEPT_ID5_1_ 
        from
            GG_EMPLOYEE employee0_ 
        where
            employee0_.ID=10
    1
    class com.atguigu.hibernate.entities.Employee
    Hibernate: 
        insert 
        into
            GG_EMPLOYEE
            (NAME, SALARY, EMAIL, DEPT_ID) 
        values
            (?, ?, ?, ?)
    Hibernate: 
        select
            employee0_.ID as ID1_1_,
            employee0_.NAME as NAME2_1_,
            employee0_.SALARY as SALARY3_1_,
            employee0_.EMAIL as EMAIL4_1_,
            employee0_.DEPT_ID as DEPT_ID5_1_ 
        from
            GG_EMPLOYEE employee0_ 
        where
            employee0_.ID=10
    1


    我在进行了第一次HQL查询后又对了数据表进行了增加操作了,此时的数据表已经发生了改变了,此时查询缓存被关闭了(就算更新操作对我HQL语句查询的结果没影响,但是查询缓存还是被关闭了)

    如果查询缓存没有被关闭,那已是发送一条select语句和一条insert语句,但是现在是发送了两条select语句,一条insert语句 ,所以证明了,当查询缓存相关的表更新后,
    查询缓存会自动关闭,这一点需要记住
  • 相关阅读:
    微信小程序学习系列(5) 微信小程序逻辑层
    微信小程序学习系列(4) 微信小程序架构文件
    微信小程序学习系列(3) 如何优雅的使用微信开发者工具
    使用Sqlserver 2012 导出表数据为SQL脚本
    Sqlserver2012 使用sql语句增加(或删除)表一个字段
    微信小程序学习系列(2) 使用AppId创建一个微信小程序
    微信小程序学习系列(1) 如何注册微信小程序
    微信小程序如何使用Vant
    vs2017搭建自己的nuget服务器
    使用swagger实现在线api文档自动生成 在线测试api接口
  • 原文地址:https://www.cnblogs.com/jeremy-blog/p/4022187.html
Copyright © 2011-2022 走看看