一点点学习Hibernate3.6 -二级缓存

 

Hibernate中提供了两个级别的缓存:

一级缓存是session的缓存,它属于session的生命周期,session关闭后缓存也将清除.这就说明用session来提升性能的能力有限,而二级缓存是sessionFactory级别的,可以做更多的事情,但是默认是不开启的,我们想要使用,就必须先开启.在主配置文件中添加以下代码来开启二级缓存:

<property name="cache.use_second_level_cache">true</property> 

光开启还不够,还要提供二级缓存的实现,需要给定缓存的提供商,有多种提供商可供选择,EhCacheProvider是一个专业的缓存提供商,在这里就使用它为hibernate的二级缓存服务.给出配置文件的相关配置:

<ehcache>
    <!-- 在内存中存不下的时候,存放的临时目录 -->
    <diskStore path="c:/ehcache"/>
    <!-- 
        maxElementsInMemory:可存10000个对象,超出后存入临时目录
        eternal:设置对象是否为永久的,true表示永不过期,此时将忽略timeToIdleSeconds 和 timeToLiveSeconds属性; 默认值是false 
        timeToIdleSeconds:设置对象空闲最长时间,以秒为单位, 超过这个时间,对象过期。当对象过期时,EHCache会把它从缓存中清除。
                    如果此值为0,表示对象可以无限期地处于空闲状态。 
        timeToLiveSeconds:设置对象生存最长时间,超过这个时间,对象过期。
                    如果此值为0,表示对象可以无限期地存在于缓存中. 该属性值必须大于或等于 timeToIdleSeconds 属性值 
        overflowToDisk:设置基于内在的缓存中的对象数目达到上限后,是否把溢出的对象写到基于硬盘的缓存中
    -->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />
</ehcache> 

到此才算是完全开启,但是,光开启还不够!需要指定哪些类需要缓存,不需要的就不指定.如果有哪个类更新频率很快,比如新闻、首页之类的,就不需要缓存.把类缓存起来称为类缓存.

<class-cache usage="read-write" class="..senondcache.Department"/>
<class-cache usage="read-write" class="..senondcache.Employee"/> 

二级缓存中的类缓存,只适用于使用id查询的方式,比如get()或load(),对于使用HQL的方式不可以缓存,比如"FROM Department d WHERE d.id=1"就不会缓存,比如以下就可以缓存:

 

@Test
public void testSecondCache() {
    // ==========================================================
    // 第一个Session
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    // --------------------------------------------------------------
    Department department = (Department) session.get(Department.class, 1);
    System.out.println(department);
    System.out.println(department.getEmployees());
    // --------------------------------------------------------------
    tx.commit();
    session.close();
    System.out.println("/n----------/n");
    // ==========================================================
    // 第二个Session
    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    // --------------------------------------------------------------
    Department department2 = (Department) session.get(Department.class, 1);
    System.out.println(department2);
    System.out.println(department2.getEmployees());
    // --------------------------------------------------------------
    tx.commit();
    session.close();
} 

如果想使用查询缓存,还要在主配置文件中打开"开关":

<property name="cache.use_query_cache">true</property> 

但是这样还不够,没有缓存哪条语句,在程序中指定:

@Test
    public void testQueryCache() {
        // ==========================================================
        // 第一个Session
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        // --------------------------------------------------------------
        Department department = (Department) session.createQuery(//
                "FROM Department d WHERE d.id=?")//
                .setParameter(0, 1)//
                .setCacheable(true)// 把查询语句缓存起来,以后使用就是使用缓存了
                .uniqueResult();
        System.out.println(department);
        // --------------------------------------------------------------
        tx.commit();
        session.close();
        System.out.println("/n----------/n");
        // ==========================================================
        // 第二个Session
        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        // --------------------------------------------------------------
        Department department2 = (Department) session.createQuery(//
                "FROM Department d WHERE d.id=?")//
                .setParameter(0, 1)//
                .setCacheable(true)// 使用查询缓存
                .uniqueResult();
        System.out.println(department2);
        // --------------------------------------------------------------
        tx.commit();
        session.close();
    } 

 

如果类中有集合,则集合不会缓存进来,除非设置集合缓存:

<collection-cache usage="read-write" collection="..senondcache.Department.employees"/> 

 

还有另外一种缓存,叫时间戳缓存.

时间戳缓存就是指定Hibernate的二级缓存会自动的检测,如果使用了Update或Delete语句,则把一些数据清出缓存,但是它只会清出二级缓存,如果要更新一级缓存,必须使用refresh()方法.

最后还有一个和缓存相关的,使用Query对象.

Query.list()不会使用缓存,除非调用了.setCacheable(true)才可以,但是HQL一变或参数变了,就不会再用缓存的结果了.

但是Query.iterate()会使用类缓存,原理是:

  • 先执行一个查询,查询所有的符合条件的id
  • 再使用每一个对象时,先根据id找缓存,如果找不着,就会生成一个select .. where id=? 的查询
  • 就是说会有n+1次查询的问题(n是指定符合条件的数据量,1是指定查询id的SQL语句)
@Test
public void testQueryIterate() {
    // ==========================================================
    // 第一个Session
    Session session = sessionFactory.openSession();
    Transaction tx = session.beginTransaction();
    // --------------------------------------------------------------
    List list = session.createQuery("FROM Department d WHERE d.id<=2").list();
    for(Object obj : list){
        System.out.println(obj);
    }
    // --------------------------------------------------------------
    tx.commit();
    session.close();
    System.out.println("/n----------/n");
    // ==========================================================
    // 第二个Session
    session = sessionFactory.openSession();
    tx = session.beginTransaction();
    // --------------------------------------------------------------
    Iterator iter = session.createQuery("FROM Department d WHERE d.id<=3").iterate();
    while(iter.hasNext()){
        System.out.println(iter.next());
    }
    // --------------------------------------------------------------
    tx.commit();
    session.close();
}
 

 

你可能感兴趣的:(Hibernate,二级缓存)