Hibernate缓存研究

1. 什么是缓存?

数据库的缓存指的是应用程序和物理数据源之间的数据。即把物理数据源的数据复制到缓存。有了缓存,可以降低应用程序对物理数据源的访问频率,从而提高效率。缓存的介质一般是内存,也可以是硬盘。

Hibernate的缓存有三种类型:一级缓存、二级缓存和查询缓存。

2. 一级缓存

一级缓存即Session缓存,由Session自动进行管理,不需要程序进行干预。一级缓存根据对象的ID进行加载和缓存。如下面的代码:

    @Override
    public void testCache() {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Course c = (Course) session.get(Course.class, 1);
        System.out.println("Name:" + c.getName());
        c = (Course) session.get(Course.class, 1);
        System.out.println("Name:" + c.getName());
        tx.commit();
        session.close();

    }

运行结果:

Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Name:计算机原理
Name:计算机原理

第1次查询时生成了SQL语句,并将查询出来的对象放在一级缓存里面,第2次查询时,在一级缓存里面直接找到了这个对象,就不需要再次生成SQL语句了。

再看一个例子:

    @Override
    public void testCache() {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Course c = (Course) session.get(Course.class, 1);
        System.out.println("Name:" + c.getName());
        tx.commit();
        session.close();

        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        c = (Course) session.get(Course.class, 1);
        System.out.println("Name:" + c.getName());
        tx.commit();
        session.close();
    }

由于一级缓存是Session级别的缓存,所以Session关闭以后,一级缓存也就不存在了,第2次查询也要生成SQL语句:

Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Name:计算机原理
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Name:计算机原理

3. 二级缓存

二级缓存即SessionFactory缓存,和一级缓存类似,也是根据对象的ID进行加载和缓存,区别就在于一级缓存只在Session内有效,而二级缓存在SessionFactory内有效。在访问某个ID的对象时,先到一级缓存里面去找,如果没有找到就到二级缓存里面去找。二级缓存包括EHCache,OSCache,SwarmCache和JBossCache等。这里以EHCache作为例子。

二级缓存需要程序进行管理。首先,配置Maven下载相关的Jar,在pom文件里面添加:

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>4.1.0.Final</version>
        </dependency>

        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.8.3</version>
        </dependency>

创建EHCache配置文件ehcache.xml:

<ehcache>
    <diskStore path="E:\Eclipse\MyWorkspace\Cache"/>
    <defaultCache
        maxElementsInMemory="10000"
        eternal="true"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
    />
    <cache name="com.hzhi.course.entity.Course"
        maxElementsInMemory="10000"
        eternal="true"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
    />
</ehcache>

defaultCache是默认的设置,下面一个cache指明了对哪一个类进行二级缓存。里面设置了最大缓存的对象数量,是否永久有效、最大空闲秒数、最大生存秒数、内存满时是否写到硬盘,写到硬盘的路径等等。

修改需要缓存的类的hbm文件:

    <class name="com.hzhi.course.entity.Course" table="clas">
        <cache usage="read-only"/>
                ......
    </class>

usage设置了并发访问策略,一般设置成read-only。

修改applicationContext.xml中的SessionFactory的配置,增加二级缓存的一些属性:

    <!-- SessionFactory -->
     <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" >
            <ref local="dataSource"/>
        </property>
        <!-- 配置Hibernate的属性 -->
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.connection.isolation">8</prop>
                <!-- 二级缓存 -->
                <prop key="hibernate.cache.use_second_level_cache">false</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                <prop key="hibernate.cache.provider_configuration_file_resource_path">WEB-INF/ehcache.xml</prop>
            </props>
        </property>     ......     </bean>

运行下面的例子:

    @Override
    public void testCache() {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Course c = (Course) session.get(Course.class, 1);
        System.out.println("Name:" + c.getName());
        tx.commit();
        session.close();

        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        c = (Course) session.get(Course.class, 1);
        System.out.println("Name:" + c.getName());
        tx.commit();
        session.close();
    }

结果:

Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Name:计算机原理
Name:计算机原理

虽然关闭了Session,但是二级缓存仍然存在,所以只生成了一次SQL语句。

下面的例子:

    @Override
    public void testCache() {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Course");
        Iterator iter = query.iterate();
        while(iter.hasNext()){
               System.out.println(((Course)iter.next()).getName());
        }
        tx.commit();
        session.close();

        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        query = session.createQuery("from Course");
        iter = query.iterate();
        while(iter.hasNext()){
               System.out.println(((Course)iter.next()).getName());
        }
        tx.commit();
        session.close();
    }

结果:

