Hibernate学习11——配置Hibernate二级缓存

Posted 有点懒惰的大青年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hibernate学习11——配置Hibernate二级缓存相关的知识,希望对你有一定的参考价值。

一、缓存的概念:                                                

以空间换时间;
 
二、Hibernate缓存的分类:                                        
前面我们讲的缓存都是session缓存;也叫一级缓存;get,load等缓存都是内置的,一级缓存;
SessionFactory缓存,二级缓存;

 

这里以Class —— Student,1对多的关系(单向)来例子说明下:

Class.java:

package com.cy.model;

public class Class {
    private int id;
    private String name;
    
    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;
    }
    
    
}
View Code

Student.java:

package com.cy.model;

import com.cy.model.Class;

public class Student {
    private int id;
    private String name;
    private Class c;
    
    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 Class getC() {
        return c;
    }
    public void setC(Class c) {
        this.c = c;
    }
    
    
}
View Code

Class.hbm.xml:

<hibernate-mapping package="com.cy.model">

    <class name="Class" table="t_class">
        <id name="id" column="classId">
            <generator class="native"></generator>
        </id>
        <property name="name" column="className"></property>
    </class>

</hibernate-mapping>
View Code

Student.hbm.xml:

<hibernate-mapping package="com.cy.model">

    <class name="Student" table="t_student">
        <id name="id" column="stuId">
            <generator class="native"></generator>
        </id>
        <property name="name" column="stuName"></property>
        
        <many-to-one name="c" class="com.cy.model.Class" column="classId" cascade="save-update"></many-to-one>
    </class>

</hibernate-mapping>
View Code

StudentTest.java:

package com.cy.service;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import com.cy.model.Class;
import com.cy.util.HibernateUtil;

public class StudentTest {

    private SessionFactory sessionFactory=HibernateUtil.getSessionFactory();
    private Session session;
    
    @Before
    public void setUp() throws Exception {
        session=sessionFactory.openSession(); 
        session.beginTransaction();
    }

    @After
    public void tearDown() throws Exception {
         session.getTransaction().commit();
         session.close();
    }
    
    /**
     * 同一个session中,同一个事务是有一级缓存的;
     */
    @Test
    public void testCache1(){
        Class c = (Class) session.get(Class.class, 1);
        System.out.println(c.getName());
        
        Class c2 = (Class) session.get(Class.class, 1);
        System.out.println(c2.getName());
        System.out.println(c == c2);
        
        /*
         *  Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=?
            08计算机本科
            08计算机本科
            true
            
            第一次取c1的时候,已经将取出来的数据c1放到缓存中。
            第二次取c2的时候,是有session缓存的。首选从缓存中找,找到,直接从缓存中拿,而不到数据库中去取了。
            两个是同一个OID对象;
         */
    }
    
    /**
     * 在不同的事务中,是否有缓存?
     */
    @Test
    public void testCache2(){
        Session session1 = sessionFactory.openSession();
        session1.beginTransaction();
        Class c = (Class) session1.get(Class.class, 1);
        System.out.println(c.getName());
        session1.getTransaction().commit();
        session1.close();
        
        
        Session session2 = sessionFactory.openSession();
        session2.beginTransaction();
        Class c2 = (Class) session2.get(Class.class, 1);
        System.out.println(c2.getName());
        session2.getTransaction().commit();
        session2.close();
        
        System.out.println(c == c2);
        /*
         *  Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=?
            08计算机本科
            Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=?
            08计算机本科
            false
            
            虽然在同一个session中有缓存,但是这里新开辟了一个事务,发出两个sql
            不同的事务是不能共用一级缓存的。
            一级缓存只适用于同一个session,同一个事务;
         */
    }
}
View Code

 

三、二级缓存策略提供商:                                          

配置ehcache二级缓存,让不同的session,不同的事务能共享数据。
要用到SessionFactory缓存了;
 
使用到的ehcache相关的jar包:

