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

出自: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包下)
..\lib\concurrent\backport-util-concurrent.jar
..\lib\commons-logging.jar

Hibernate.cfg.xml:

  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. hit:命中次数:是指从二级缓存中获取到了几次数据。
  10. miss:没有命中的次数。
  11. -->
  12. <property name="hibernate.generate_statistics">true</property>
  13. <!--配置二级缓存中存放的数据类型,要放置在mapping元素的下面-->
  14. <!--配置类级别的二级缓存-->
  15. <class-cache class=”cn.itcast.Customer” usage=”read-write”/>
  16. <class-cache class=”cn.itcast.Order” usage=”read-write”/>
  17. <!--配置集合级别的二级缓存-->
  18. <collection-cache class=”cn.itcast.Customer.orders” usage=”read-write”/>

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

  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

  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>

辅助理解一级缓存:

  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,封装了城市的信息

  1. public class City {
  2. private String name;
  3. public City(String name) {
  4. this.name = name;
  5. }
  6. ...
  7. }

// 测试类

    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. }

关于hibernate一级缓冲和二级缓冲的更多相关文章

  1. 转载 hibernate一级缓存和二级缓存的区别

    文章来源:http://blog.csdn.net/defonds/article/details/2308972     hibernate一级缓存和二级缓存的区别 缓存是介于应用程序和物理数据源之 ...

  2. Hibernate一级缓存与二级缓存的区别

    一级缓存: 就是Session级别的缓存.一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中. 如果短时间内这个session(一定要同一个session)又做了同一个操作,那么h ...

  3. Hibernate一级缓存和二级缓存深度比较

    1.什么是缓存 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据, ...

  4. Hibernate一级缓存和二级缓存详解

    (1)一级缓存 是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么h ...

  5. Hibernate一级缓存、二级缓存以及查询缓存的关系

    转载自http://blog.csdn.net/maoyeqiu/article/details/50209893 前两天总结了一下二级缓存和查询缓存的关系,但是又有一个新的问题,就是查询缓存缓存到二 ...

  6. Hibernate一级缓存和二级缓存具体解释

    一.一级缓存二级缓存的概念解释 (1)一级缓存就是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中.假设短时间内这个 session(一定要同一个ses ...

  7. Hibernate一级缓存、二级缓存

    缓存就是把以前从数据库中查询出来和使用过的对象保存在内存中,准确说就是一个数据结构中,这个数据结构通常是或类似HashMap,当以后要使用某个对象时,先查询缓存中是否有这个对象,如果有则使用缓存中的对 ...

  8. hibernate一级缓存和二级缓存的区别

    http://blog.csdn.net/defonds/article/details/2308972 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了 ...

  9. hibernate 一级缓存、二级缓存

    一级缓存:——session一旦关掉就没有了.使用 load和get加载对象的时候,会自动加载到缓存,读取的也会读缓存. public void huancun(){ Session session= ...

随机推荐

  1. 最全最详细:ubuntu16.04下linux内核编译以及设备驱动程序的编写(针对新手而写)

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

  2. json和pickle,XML

    什么是 JSON ? JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation) JSON 是轻量级的文本数据交换格式 JSON 独立于语言:JSON ...

  3. YII2 BUG记录

    YII2 的ar类在插入数据的时候,如果类的成员属性有和字段相同的,则该字段插入不成功 示例: CONSTROLLER 层 $banner->type = '4'; //////type在mod ...

  4. python中dict的fromkeys用法

    fromkeys是创造一个新的字典.就是事先造好一个空字典和一个列表,fromkeys会接收两个参数,第一个参数为从外部传入的可迭代对象,会将循环取出元素作为字典的key值,另外一个参数是字典的val ...

  5. 关于linux特殊含义的转义符\033

    格式: echo -e "\033[字背景颜色;字体颜色m字符串\033[0m" 例如: echo -e "\033[41;36m something here \033 ...

  6. Ubuntu14.04 LTS 安装Chrome浏览器(转)

    add zhj: 亲测过,可以,原来不用FQ就可以下载,有点意外 原文:http://www.jianshu.com/p/8220578d0b15 1.打开终端(ctrl + alt + t),下载6 ...

  7. 催希凡javaweb 学习28天

    看到这样的博客,自己也在看传智播客的视频,收藏一下 催希凡javaweb 学习28天 http://www.cnblogs.com/Prozhu/category/824899.html

  8. 1-AO3402MOS管使用

    1.做电源设计,或者做驱动方面的电路,难免要用到MOS管.MOS管有很多种类,也有很多作用.做电源或者驱动的使用,当然就是用它的开关作用. 2.MOS管的三个极,G.S.D分别代表是什么? (1).判 ...

  9. Linux上跑MySQL优化技巧

    1.禁止操作系统更新文件的atime属性 atime是Linux/UNIX系统下的一个文件属性,每当读取文件时,操作系统都会将读操作时间回写到磁盘上.对于读写频繁的数据库文件来说,记录文件的访问时间一 ...

  10. centos who命令 查看当前登录系统用户信息

    who 显示当前登录系统的用户,但w显示的更为详细 默认输出 [root@mysql ~]# who //用户名.登录终端.登录时间 root pts/ -- : (192.168.0.110) -a ...