【Hibernate】解析hibernate中的缓存

Hibernate中的缓存一共有三种,一级缓存、二级缓存、查询缓存。缓存除了使用Hibernate自带的缓存,还可以使用redis进行缓存,或是MongoDB进行缓存

所使用的Demo:

User.java文件

package cn.test.bean;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="user")//表示对应的表名
public class User {

    @Id
    @Column(name="uid")
    private int id;
    @Column(name="uname")
    private String name;
    @Column(name="upass")
    private String password;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }



}

User.java

hibernate.cfg.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<!-- Generated by MyEclipse Hibernate Tools.                   -->
<hibernate-configuration>
    <session-factory>
        <property name="dialect">
            org.hibernate.dialect.MySQLDialect
        </property>
        <property name="connection.url">
            jdbc:mysql://localhost:3306/test?useUnicode=true&amp;characterEncoding=utf8
        </property>
        <property name="connection.username">root</property>
        <property name="connection.password">517839</property>
        <property name="connection.driver_class">
            com.mysql.jdbc.Driver
        </property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>

        <!-- 加载映射描述信息 -->
        <mapping class="cn.test.bean.User" />

    </session-factory>
</hibernate-configuration>

hibernate.cfg.xml

其中:

        <property name="show_sql">true</property>
        <property name="format_sql">true</property>

表示开启打印底层执行的SQL日志。

下面这是图片反应了hibernate缓存的大致流程:

1,一级缓存

每个 Session 对象创建出来,就会分配一块缓存空间,可以存储 session 对象访问的对象信息。 session 关闭后会自动清除缓存,手动清除可以用session.clear() , session.evict(obj) 。 Session 一级缓存是独享。
load/get/save/update/saveorupdate 方法处理的对象都会放入缓存中

复制代码
Configuration conf = new Configuration();
conf.configure("hibernate.cfg.xml");//读取连接参数和映射描述信息
SessionFactory factory = conf.buildSessionFactory();
Session session = factory.openSession();

User user1 = (User)session.load(User.class,1);
System.out.println(user1.getName());//honny,如果不调用用getName()方法,那么数据不会显示,因为load()默认使用的是一种延迟加载的机制,只有使用到数据的时候才会到数据库中查询

//先从session缓存中查找,如果没找到再去数据库获取
User user2 = (User)session.load(User.class,1);
System.out.println(user2.getName());//honny
            
System.out.println(user1==user2);//true,因为user1和user2使用的是同一个session
复制代码

然后再来看一看控制台:

从控制台中,我们也可以看出上只执行了一次SQL查询。

 

一级查询的优缺点:

优点:可以减少查询数据库的次数,加快查询速度。
缺点:在批量操作中容易导致内存溢出问题。

2,二级缓存

二级缓存是SessionFactory 对象缓存,可以被创建出的多个 Session 对象共享。

下面是一张图片体现一级缓存和二级缓存的关系:

从这个我们就看出了二级缓存包含了一级缓存。

二级缓存默认是关闭的,如果要使用需要手动开启,下面是开启过程:

1.导入ehcache 工具包和 ehcache.xml 配置文件(配置文件放到src路径下)

echache工具包包括:ehcache-core-2.4.3.jar,hibernate-ehcache-4.2.21.Final.jar,slf4j-api-1.6.1.jar

ehcache.xml 文件

复制代码
<!--
  ~ Hibernate, Relational Persistence for Idiomatic Java
  ~
  ~ Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
  ~ indicated by the @author tags or express copyright attribution
  ~ statements applied by the authors. All third-party contributions are
  ~ distributed under license by Red Hat Middleware LLC.
  ~
  ~ This copyrighted material is made available to anyone wishing to use, modify,
  ~ copy, or redistribute it subject to the terms and conditions of the GNU
  ~ Lesser General Public License, as published by the Free Software Foundation.
  ~
  ~ This program is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->
