J2EE系列之Hibernate4学习笔记(十九)--hibernate高级配置(配置hibernate二级缓存)

本文详细介绍了Hibernate二级缓存的概念、分类、适用数据类型,以及如何配置和使用EHCache实现二级缓存,强调了二级缓存对于提高应用程序性能的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先要明确一下几点信息:

1,缓存的概念:

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

2,Hibernate 缓存的分类:

1、Session缓存(又称作事务缓存):Hibernate内置的,不能卸除。

缓存范围:缓存只能被当前Session对象访问。缓存的生命周期依赖于Session的生命周期,当Session被关闭后,缓存也就结束生命周期。

2、SessionFactory缓存(又称作应用缓存):使用第三方插件,可插拔。

缓存范围:缓存被应用范围内的所有session 共享,不同的Session 可以共享。这些session 有可能是并发访问缓存,因此必须对缓存进行更新。缓存的生命周期依赖于应用的生命周期,应用结束时,缓存也就结束了生命周期,二级缓存存在于应用程序范围。

3,二级缓存策略提供商:

提供了HashTable缓存,EHCache,OSCache,SwarmCache,jBoss Cathe2,这些缓存机制,其中EHCache,OSCache 是不能用于集群环境(Cluster Safe)的,而SwarmCache,jBoss Cathe2 是可以的。HashTable 缓存主要是用来测试的,只能把对象放在内存中,EHCache,OSCache 可以把对象放在内存(memory)中,也可以把对象放在硬盘(disk)上(为什么放到硬盘上?上面解释了)。

4,什么数据适合放二级缓存中:

(1)经常被访问

(2)改动不大

(3)数量有限

(4)不是很重要的数据,允许出现偶尔并发的数据。

比如组织机构代码,列表信息等;

一、新建工程Hibernate11-02

二、新建学生类Student:

package com.test.model;

public class Student {

	private long id;
	private String name;
	private Class c;
	
	public long getId() {
		return id;
	}
	public void setId(long 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;
	}
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + "]";
	}
	
	
	
}
新建班级类Class:

package com.test.model;

public class Class {

	private long id;
	private String name;
	
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	
}

2.Student类配置文件:

<?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.test.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" column="classId" class="com.test.model.Class" cascade="save-update"></many-to-one>
		
	</class>

</hibernate-mapping>

3,写Class映射文件:

<?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.test.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>

4.把这两个类的映射文件添加到hibernate配置文件中,写测试方法:

package com.test.service;

import static org.junit.Assert.*;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.test.model.Class;
import com.test.model.Student;
import com.test.util.HibernateUtil;

public class StudentTest {

	private SessionFactory sessionFactory = HibernateUtil.getSessionFactory(); // 获取Session工厂
	private Session session;
	@Before
	public void setUp() throws Exception {
		session=sessionFactory.openSession(); // 生成一个session
	    session.beginTransaction(); // 开启事务
	}

	@After
	public void tearDown() throws Exception {
		session.getTransaction().commit(); // 提交事务
	    session.close(); // 关闭session
	}

	@Test
	public void testCache1() {
		
	}
	
	

}

运行testCache1生成数据表,并往数据表t_class中添加测试数据如下:


修改测试方法:

@Test
	public void testCache1() {
		Class c = (Class) session.get(Class.class, Long.valueOf(1));
		System.out.println(c.getName());
		Class c2 = (Class) session.get(Class.class, Long.valueOf(1));
		System.out.println(c2.getName());
		System.out.println(c==c2);
	}

运行程序:


可以看到这里只运行了一次sql查询,在第一次运行sql语句查询出班级的信息后会把班级信息保存在session缓存中,当第二次取相同的班级信息时先在session缓存中取,发现该对象后直接使用,这两个对象指向了同一个OID对象。


写一个新的测试方法:

@Test
	public void testCache2() {
		Session session1 = sessionFactory.openSession();
		session1.beginTransaction();
		Class c = (Class) session1.get(Class.class, Long.valueOf(1));
		System.out.println(c.getName());
		session1.getTransaction().commit();
		session1.close();
		
		
		Session session2 = sessionFactory.openSession();
		session2.beginTransaction();
		Class c2 = (Class) session2.get(Class.class, Long.valueOf(1));
		System.out.println(c2.getName());
		session2.getTransaction().commit();
		session2.close();
	}

运行这个测试方法:


这里执行了两次sql查询,取到的两个对象为OID不同的两个对象。因为使用的session缓存不同,这两个对象占据了不同的内存空间。


上面这个例子可以看出一级session缓存是不能够共用的,不同的session使用不同的session缓存。



三、配置EHCache二级缓存

上面的例子知道不同的session使用不同的一级缓存,是不能够共享同一个一级缓存的。如果想让他们共享同一个缓存,就要用sessionfactory二级缓存了。下面配置一个EHCache二级缓存。

1.工程中添加jar包:在hibernate的安装文件中给我们提供了ehcache的jar包:hibernate-release-4.3.5.Final\lib\optional\ehcache文件夹下。在工程根目录下新建文件夹eacache,把jar包放到该文件夹下,并添加到工程中:


2.添加eacache配置文件:可以在hibernate安装包里面的demo中直接复制一个:


配置文件内容为:

<ehcache>
   
   	<!-- 指定一个文件目录,当EHCache把数据写到硬盘上时,将把数据写到这个目录下 -->
    <diskStore path="c:\\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.test.model.Class"
        maxElementsInMemory="1"
        eternal="false"
        timeToIdleSeconds="300"
        timeToLiveSeconds="600"
        overflowToDisk="true"
        />
 

</ehcache>


修改hibernate的配置文件:

<?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">123456</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>
        
        <mapping resource="com/test/model/Student.hbm.xml"/>
        <mapping resource="com/test/model/Class.hbm.xml"/>
        

    </session-factory>

</hibernate-configuration>

修改Class的映射文件:

<hibernate-mapping package="com.test.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>

这里添加了一个<cache>标签,来启动二级缓存。这样的话Class类的对象会保存到二级缓存中。


再次运行testCache2测试方法:



可以看到这里只执行了一条sql查询语句了,这里二级缓存起作用了。由于使用了不同的session,这两个对象的OID标识符不同,所以他们是不相同的。不同的session是共享同一个二级缓存的,所以这里也就没有执行新的sql查询语句。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值