首页 > 代码库 > Caching

Caching

 1、查询缓存
  如果你有查询运行一遍又一遍,用相同的参数,查询缓存提供了性能。
  缓存介绍在事务处理的上面。如,缓存了一个对象查询的结果,Hibernate需要跟踪是否对对象的任何更改,
  并是其相应的缓存失效。另外,受益于缓存查询结果是有限的,和高度依赖于应用程序的使用模式。处于这些原因,
  Hibernate禁用默认查询缓存。
  
  启用查询缓存
  
   1、hibernate.cache.use_query_cache = true
    这个设置创建两个新的缓存区域:
     org.hibernate.cache.internal.StandardQueryCache缓存查询结果。
     org.hibernate.cache.spi.UpdateTimestampsCache拥有最新更新时间戳的可查询的表,这些timestamps从查询缓存中校验结果
   2、调整底层缓存区域的缓存超时
    如果你配置底层的缓存实现使用过期或超时,设置底层的缓存区域的缓存超时UpdateTimestampsCache的值高于任何查询的缓存。
    有可能并建议,设置UpdateTimestampsCache从不过期。具体地说,一个LRU(最近最少使用)缓存到期政策是不合适的。
   3、启用缓存特定查询的结果
    因为大多数查询不受益于缓存的结果,您需要启用缓存单个查询,即使启用查询缓存。
    使特定查询结果缓存,调用org.hibernate.Query.setCacheable(true),这个调用允许查询寻找现有缓存结果或结果添加到缓存时执行。
    
   查询缓存不缓存的状态实际实体在缓存中,它缓存标识符值和值类型的结果。因此,总是使用的查询缓存和二级缓存的实体应该作为缓存查询结果缓存的一部分。
  
  查询缓存区域
   查询缓存过期进行细粒度的控制策略,为特定的查询指定一个名叫缓存区域通过调用Query.setCacheRegion()。
   List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
      .setEntity("blogger", blogger)
            .setMaxResults(15)
            .setCacheable(true)
            .setCacheRegion("frontpages")
            .list();
      
   迫使查询缓存刷新它的地区之一,无视任何缓存的结果,调用org.hibernate.Query.setCacheMode(CacheMode.REFRESH)。
   结合该地区定义为给定的查询,Hibernate在特定地区选择性地刷新缓存的结果。
   这是更有效的比大部分地区的收回通过org.hibernate.SessionFactory.evictQueries()。
   
 2、二级缓存提供者
  Hibernate使用多个兼容的二级缓存。没有一个提供者支持Hibernate的所有可能的缓存策略。
 
  配置您的缓存提供者
   您可以配置您的缓存提供者使用注释或映射文件。
   
   Entities 默认情况下,实体不属于第二级缓存,他们不推荐使用。
   如果你必须使用实体,在persistence.xml中设置shared-cache-mode,或在你的配置中使用javax.persistence.sharedCache.mode,其参考值:
   ENABLE_SELECTIVE    实体不缓存,除非你显式地将它们标记为可缓存,这是默认和推荐值。
   DISABLE_SELECTIVE    实体是缓存,除非你显式地将它们标记为不缓存。
   ALL        所有实体总是缓存,即使你不将他们标记为可缓存的
   NONE       不缓存实体即使你将它们标记为可缓存的,基本上这个选项禁用二级缓存。
   
   @Entity
   @Cacheable
   @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
   public class Forest { ... }
   
   您可以缓存标识符或集合,如果集合包含其他实体,使用@Cache集合属性的注释
   @Cache属性:
    usage
     给定的缓存并发策略,这可能是:NONE/READ_ONLY/NONSTRICT_READ_WRITE/READ_WRITE/TRANSACTIONAL
    region
     缓存区域,可选,默认值为类的完全限定类名,或qually-qualified角色名称的集合
    include
     是否包括所有的属性,可选,可以采取两种可能的值:
      all 默认,包括所有的属性
      non-lazy 包括non-lazy属性
      
  缓存策略
   read-only
    有利于数据需要经常读但不修改,在集群环境中安全使用且表现良好
   nonstrict read-write
    一些应用程序很少需要修改数据,这种情况下如果两个事务不太可能试图同时更新同一项目,你不需要严格的事务隔离,
    一个nonstrict-read-write缓存可能是适当的。如果缓存是应用在JTA环境中,必需指定hibernate.transaction.manager_lookup_class。
    其他环境,在你调用Session.close() or Session.disconnect()之前ensore 事务完成
   read-write
    读写缓存是适合应用程序需要定期更新数据,如果你需要序列化事务隔离,不要使用read-write策略。
    在JTA环境中,设置hibernate.transaction.manager_lookup_class获取JTA TransactionManager(指定一个策略)。
    非JTA环境,在你调用Session.close() or Session.disconnect()之前确保事务完成。、
    注:在集群环境中使用read-write策略,底层cache的实现必需支持locking,内置缓存提供者不支持locking。
   transactional 
    事务缓存策略支持事务如JBoss TreeCache缓存提供者,在JTA环境中只能使用这样一个缓存,
    并且必需指定hibernate.transaction.manager_lookup_class
 
   Hibernate二级缓存提供者
    HashTable (testing only)    read-only/nonstrict read-write/read-write
    EHCache         read-only/nonstrict read-write/read-write/transactional
    Infinispan        read-only/transactional
   
 3、管理缓存
  移动项目进出的缓存
   添加项目到Session的内部缓存
    保存or更新一个项目:save()/update()/saveOrUpdate()
    遍历一个项目:load()/get()/list()/iterate()/scroll()
    同步或移除一个缓存项目
     当调用flush()方法,对象的状态与数据库同步。
     为了避免这种同步,可以使用evict()方法从一级缓存中移除对象和集合。
     使用Session.clear()移除所有的项目。
     
    ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
    while ( cats.next() ) {
     Cat cat = (Cat) cats.get(0);
     doSomethingWithACat(cat);
     sess.evict(cat);//Evicting an item from the first-level cache
    }
 
    决定一个项目是否属于session缓存。使用contains()方法。
     二级缓存移除
      可以移除缓存实例的状态,实体类,集合实例或实体集合,使用SessionFactory方法。
      sessionFactory.getCache().containsEntity(Cat.class, catId); // is this particular Cat currently in the cache
      sessionFactory.getCache().evictEntity(Cat.class, catId); // evict a particular Cat
      sessionFactory.getCache().evictEntityRegion(Cat.class);  // evict all Cats
      sessionFactory.getCache().evictEntityRegions();  // evict all entity data
      
      sessionFactory.getCache().containsCollection("Cat.kittens", catId); // is this particular collection currently in the cache
      sessionFactory.getCache().evictCollection("Cat.kittens", catId); // evict a particular collection of kittens
      sessionFactory.getCache().evictCollectionRegion("Cat.kittens"); // evict all kitten collections
      sessionFactory.getCache().evictCollectionRegions(); // evict all collection data
      
  一个Session和二级缓存之间的交互 
   CacheMode控制一个特定的会话与第二级缓存交互
   CacheMode.NORMAL    读项目和写他们第二级缓存
   CacheMode.GET     从二级缓存中读取项目,但是不写第二级缓存,除了更新数据。
   CacheMode.PUT     写项目到二级缓存,它不从二级缓存中读取。它绕过hibernate.cache.use_minimal_puts
           并从数据库中读取所有项目强制刷新二级缓存。
           
 Browsing the contents of a second-level or query cache region
  启用统计信息之后,您可以浏览或查询缓存区域二级缓存的内容
  启用统计信息
   1、hibernate.generate_statistics = true
   2、可选 hibernate.cache.use_structured_entries = true,使Hibernate缓存条目存储在一个可读的格式。
  
  Map cacheEntries = sessionFactory.getStatistics()
      .getSecondLevelCacheStatistics(regionName)
      .getEntries();

Caching