<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

         If the path is a Java System Property it is replaced by
         its value in the running VM.

         The following properties are translated:
         user.home - User's home directory
         user.dir - User's current working directory
         java.io.tmpdir - Default temp file path -->
    <diskStore path="./target/tmp"/>


    <!--Default Cache configuration. These will applied to caches programmatically created through
        the CacheManager.

        The following attributes are required for defaultCache:

        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        />

    <!--Predefined caches.  Add your cache configuration settings here.
        If you do not have a configuration for your cache a WARNING will be issued when the
        CacheManager starts

        The following attributes are required for defaultCache:

        name              - Sets the name of the cache. This is used to identify the cache. It must be unique.
        maxInMemory       - Sets the maximum number of objects that will be created in memory
        eternal           - Sets whether elements are eternal. If eternal,  timeouts are ignored and the element
                            is never expired.
        timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
                            if the element is not eternal. Idle time is now - last accessed time
        timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
                            if the element is not eternal. TTL is now - creation time
        overflowToDisk    - Sets whether elements can overflow to disk when the in-memory cache
                            has reached the maxInMemory limit.

        -->

    <!-- Sample cache named sampleCache1
        This cache contains a maximum in memory of 10000 elements, and will expire
        an element if it is idle for more than 5 minutes and lives for more than
        10 minutes.

        If there are more than 10000 elements it will overflow to the
        disk cache, which in this configuration will go to wherever java.io.tmp is
        defined on your system. On a standard Linux system this will be /tmp"
        -->
    <cache name="sampleCache1"
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />

    <!-- Sample cache named sampleCache2
        This cache contains 1000 elements. Elements will always be held in memory.
        They are not expired. -->
    <cache name="sampleCache2"
        maxElementsInMemory="1000"
        eternal="true"
        timeToIdleSeconds="0"
        timeToLiveSeconds="0"
        overflowToDisk="false"
        /> -->

    <!-- Place configuration for your caches following -->

</ehcache>
复制代码
ehcache.xml

2.在 hibernate.cfg.xml 中配置参数开启二级缓存,启用 ehcache

<property name="hibernate.cache.use_sencond_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">
org.hibernate.cache.ehcache.EhCacheRegionFactory
</property>

3.在要缓存的对象类型中,指定 @Cache 注解标记

复制代码
@Entity
@Table(name="user")//表示对应的表名
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class User {
    //........
}
复制代码

到这里hibernate的二级缓存配置就配好了,下面来测试一下:

复制代码
Configuration conf = new Configuration();
conf.configure("hibernate.cfg.xml");//读取连接参数和映射描述信息
SessionFactory factory = conf.buildSessionFactory();
Session session1 = factory.openSession();
User user1=(User)session1.load(User.class, 1);
System.out.println(user1.getName());//honny

Session session2 = factory.openSession();
//先从缓存中查找,如果没有查到再去数据库中取
User user2=(User)session2.load(User.class, 1);
System.out.println(user2.getName());//honny
复制代码

下面是控制台打印的打印:

我们可以看出,用同一个SessionFactory的两个不同session对象查询相同的数据,只从数据库中取了一次。

3,查询缓存

一级和二级缓存,只能缓存单个对象,如果需要缓存一个结果集,必须使用查询缓存。

查询缓存默认也是关闭的,如需使用需要手动开启,下面是开启过程:

1.针对的对象必需已经开启了二级缓存

2.在 hibernate.cfg.xml 中添加开启查询缓存的配置

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

3.在查询执行前,调用 query.setCacheable(true); 

下面看一看测试:

复制代码
        String hql="from User";
        Configuration conf=new Configuration();
        conf.configure("hibernate.cfg.xml");
        SessionFactory factory=conf.buildSessionFactory();
        Session session1 = factory.openSession();
        Query query1 = session1.createQuery(hql);
        query1.setCacheable(true);//设置开启缓存
        List list1 = query1.list();
        for(Object user:list1){
            System.out.println(((User)user).getName());
        }
        System.out.println("------------------------");
        Session session2 = factory.openSession();
        Query query2 = session2.createQuery(hql);
        query2.setCacheable(true);
        List list2 =query2.list();
        for(Object user:list2){
            System.out.println(((User)user).getName());
        }
复制代码

然后来看一看控制台:

从控制台中,我们可以看出,底层查询的数据库的过程也只执行了一次。

 

