二级缓存

1 对一级缓存和二级缓存分析:
1.1  一级缓存:一级缓存是一个事务中的缓存,只发生在一个session打开之后关闭之前,一般一级缓存是不需要人工管理操作的,但是当应用程序中有时需要大批量更新信息时候也会出现OutOfMemoryException错误,Hibernate也提供了两种方式管理一级缓存:
方法一:session.evict()
此方法一般在执行删除某记录时候执行:
Session. delete(user);
Session. evict(user);
方法二:session.clear()
此方法用于将一级缓存全部清空。
1.2 二级缓存的原理:Hibernate内部只支持一级缓存,表现在session打开关闭之前如果里面有同样的session.get()语句则不会出现第二次查询,不过这个有局限只能局限在sessin打开之后关闭之前;二级缓存突破了这一限制,在session关闭之后也能打开第二个session并在第二个里执行与第一个session里同样的session.get(),然而不通过二次查询数据库也能查到相应数据。
1.3  Hibernate二级缓存的配置:
    (1) 设置Hibernate支持二级缓存功能:
在hibernate.cfg.xml配置文件中添加属性:
<property name=" cache.use_second_level_cache ">true</property>
其实Hibernate默认的cache.use_second_level_cache值也是true,所以此属性用户可以不配置。
    (2) 设置二级缓存实现的提供商:
在hibernate.cfg.xml配置文件中添加属性:
<property name=" cache.provider_class "> org.hibernate.cache.OSCacheProvider
</property>
二级缓存的实现类有很多,好比:org.hibernate.cache.OSCacheProvider
   (3) 设置需要进行二级缓存的类:
方法一
在hibernate.cfg.xml中添加配置:
<class-cache usage="read-only" class="cn.itcast.domain.User"/>
注:使用策略usage的选项值有四种:
① read-only:如果你的应用程序只需读取一个持久类的实例,而无需对其修改,那么就可以对其进行只读缓存。这是最简单的,也是实用性最好的方法。甚至在群集中,它也能完美地运行。
② read-write:如果应用程序需要更新数据,那么读/写缓存比较合适。
③ nonstrict-read-write:如果应用程序只偶尔需要更新数据(也就是说,两个事物同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离,那么比较适合使用非严格读/写策略。
④ transaction:事务策略提供了全事务的缓存支持,例如对JBoss TreeCache的支持。这样的缓存只能用于JTAG环境中,你必须指定为其transaction.manager_lookup_class属性。
注意:class必须是完整的包括类包的类名。
方法二:没每一个要进行二级缓存的类的映射文件设置:
<class name="User" table="User">
   <cache usage="read-only"/>
     <id name="id">
       <generator class="native"/>
     </id>
    <component name="name">
      <property name="firstName" column="first_name"/>
      <property name="lastName" column="last_name"/>
    </component>
    <property name="birthday"></property>
 </class>
     注意:在<id>前定义<cache usage="read-only"/>如果映射文件中有集合类(如Set、Map、List等的)映射实体也要另行指定其cache的缓存同步策略并指定region(不过不包括component和  joined-subclass)
另举例如下
  <set name="employees" cascade="save-update" inverse="true">
    <cache usage="read-only" region="Employee"/>
    <key column="dept_id"></key>
    <one-to-many class="Employee"/>
  </set>

2  现在查看如下代码:
  User user=null;
  Session session=null;
  try
  {
    session=HibernateUtil.getSession();
    user=(User) session.get(User.class, id);
    System.out.println(user.getClass());
    //这里在session未关闭之前查询是利用一级缓存
  user=(User) session.get(User.class, id);
  System.out.println(user.getName());
  }
  finally
  {
    if(session!=null)
     session.close();
  }
  try
 { //之前的session关闭了,这里重新打开了一个新的session,这里查询利用的是二级缓存
    session=HibernateUtil.getSession();
    user=(User) session.get(User.class, id);
  }
  finally
  {
    if(session!=null)
    session.close();
  }
2.1 检测二级缓存性能:
(1) 在hibernate.cfg.xml配置一个属性:
generate_statistics=true
(2) 测试代码:
  public static void main(String[] args)
  {
    User user=addUser();
    getUser(user.getId());
   Statistics st=HibernateUtil.getSessionFactory().getStatistics();
    System.out.println("put"+st.getSecondLevelCachePutCount());
    System.out.println("hit"+st.getSecondLevelCacheHitCount());
    System.out.println("miss"+st.getSecondLevelCacheMissCount());
  }
注意:以上代码作用是分别获取二级缓存中向map中存数据次数、命中数据次数、没命中数据次数。
    
3  对二级缓存的人工管理:
 对二级缓存一般是不用管理的,都是有提供商和hibernate管理好的,不过也提供了几个控制二级缓存的方法:
 (1) HibernateUtil.getSessionFactory().evict(User.class);
    把二级缓存中User的所有实例清除掉包括继承它的子类实例;
 (2) HibernateUtil.getSessionFactory().evict(User.class, id);
    把二级缓存中通过id指定的User实例清除掉。
    
4  增加对查询HQL查询的二级缓存功能:
 Query query=session.createQuery("from User where id>20");    
 像上面这样的查询语句,hibernate是默认不支持二级缓存的,因为每个查询都是有针对性的查询条件,下次查询的命中率不高,但是也是可以设置打开查询二级缓存的。
 打开步骤:
(1). 在hibernate.cfg.xml中配置以下属性:
<property name="cache.use_query_cache">true</property>
注意:此属性Hibernate缺省的是false,所以必须配置为true。
(2). 修改代码:
static User query(int id)
{
     Session session=null;
     session=HibernateUtil.getSession();
     Query query=session.createQuery("from User where id>20");
     query.setCacheable(true);
     User user=(User)query.uniqueResult();
     return user;
}
 小结:
1. Session的save()方法不适合native生成方式的主键。
2. update,saveOrUpdate,list,iterator,get,load以及Query,Criteria都会填充二级缓存,但只是在查询缓存时候,Session的iterator.getLoad()会从二级缓存中取数据(iterator可能存在N+1此查询)
3.Query.Criteria查询缓存由于命中率较低,所以Hibernate缺省时关闭的.
4.SessionFactory中提供了evictXXX()方法用来清除缓存中的内容。
5.统计信息打开generate_statics,用sessionFactory.getStatics()获取统计信息。
转自:http://blog.163.com/zhangfei_jiayou/blog/static/56244178200983061742668/

原文地址:https://www.cnblogs.com/a1280055207/p/3173269.html