Hibernate:
    select
        course0_.ID as col_0_0_
    from
        clas course0_
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
计算机原理
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
计算机网络
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
数据库原理
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
C语言
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
大学英语A
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Java
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Linux
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
高等数学
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
语文
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
大学物理
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
软件工程
Hibernate:
    select
        course0_.ID as col_0_0_
    from
        clas course0_
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程

当使用Query的list()方法时,只生成一次SQL语句查询出所有的对象,使用iterate()方法时,会先得到所有对象的ID,然后根据每个ID生成一次SQL语句查询。第二个Session里面使用的也是iterate()方法,首先生成一次SQL语句,得到ID,然后根据ID查找对象,由于开启了二级缓存,在二级缓存里面找到了对象,所以就直接输出了,并没有再根据每个ID生成SQL语句。

不论是一级缓存还是二级缓存,都只能缓存对象,不能缓存属性的值。下面的例子:

    @Override
    public void testCache() {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("select c.name from Course c");
        List<String> names = query.list();
        for(Iterator iter = names.iterator(); iter.hasNext();){
            String name = (String) iter.next();
            System.out.println(name);
        }
        System.out.println("----------");
        query = session.createQuery("select c.name from Course c");
        names = query.list();
        for(Iterator iter = names.iterator(); iter.hasNext();){
            String name = (String) iter.next();
            System.out.println(name);
        }
        System.out.println("----------");
        tx.commit();
        session.close();

    }

运行结果:

Hibernate:
    select
        course0_.NAME as col_0_0_
    from
        clas course0_
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------
Hibernate:
    select
        course0_.NAME as col_0_0_
    from
        clas course0_
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------

虽然开启了二级缓存,但是查询的结果不是对象,是属性,所以并没有缓存,第2次查询仍然生成了查询语句。要解决这个问题,就需要查询缓存。

3. 查询缓存

在配置了二级缓存的基础上,可以设置查询缓存,在SessionFactory的设置里面加上一行:

<prop key="hibernate.cache.use_query_cache">true</prop>

即打开了查询缓存。查询缓存也是SessionFactory级别的缓存,在整个SessionFactory里面都是有效的。

关闭二级缓存,运行下面的例子,在Query后面添加setCacheable(true)打开查询缓存:

    @Override
    public void testCache() {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("select c.name from Course c");
        query.setCacheable(true);
        List<String> names = query.list();
        for(Iterator iter = names.iterator(); iter.hasNext();){
            String name = (String) iter.next();
            System.out.println(name);
        }
        System.out.println("----------");
        query = session.createQuery("select c.name from Course c");
        query.setCacheable(true);
        names = query.list();
        for(Iterator iter = names.iterator(); iter.hasNext();){
            String name = (String) iter.next();
            System.out.println(name);
        }
        System.out.println("----------");
        tx.commit();
        session.close();

    }

结果:

Hibernate:
    select
        course0_.NAME as col_0_0_
    from
        clas course0_
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------

由于两次查询的HQL语句是一致的,所以只生成一次SQL语句。但是如果把第二次查询改一下:

        System.out.println("----------");
        query = session.createQuery("select c.name from Course c where c.id > 5");
        query.setCacheable(true);
        names = query.list();
        for(Iterator iter = names.iterator(); iter.hasNext();){
            String name = (String) iter.next();
            System.out.println(name);
        }
        System.out.println("----------"); 

结果:

Hibernate:
    select
        course0_.NAME as col_0_0_
    from
        clas course0_
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------
Hibernate:
    select
        course0_.NAME as col_0_0_
    from
        clas course0_
    where
        course0_.ID>5
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------

由于HQL语句变了,所以第二次也生成了SQL语句。

查询缓存可以缓存属性,也可以缓存对象,但是当缓存对象时,只缓存对象的ID,不会缓存整个对象。下面的例子:

    @Override
    public void testCache() {
        // TODO Auto-generated method stub
        Session session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        Query query = session.createQuery("from Course");
        query.setCacheable(true);
        List<Course> list = query.list();
        for (int i=0; i<list.size(); i++){
            System.out.println(list.get(i).getName());
        }
        System.out.println("----------");
        tx.commit();
        session.close();

        session = sessionFactory.openSession();
        tx = session.beginTransaction();
        query = session.createQuery("from Course");
        query.setCacheable(true);
        list = query.list();
        for (int i=0; i<list.size(); i++){
            System.out.println(list.get(i).getName());
        }
        System.out.println("----------"); 

        tx.commit();
        session.close();
    }

结果:

Hibernate:
    select
        course0_.ID as ID0_,
        course0_.NAME as NAME0_,
        course0_.COMMENT as COMMENT0_
    from
        clas course0_
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
Hibernate:
    select
        course0_.ID as ID0_0_,
        course0_.NAME as NAME0_0_,
        course0_.COMMENT as COMMENT0_0_
    from
        clas course0_
    where
        course0_.ID=?
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------