上面就是hibernate的三种缓存。最后总结一下,并不是所有的方法都会产生缓存效果,只有“load/get/save/update/saveorupdate”才会产生缓存效果。三种缓存中一级缓存是默认开启的,二级缓存和三级缓存默认是关闭的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
hibernate 3缓存小结 2.2. 一级缓存的管理: 当应用程序调用Session的save()、update()、savaeOrUpdate()、get()或load(),以及调用查询接口的list()、iterate()或filter()方法时,如果在Session缓存还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存。当清理缓存时,Hibernate会根据缓存对象的状态变化来同步更新数据库。 Session为应用程序提供了两个管理缓存的方法: evict(Object obj):从缓存清除参数指定的持久化对象。 clear():清空缓存所有持久化对象。 2.3. 二级缓存的管理: 2.3.1. Hibernate的二级缓存策略的一般过程如下: 1) 条件查询的时候,总是发出一条select * from table_name where …. (选择所有字段)这样的SQL语句查询数据库,一次获得所有的数据对象。 2) 把获得的所有数据对象根据ID放入到第二级缓存。 3) 当Hibernate根据ID访问数据对象的时候,首先从Session一级缓存查;查不到,如果配置了二级缓存,那么从二级缓存查;查不到,再查询数据库,把结果按照ID放入到缓存。 4) 删除、更新、增加数据的时候,同时更新缓存。   Hibernate的二级缓存策略,是针对于ID查询的缓存策略,对于条件查询则毫无作用。为此,Hibernate提供了针对条件查询的Query Cache。 2.3.2. 什么样的数据适合存放到第二级缓存? 1 很少被修改的数据 2 不是很重要的数据,允许出现偶尔并发的数据 3 不会被并发访问的数据 4 参考数据,指的是供应用参考的常量数据,它的实例数目有限,它的实例会被许多其他类的实例引用,实例极少或者从来不会被修改。 2.3.3. 不适合存放到第二级缓存的数据? 1 经常被修改的数据 2 财务数据,绝对不允许出现并发 3 与其他应用共享的数据。 2.3.4. 常用的缓存插件 Hibernater 的二级缓存是一个插件,下面是几种常用的缓存插件: l EhCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持。 l OSCache:可作为进程范围的缓存,存放数据的物理介质可以是内存或硬盘,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持。 l SwarmCache:可作为群集范围内的缓存,但不支持Hibernate的查询缓存。 l JBossCache:可作为群集范围内的缓存,支持事务型并发访问策略,对Hibernate的查询缓存提供了支持。 2.3.5. 配置二级缓存的主要步骤: 1) 选择需要使用二级缓存的持久化类,设置它的命名缓存的并发访问策略。这是最值得认真考虑的步骤。 2) 选择合适的缓存插件,然后编辑该插件的配置文件。 2.4. 使用EhCache配置二级缓存: 2.4.1. 配置准备: 1) 把ehcache-1.2.3.jar加入到当前应用的classpath。 2) 在hibernate.cfg.xml文件加入EhCache缓存插件的提供类。 <!--配置缓存插件 --> <property name="hibernate.cache.provider_class"> org.hibernate.cache.EhCacheProvider </property> 3) 挎贝ehcache.xml文件到类路径(项目工程的src目录下),这个文件在Hibernate安装目录的etc下。 2.4.2. 配置步骤: Hibernate允许在类和集合的粒度上设置第二级缓存。在映射文件,<class>和<set>元素都有一个<cache>子元素,这个子元素用来配置二级缓存。 示例:以category(产品类别)和product(产品)的映射为例: 1) 修改要配置缓存的那个持久化类的对象关系映射文件: Category.hbm.xml <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="org.qiujy.domain.cachedemo.Category" table="categories"> <!— 配置缓存,必须紧跟在class元素后面 对缓存的Category对象采用读写型的并发访问策略 --> <cache usage="read-write"/> <id name="id" type="java.lang.Long"> <column name="id" /> <generator class="native" /> </id> <!-- 配置版本号,必须紧跟在id元素后面 --> <version name="version" column="version" type="java.lang.Long" /> <property name="name" type="java.lang.String"> <column name="name" length="32" not-null="true"/> </property> <property name="description" type="java.lang.String"> <column name="description" length="255"/> </property> <set name="products" table="products" cascade="all" inverse="true"> <!-- Hibernate只会缓存对象的简单属性的值, 要缓存集合属性,必须在集合元素也加入<cache>子元素 而Hibernate仅仅是把与当前持久对象关联的对象的OID存放到缓存。 如果希望把整个关联的对象的所有数据都存入缓存, 则要在相应关联的对象的映射文件配置<cache>元素 --> <cache usage="read-write"/> <key column="categoryId" not-null="true"/> <one-to-many class="org.qiujy.domain.cachedemo.Product"/> </set> </class> </hibernate-mapping>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值