Hibernate 缓存

来源:互联网 发布:51单片机复位的作用 编辑:程序博客网 时间:2024/06/03 16:19

Hibernate提供了两级缓存:
一级缓存: Session级别的缓存
二级缓存: SessionFactory级别的全局缓存

Hibernate的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝。
那么它们之间的区别是什么呢?
为了理解二者的区别,需要深入理解持久化层的缓存的一个特性:缓存的范围。


缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。

事务范围:

       缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。一级缓存就属于事务范围。


进程范围:

       缓存被进程范围内的所有事务共享。这些事务有可能并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。它的物理介质可以是内存或硬盘。


集群范围:

       在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。
持久化层的第二级缓存就存在于进程范围或集群范围。


理解一级缓存
        Session具有一个缓存,是一块内存空间,在这个内存空间存放了相互关联的java对象,这种位于Session缓存内的对象也被称为持久化对象,Session负责根据持久化对象的状态变化来同步更新数据库。
        Session的缓存是内置的,不能被卸除的,也被称为Hibernate的第一级缓存。在正常的情况下一级缓存是由Hibernate自动维护的,无需人工干预。

       (1)当应用程序调用Session接口的save()、update()、saveOrUpdate()时,如果Session缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。
       (2)当调用Session接口的load()、get()以及Query查询接口的list()、iterator()方法时,如果Session缓存中存在相应的对象,就不需要到数据库中检索。
       (3)当调用Session的close()时,Session缓存就被清空。
              

Session接口的用法
        session接口是Hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存、更新、删除和加载等方法。
        Java对象在Hibernate持久化层的状态:
临时状态:刚用new语句创建,还没有被持久化,并且不处于session缓存中(处于临时状态的对象成为临时对象)
        持久化状态:已经被持久化,并且加入到session缓存中。处于持久化状态的对象称为持久化对象
游离状态:已经被持久化,但不再处于session缓存中。处于游离状态的对象称为游离对象
删除状态:不再处于session缓存中,并且session已经计划将其从数据库中删除

        save()和persist()
        save()方法把一个临时对象加入到Session缓存中,并持久化该临时对象,计划执行一个insert语句。
        persist()和save()方法类似,也能把把一个临时对象转变为持久化对象。
        区别:
      (1)persist() 是在Hibernate3版本中才出现。在使用代理主键的情况下persist()方法不保证立即为持久化对象的ID赋值,而是有可能在Session清理缓存时才为ID赋值。
      (2)如果在事务边界以外调用persist()方法,那么该方法不会计划执行insert语句,这可以提高负责长时间运行事务的程序的健壮性。
而save()方法,不管是在事务边界以外或以内调用它,都会计划执行insert语句。

        get()和load()
        试图从数据库加载一个实体对象时,Session先判断对象是否存在,如果存在就不到数据库中检索。返回的对象都位于Session缓存中,接下来修改了持久化对象的属性后,当Session清理缓存时,会根据持久化对象的属性变化来同步更新数据库。
        区别:
       (1)当数据库中不存在与OID对应的记录时,load()方法抛出ObjectNotFoundException异常,而get()方法返回null.
       (2)两者采用不同的检索策略。
         默认情况下,load()方法采用延迟检索策略(Hibernate不会执行select语句,仅返回实体类的代理类实例,占用内存很少);而get()采用立即检索策略(Hibernate会立即执行select语句)。
        使用场合: 
     (1)如果加载一个对象的目的是为了访问它的各个属性,可以用get();
     (2)如果加载一个对象的目的是为了删除它,或者建立与别的对象的关联关系,可以用load()  ; 

         update() 和merge() 
         update()方法把游离对象加入当前Session缓存中,计划执行update语句。
         当update()方法关联一个游离对象时,如果session缓存中已经有一个同类型且ID相同的持久化对象,那么update()方法会抛出NonUniqueException异常.
         当update()方法关联一个持久化对象时,该方法不起作用。
         merge() 方法能够把游离对象的属性复制到一个持久化对象中。
         
         
  
        saveOrUpdate()
        同时包含了save()和update()方法的功能。 
        如果传入的是临时对象,就调用save()方法;
        如果传入的是游离对象,就调用update()方法
        如果传入的是持久化对象,就直接返回。        
        delete() :计划执行一个delete语句,把对象从Session缓存中删除。
        close() :清空session缓存。

