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. }  
  • 相关阅读:
    Windows Server 2003 SP2(32位) 中文版 下载地址 光盘整合方法
    用Recycle()方法对Java对象的重要性
    Lotus中千奇百怪的 $$
    Developing a simple application using steps "User Decision" and "Mail"(1) 沧海
    沟通中的情绪管理(演讲稿) 沧海
    人只有在压力之下,才可能成功,没做一件事,都必须成功,不许言败 沧海
    什么是IDOC,以及IDOC的步骤 沧海
    VS2008 Professional Edition CHS中的deffactory.dat读取错误 沧海
    Including custom text in the step "User Decision" 沧海
    SAP Upgrade Strategy 沧海
  • 原文地址:https://www.cnblogs.com/lihuibin/p/8324936.html
Copyright © 2011-2022 走看看