jar包在hibernate压缩包中:
hibernate-release-4.3.5.Final\\lib\\optional\\ehcache
可以参考hibernate压缩包中的hibernate-ehcache的配置:
hibernate-release-4.3.5.Final\\project\\hibernate-ehcache\\bin
hibernate-release-4.3.5.Final\\project\\hibernate-ehcache\\bin\\hibernate-config\\ehcache.xml 以及hibernate.cfg.xml
 
代码实现:
1)ehcache.xml配置:
<ehcache>
   
       <!-- 指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个目录下 -->
    <diskStore path="E:\\\\ehcache"/>
    
    <!--  
        设置缓存的默认数据过期策略 
    -->    
    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
     />

    <!-- 
        name 设置缓存的名字,他的取值为类的完整名字或者类的集合的名字;
        maxElementsInMemory 设置基于内存的缓存可存放的对象的最大数目
        eternal 如果为true,表示对象永远不会过期,此时会忽略timeToIdleSeconds和timeToLiveSeconds,默认为false;
        timeToIdleSeconds 设定允许对象处于空闲状态的最长时间,以秒为单位;
        timeToLiveSeconds 设定对象允许存在于缓存中的最长时间,以秒为单位;
        overflowToDisk 如果为true,表示当基于内存的缓存中的对象数目达到maxElementsInMemory界限,会把溢出的对象写到基于硬盘的缓存中;
     -->


    <!-- 设定具体的第二级缓存的数据过期策略 -->
    <cache name="com.cy.model.Class"
        maxElementsInMemory="1"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
     />
 

</ehcache>
View Code

2)hibernate.cfg.xml中相关ehcache二级缓存的配置:

<?xml version=\'1.0\' encoding=\'utf-8\'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>

    <session-factory>

        <!--数据库连接设置 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
       
        <!-- 方言 -->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
    
        <!-- 控制台显示SQL -->
        <property name="show_sql">true</property>

        <!-- 自动更新表结构 -->
        <property name="hbm2ddl.auto">update</property>
        
         <!-- 启用二级缓存 -->
        <property name="cache.use_second_level_cache">true</property>
        <!-- 配置使用的二级缓存的产品 -->
        <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
        <!-- 配置启用查询缓存 -->
        <property name="cache.use_query_cache">true</property>
        <property name="net.sf.ehcache.configurationResourceName">ehcache.xml</property>
        
        <mapping resource="com/cy/model/Student.hbm.xml"/>
        <mapping resource="com/cy/model/Class.hbm.xml"/>
    </session-factory>

</hibernate-configuration>

3)最后,Class.hbm.xml中配置使用cache:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.cy.model">

    <class name="Class" table="t_class">
        <cache usage="read-only"/>
        <id name="id" column="classId">
            <generator class="native"></generator>
        </id>
        <property name="name" column="className"></property>
    </class>

</hibernate-mapping>

4)测试代码:

/**
     * 配置了二级缓存ehcache后,再次进行测试:
     */
    @Test
    public void testCache3(){
        Session session1 = sessionFactory.openSession();
        session1.beginTransaction();
        Class c = (Class) session1.get(Class.class, 1);
        System.out.println(c.getName());
        session1.getTransaction().commit();
        session1.close();
        
        
        Session session2 = sessionFactory.openSession();
        session2.beginTransaction();
        Class c2 = (Class) session2.get(Class.class, 1);
        System.out.println(c2.getName());
        session2.getTransaction().commit();
        session2.close();
        
        System.out.println(c == c2);
        /*
         *  Hibernate: select class0_.classId as classId1_0_0_, class0_.className as classNam2_0_0_ from t_class class0_ where class0_.classId=?
            08计算机本科
            08计算机本科
            false
            
            只有1条sql,说明在第2次查的时候,使用到了二级缓存。
         */
        
    }
View Code

 

 

四、什么数据适合放二级缓存中                                    

一般这些信息都是只读;不能修改;
 
 
 

以上是关于Hibernate学习11——配置Hibernate二级缓存的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate 学习-2

Hibernate配置(外部配置文件方式)

请说说你对Hibernat的理解?JDBC和Hibernate各有什么优势和劣势?

Spring整合Hibernate

Hibernat 原生SQL运行结果集处理方法

hibernate关联映射注解