Session清理缓存
       清理缓存是指Session按照缓存中对象的属性变化来同步更新数据库。
       Session在清理缓存的时候会自动进行脏检查(dirty-check),如果发现Session缓存中的对象与数据库中相应的记录不一致,就会同步数据库。
       Session是如何进行脏检查的呢?
       当一个对象被加入到Session缓存时,Session会为该对象的值类型的属性复制一份快照。当Session清理缓存的时候,会进行脏检查,即比较对象的当前属性与它的快照,来判断对象的属性是否发生变化,如果发生变化,就称这个对象是“脏对象”,Session会根据脏对象的最新属性来执行相关的SQL语句,从而同步更新数据库。

Session何时清理缓存
       session缓存中对象的属性每次发生变化,Session不会立即清理缓存及执行相关的update语句,而是在特定的时间点才清理缓存,这使得Session能够把几条相关的sql语句合并为一条sql语句,以便减少访问数据库的次数。
       
session会在下面的时间点清理缓存:  
       (1) 当应用程序调用org.hibernate.Transaction的commit()方法的时候  commit()方法先清理缓存,然后再向数据库提交事务。
       (2) 当应用程序执行一些查询操作时,如果缓存中持久化对象的属性已经发生变化,就会先清理缓存,使得Session缓存与数据库进行了同步,从而保证查询结果返回的是正确的数据。
      (3) 当应用程序显式调用Session的flush()方法的时候。

Sesion缓存的管理
        第一级缓存在正常的情况下是由Hibernate自动维护的。
        在特殊的情况下需要我们进行手动维护,Hibernate就提供了两个管理Session缓存的方法:  
        (1)Session.evict(Object o)        
        将某个特定的对象从缓存中清除,使用此方法有两种适用情形,一是在特定的操作(如批量处理),需要及时释放对象占用的内存。二是不希望当前Session继续运用此对象的状态变化来同步更新数据库。 
        (2)Session.clear() 
        清除缓存中的所有持久化对象。

1、在多数情况下并不提倡通过evit()和clear()来管理一级缓存。
2、管理一级缓存最有效的方法是采用合理的检索策略和检索方式来节省内存的开销。


Session缓存的作用
     (1)减少访问数据库的频率。
     (2)保证缓存中的对象与数据库中的相关记录保持同步。
      当缓存中的持久化对象的属性发生变化时,Session并不会立即执行相关的update语句。

Hibernate二级缓存概述
       因为Session的生命期往往很短,存在于Session内部的第一级缓存的生命期当然也很短,所以第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的。当然,这个Session缓存的主要作用是保持Session内部数据状态同步,并非是hibernate为了大幅提高系统性能所提供的。
       Hibernate二级缓存:
       1、SessionFactory级别的全局缓存
       2、可配置可插拔的缓存插件
       3、涵盖了进程范围与集群范围
       4、物理介质:内存或硬盘

 Hibernate的两级缓存机制:
       如果在一级缓存中没有查询到相应的数据,可以到二级缓存中查找,如果在二级缓存中也没有找到数据,那么就只好查询数据库了。
       
       


Cache Providers
       Hibernate本身并不提供二级缓存的产品化实现,而是为众多支持Hibernate的第三方缓存插件提供整和接口。缓存插件用于把第三方的具体的缓存实现软件和Hibernate集成,可以在每个持久化类或每个集合的粒度上配置二级缓存。
      通过在hibernate.cache.provider_class属性中指定org.hibernate.cache.CacheProvider的某个实现的类名,你可以选择让Hibernate使用哪个缓存实现。         
       Hibernate打包一些开源缓存实现,提供对它们的内置支持。
       除此之外,你也可以实现你自己的缓存,将它们插入到系统中。
 
Hibernate支持以下类型的缓存插件:
       为了把这些缓存插件集成到Hibernate中,Hibernate提供了org.hibernate.cache.CacheProvider接口,它是缓存插件和与Hibernate之间的适配器。Hibernate分别为这些缓存插件提供了内置的CacheProvider实现。           
       
       
         如果需要实现其它类型的缓存插件,只需要为这个插件提供实现org.hibernate.cache.CacheProvider接口的类。


缓存的并发访问策略--cache concurrency strategy




原创粉丝点击