zoukankan      html  css  js  c++  java
  • 关于hibernate一级缓冲和二级缓冲

    关于一级缓冲和二级缓冲的内容,在面试的时候被问起来了,回答的不是很满意,所以有专门找了些有关这方面的文章加以理解

    出自:http://blog.csdn.net/zdp072/article/details/51146981

    1. 管理session
    session对象的生命周期与本地线程绑定
    <!-- 配置session对象的生命周期和本地线程绑定 -->
    <property name=”hibernate.current_session_context_class”>thread</property>

    使用本地线程绑定,每次都从当前的线程提取session!!!
        * 当前线程如果存在session对象,取出直接使用
        * 当前线程如果不存在session对象,获取一个新的session对象和当前线程绑定
    Session s1 = sf.getCurrentSession();
    Session s2 = sf.getCurrentSession();
    System.out.println(s1==s2);  // true

    2. hibernate缓存机制
    Hibernate中提供了两个级别的缓存
    第一级别的缓存是 Session的缓存,它是属于线程范围的缓存。这一级别的缓存由 hibernate 管理的,我们无需干预
    第二级别的缓存是 SessionFactory的缓存,它是属于进程范围的缓存

    缓存的作用主要用来提高性能,可以简单的理解成一个Map

    使用缓存涉及到三个操作:把数据放入缓存、从缓存中获取数据、删除缓存中的无效数据

    2.1 一级缓存
    一级缓存指的是session对象内部的一个HashMap  (session的实现类是:SessionImpl)
    用户不需要做任何配置就可以使用,但它的生命周期非常小, 只要session关闭,缓存就消失
    每个session拥有自己的缓存区, 执行session.save()操作的时候,会先放入一级缓存
    --> 放入一级缓存的对象称为持久化对象

    * 执行查询的时候,会先到session的一级缓存中查找 
              * 如果找到,直接从缓存中获取该对象,这时不再查询数据库
              * 如果没有找到,此时查询数据库,产生select语句,并把查询到的对象放入缓存
    Customer c1 = (Customer) session.get(Customer.class, 1);

    * 执行查询的时候,会将查到的对象放到session的一级缓存中一份,同时在session的快照中有一份复制
              当执行session.close()的时候,清理缓存,这时会比对缓存中对象的属性值和快照中对象的属性值,看是否一致
    * 如果一致,不再执行update语句
    * 如果不一致,执行update语句
    * session如何判断持久化对象的状态发生改变呢?
    * session加载对戏那个后会为对象属性复制一份快照,当session清理缓存时,会比较当前对象和它的快照就可以知道哪些属性发生了改变

    * 在什么时候session会清理缓存呢?
              * 当应用程序调用Transaction的commit()方法时,该方法先清理缓存,然后向数据库提交事务
              * 当应用程序执行一些查询操作,如果缓存中持久化对象的属性已经发生了变化,会先清理缓存,以保证查询结果能反应持久化对象的最新状态
              * 显式的调用Session的flush()方法

    注意: 清理缓存,缓存中的数据不会丢失,清理不等于清除  session.clear()为清空缓存
    session.refresh(customer) 刷新数据库中的数据和缓存中的同步,方向: 从数据库-->缓存
    session.fresh() 刷新session的一级缓存中的数据到数据库,让缓存中的数据跟数据库同步,方向: 从缓存--> 数据库
    session在清理缓存时,会根据持久化对象的属性变化,来同步更新数据库

    * session缓存的作用?
              * 减少数据库的访问频率,提高访问性能
              * 保证缓存中的对象与数据库同步,位于缓存中的对象称为持久化对象

    2.2 SessionFactory的缓存

    1.) 内置缓存: 只读的
             * 连接数据库的信息
             * 映射文件的信息
             * 预定义的sql语句

    2.) 外置缓存(二级缓存) 一个可以配置的缓存插件,第三方的,分为四个部分  -> 所谓的缓存就是hashmap
    * 类级别的缓存
             * 放置的是查询到的对象(散列数据),  同时还要把查询的时间放置到类级别的时间戳区域
    * 集合级别的缓存 (存放的永远是查询条件)
             * 放置的是查询条件,真正的实体还是在类级别的缓存区域中
    * 查询缓存
             * 放置的是查询条件,真正的实体还是在类级别的缓存区域中
             <property name=”hibernate.cache.use_query_cache”>true</property>  // 配置启用查询缓存
             query.setCacheable(true);  // 启用查询缓存
    * 更新时间戳缓存
    * 适合放入二级缓存的数据: 可以缓解数据库的压力
             * 很少被修改
             * 不是很重要的数据,允许出现偶尔的并发问题
    * 不适合放入二级缓存的数据:
             * 经常被修改
             * 财务数据,绝对不允许出现并发问题
             * 与其他应用数据共享的数据

    * hibernate有了一级缓存,为什么还要有二级缓存?
    * 一级缓存只对当前的session有效
    * 二级缓存里的数据可以跨多个session,可以被多个session共享
    * 缓存的时间更久,不会像一级缓存那样,一旦session销毁就销毁

    * 二级缓存散列数据的概念!
             * 做查询的时候: Customer c = (Customer) session.get(Customer.class,1); // 已配置了Customer类级别的二级缓存
                会将c放入一级缓存和二级缓存!!! 二级缓存中放置的是不是对象,而是对象的属性值!所以称二级缓存存放的是散列数据
                每次取出的对象是不同的对象

    2.3 缓存策略
    read-only - 只可执行读取,不能进行更新。
    read-wirte: - 可读,也可以写
    对于查询缓存,如果只查询一个类,则只配置cache即可,
    但如果查询的结果是一个集合, 则必须要hibernate.cfg.xml中配置开启查询缓存

    3. 配置二级缓存

    第一步:导jar包echace.jar.
    第二部: 先使用ehcache-1.5.0.jar该缓存的默认配置,此时执行的是jar包下的ehcache-failsafe.xml文件
    第三步:开启二级缓存,配置缓存提供的供应商,并将需要支持二级缓存的类配置到hibernte.cfg.xml中.
    第四步:配置ehcache自己的配置文件:classpath:ehcache.xml (针对某个对象设置缓存)
    第五步:配置一些信息,如:最多存多少个数据对象,数据对像太多时,不用的对象是否应该保存到硬盘上去

    要使用二级缓存,还需要引入两个jar包(spring包下)
    ..libconcurrentackport-util-concurrent.jar
    ..libcommons-logging.jar

    Hibernate.cfg.xml:

    [html] view plain copy
     
    1. <!-- 以下配置二级缓存-以下启动了二级缓存,默认是不开启的-->  
    2.     <property name="cache.use_second_level_cache">true</property>  
    3.     <property name="hibernate.cache.provider_class">  
    4.         org.hibernate.cache.EhCacheProvider  
    5.     </property>  
    6.     <!-- 以下打开查询缓存 -->  
    7.     <property name="hibernate.cache.use_query_cache">true</property>  
    8.       
    9.     <!-- 打开二级缓存的统计信息  
    10.         hit:命中次数:是指从二级缓存中获取到了几次数据。  
    11.         miss:没有命中的次数。  
    12.      -->  
    13. <property name="hibernate.generate_statistics">true</property>  
    14.     <!--配置二级缓存中存放的数据类型,要放置在mapping元素的下面-->  
    15. <!--配置类级别的二级缓存-->  
    16. <class-cache class=”cn.itcast.Customer” usage=”read-write”/>  
    17. <class-cache class=”cn.itcast.Order” usage=”read-write”/>  
    18. <!--配置集合级别的二级缓存-->  
    19. <collection-cache class=”cn.itcast.Customer.orders” usage=”read-write”/>  

    也可以在映射文件里面配置(不推荐)

    [html] view plain copy
     
    1. <class name=”cn.itcast.Customer” table=”customers”>  
    2.         <!--配置类级别的二级缓存,此时二级缓存中能存放Customer对象-->  
    3.         <cache usage=”read-write”/>     
    4.         <id name=”id” type=”integer”>  
    5.         </id>  
    6.         ...  
    7.         <set name=”orders” table=”orders” inverse=”true”>  
    8.         <!—配置集合级别的二级缓存,此时orderes订单集合放入到二级缓存中-->  
    9.             <cache usage=”read-write”/>    
    10.         </set>  
    11. </class>  

    eacache.xml

    [html] view plain copy
     
    1. <ehcache>  
    2.     <!-- 设置当内存数据太多时,保存到哪一个目录 -->  
    3.     <diskStore path="d:/a"/>  
    4.     <!--以下是默认缓存区,必须存在  
    5.         eternal:在内存中的数据是否永不过期。建议设置为false  
    6.         -->  
    7.     <defaultCache  
    8.         maxElementsInMemory="100"  
    9.         eternal="false"  
    10.         timeToIdleSeconds="120"  
    11.         timeToLiveSeconds="300"  
    12.         overflowToDisk="true"  
    13.         />  
    14.     <!-- 以下定义一个有名的cache区 -->  
    15.     <cache name="itcast"  
    16.         maxElementsInMemory="100"  
    17.         eternal="false"  
    18.         timeToIdleSeconds="300"  
    19.         timeToLiveSeconds="600"  
    20.         overflowToDisk="true"  
    21.         />  
    22. </ehcache>  

    辅助理解一级缓存:

    [java] view plain copy
     
    1. // 核心类,维护了一个map,相当于一个缓存  
    2. public class Baidu {  
    3.     private static Map<String,City> citys = new HashMap<String,City>();  
    4.     public static City getCity(String name){  
    5.         City city = citys.get(name);  
    6.         if(city==null){  
    7.             city = new City(name);  
    8.             citys.put(name, city);  
    9.         }  
    10.         return city;  
    11.     }  
    12. }  

    // 一个javabean,封装了城市的信息

    [java] view plain copy
     
    1. public class City {  
    2.     private String name;  
    3.     public City(String name) {  
    4.         this.name = name;  
    5.     }  
    6.     ...  
    7. }  

    // 测试类

    [java] view plain copy
     
      1. public class Main {  
      2.     public static void main(String[] args) {  
      3.         City city1 = Baidu.getCity("Beijing");   // 第一次获取北京的信息 -> 查缓存 -> 没有 -> 查数据库 -> 维护到缓存  
      4.         City city2 = Baidu.getCity("Beijing");   // 第二次查缓存 -> 有 -> 直接从缓存获取  
      5.         System.out.println(city1==city2);  
      6.     }  
      7. }  
  • 相关阅读:
    39页第3题 求x的n次幂
    实验4-1 求花费电费的金额
    实验二利用循环计算多个圆柱体体积
    39页第一题 四则运算及其余数
    实验一计算圆的面积
    7-14
    第六章例6-3
    第六章例6-2
    第六章例6-1
    第五章例5-9
  • 原文地址:https://www.cnblogs.com/lihuibin/p/8324936.html
Copyright © 2011-2022 走看看