由于开了查询缓存,没有开二级缓存,虽然使用的是list()方法一次查询出了所有的对象,但是查询缓存只缓存了对象ID,没有缓存整个对象。所以在第2个Session里面"from Course"这个HQL由于和前面的相同,并没有生成SQL语句,但是由于没有开二级缓存,没有缓存整个对象,只能根据每个ID去生成一次SQL语句。虽然两次用的都是list()方法,但是第一次是生成SQL语句去一次查询出所有的对象,而第二次是根据查询缓存里面的ID一个一个的生成SQL语句。

如果同时打开查询缓存和二级缓存,第2个Session里面就不用再根据ID去生成SQL语句了:

Hibernate:
    select
        course0_.ID as ID0_,
        course0_.NAME as NAME0_,
        course0_.COMMENT as COMMENT0_
    from
        clas course0_
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------
计算机原理
计算机网络
数据库原理
C语言
大学英语A
Java
Linux
高等数学
语文
大学物理
软件工程
----------
时间: 2024-11-06 02:47:26

Hibernate缓存研究的相关文章

hibernate缓存问题

转载: 很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了. 我的经验主要来自hibernate2.1版本,基本原理和3.0.3.1是一样的,请原谅我的顽固不化. hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了. 二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比

[原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

Hibernate 缓存机制

一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据. 二.what(Hibernate缓存原理是怎样的?)Hibernate缓存包括两大类:Hibernate一级缓存和Hibernate二级缓存. 1.Hibernate一级缓存又称为“Session的

10.hibernate缓存机制详细分析(转自xiaoluo501395377)

hibernate缓存机制详细分析 在本篇随笔里将会分析一下hibernate的缓存机制,包括一级缓存(session级别).二级缓存(sessionFactory级别)以及查询缓存,当然还要讨论下我们的N+1的问题. 随笔虽长,但我相信看完的朋友绝对能对hibernate的 N+1问题以及缓存有更深的了解. 一.N+1问题 首先我们来探讨一下N+1的问题,我们先通过一个例子来看一下,什么是N+1问题: list()获得对象: 1 /** 2 * 此时会发出一条sql,将30个学生全部查询出来

Hibernate缓存

一.Hibernate缓存概述 Hibernate中提供两个级别的缓存,一级缓存和二级缓存. 1.一级缓存是Session级别的缓存,它属于事物范围的缓存,一级缓存有hibernate进行管理. 2.二级缓存是sessionFactory级别的缓存,它属于进程范围的缓存,二级缓存又可分为"内置缓存"和"外置缓存",内置缓存:是hibernate在创建sessionFactory时会加载.hbn.xml文件并会在内存中初始化一些默认的sql语句,该内置缓存是只读的:外

面试中对Hibernate缓存机制的回答

这是面试中经常问到的一个问题,可以按照下面的思路回答,准你回答得很完美.首先说下Hibernate缓存的作用(即为什么要用缓存机制),然后再具体说说Hibernate中缓存的分类情况,最后可以举个具体的例子.Hibernate缓存的作用: Hibernate是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据Hibernat

WindowsPhone 8.1 新闻应用开发--缓存研究(1)

最近要开发一个新闻应用,暂定从Api获取新闻html,再放在WebView中展示(WP8.1已经把WebBrowser改成了WebView). Api还没开发好,因此参考知乎日报的Api:https://github.com/izzyleung/ZhihuDailyPurify/wiki/%E7%9F%A5%E4%B9%8E%E6%97%A5%E6%8A%A5-API-%E5%88%86%E6%9E%90 新闻应用的难点之一在于如何实现缓存,参考了一些文章,在WP上实现缓存的思路是:获取目标网址

Hibernate缓存管理

Hibernate缓存管理 ++YONG原创,转载请注明 1.    Cache简介: 缓存(Cache )是计算机领域非常通用的概念.它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能.缓存中的数据是数据存储源中数据的拷贝,应用程序在运行时直接读写缓存中的数据,只在某些特定时刻按照缓存中的数据来同步更新数据存储源. 缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬盘或磁盘,应用程序读写内在的

【转】hibernate缓存:一级缓存和二级缓存

什么是缓存? 缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能.Hibernate在进行读取数据的时候,根据缓存机制在相应的缓存中查询,如果在缓存中找到了需要的数据(我们把这称做"缓存命 中"),则就直接把命中的数据作为结果加以利用,避免了大量发送SQL语句到数据库查询的性能损耗. 缓存策略提供商 提供了HashTable缓存,EHCache,OSCache,SwarmCac