复习 - Hibernate的缓存(主要是二级缓存)
对缓存做一下简单的总结和复习.
首先我们知道Hibernate的缓存有Session级别和SessionFactory级别的,也就是一级缓存和二级缓存. 顾名思义,一级缓存是不能跨session的,这样,不同的session里面,就不能共享信息,这样我们就需要跨session的二级缓存, 即可以共享不同session中的信息。 关于这个就不写例子了,记着就行了..
首先从较高的层次来总结一下缓存的作用范围.
1. 事务级别(Transaction level)
事务级别的缓存其作用范围仅限于单个Hibenate Session中,一级缓存属于事务级别的缓存
2. 进程级别(Process level)
进程级别的缓存其作用范围并不限于单个的Hibernate Session了,而是扩展至整个JVM进程. 二级缓存属于进程级别的缓存
3. 集群级别(Cluster level)
集群级别的缓存作用范围则不限于JVM,而是跨JVM,甚至跨实际机器,即分布式的缓存.
ok,事务的类型做了一下介绍,接着来看看同步策略.
什么是同步策略呢?
我们可以考虑一个问题:在进行开发时,我们指定了相应的事务隔离级别(即使没有显式的指定,也有默认的啦., P.S. 我自己觉得事务隔离级别事实上就是对数据库中的数据进行读写上的控制(实现其实就是加锁),已保证各种事务问题(如: 丢失更新,不可重复读等等)不发生). 但是现在的问题是我们开启了缓存,这个时候应用程序可以直接从缓存里面读取数据,而不用去数据库中读取,并且可以将修改后的数据写入缓存,这个时候原先的事务隔离级别肯定就有问题了,因为它控制的仅仅是数据库中的记录,而管不了缓存中的数据啊. ------ 我的理解是这样,不知道是否正确.
问题出来了,那么同步策略的作用就很明了了: 同步缓存和数据库中的数据,以保障应用程序原先设定的隔离级别.
有如下几种同步策略:
1. read-only : 仅适用于只读数据
2. Nonstrict-read-write : 不是很严格的读写, 不能保证缓存和数据库中的数据保持一致, 缓存里面的数据可能是过期的.
3. Read-write : 较为严格的读写控制, 保证read-commited的隔离级别.
4. Transactional: 可以保证repeatable read的隔离级别.
二级缓存适用的对象一般具有如下特性:
1. 很少修改
2. 非关键性数据
3. 不和其他的应用系统共享数据
4. 读取很频繁
5. 数据量不大.
一些常用的二级缓存提高者:
EHCache, Jboss Cache, OsCache, SwarmCache.
好了,需要的基础知识基本完了,下面该动手实践啦.......这里使用EHCache,步骤如下:
1. 首先是hibernate.cfg.xml里面需要加入cache提供者的相关信息:
<property name="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</property>
2. 然后就是要配置ehcache,文件名为ehcache.xml,你可以把它放在classpath下面.
<ehcache>
<diskStore path="c:\data\ehcache" />
<defaultCache maxElementsInMemory="10000" eternal="false"
overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" />
</ehcache>
3. 接着就配置要使用的同步策略,之前说过的那几种,这里我使用read-write.
配置的方法有两种.
<1>. 在hibernate.cfg.xml里面配置,必须放在<mapping>后面
<class-cache usage="read-write" class="com.yxy.bean.Student"/>
<2>. 在对应实体的hbm文件里面配置,必须放在<id>之前
<class name="Student" table="student" select-before-update="true">
<cache usage="read-only"/>
<id name="id" type="int">
<generator class="native" />
</id>
<property name="name" type="string" column="name"/>
<property name="sex" type="string" column="sex"/>
<property name="registerDate" type="date" column="register_date"/>
</class>
两种选一种就行了..
4. 决定使用何种CacheMode.(即决定如何去对待缓存)
总共有5种模式:
<1> CacheMode.PUT Hibernate会将从db读取出来的数据放入二级缓存,但是不会从二级缓存中拿数据,也就是只放不拿.
<2> CacheMode.NORMAL 这个是默认的行为,即需要数据时,首先去二级缓存里面查看有没有,没有的话就去db里面查找,找到后顺便把数据放入二级缓存中.
<3> CacheMode.IGNORE 无视Hiberante的二级缓存.相当于没有开启二级缓存,不会往里面放,也不会从里面拿
<4> CacheMode.GET 这个和PUT相对,这个只拿不放
<5> CacheMode.REFRESH 这个和只放不拿(PUT)类似.
5. 测试:
首先看看CacheMode为PUT时的效果..如果不出意外,应该是只会往缓存中放,而不会从缓存中取.
package com.yxy.test;
import org.hibernate.CacheMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.stat.Statistics;
import com.yxy.bean.Student;
public class HibernateCacheTest {
public static void main(String[] args){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
/*
* 保证之前二级缓存中的student数据都被清理掉
*/
sessionFactory.evict(Student.class);
Session session = sessionFactory.openSession();
/*
* 设置CacheMode
*/
session.setCacheMode(CacheMode.PUT);
Statistics stat = sessionFactory.getStatistics();
session.getTransaction().begin();
stat.setStatisticsEnabled(true);
Student s1 = (Student)session.get(Student.class, 1);
System.out.println(stat.getSecondLevelCacheHitCount());
System.out.println(stat.getSecondLevelCacheMissCount());
System.out.println(stat.getSecondLevelCachePutCount());
Student s2 = (Student)session.get(Student.class, 2);
System.out.println(stat.getSecondLevelCacheHitCount());
System.out.println(stat.getSecondLevelCacheMissCount());
System.out.println(stat.getSecondLevelCachePutCount());
stat.setStatisticsEnabled(false);
session.getTransaction().commit();
session.close();
}
}
输出的结果:
Hibernate:
/* load com.yxy.bean.Student */ select
student0_.id as id0_0_,
student0_.name as name0_0_,
student0_.sex as sex0_0_,
student0_.register_date as register4_0_0_
from
student student0_
where
student0_.id=?
0
0
1
Hibernate:
/* load com.yxy.bean.Student */ select
student0_.id as id0_0_,
student0_.name as name0_0_,
student0_.sex as sex0_0_,
student0_.register_date as register4_0_0_
from
student student0_
where
student0_.id=?
0
0
2
从输出我们可以看到,Hiberante并不会尝试去二级缓存里面查找: System.out.println(stat.getSecondLevelCacheMissCount())为0, 但是一旦从db里面找出数据,是会把数据放入二级缓存的.
接下来可以测试一下默认情况,也就是CacheMode.NORMAL.
例子如下,会有两个session:
package com.yxy.test;
import org.hibernate.CacheMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.stat.Statistics;
import com.yxy.bean.Student;
public class HibernateCacheTest {
public static void main(String[] args){
SessionFactory sessionFactory = HibernateUtils.getSessionFactory();
/*
* 保证之前二级缓存中的student数据都被清理掉
*/
// sessionFactory.evict(Student.class);
Session session = sessionFactory.openSession();
/*
* 设置CacheMode
*/
session.setCacheMode(CacheMode.NORMAL);
Statistics stat = sessionFactory.getStatistics();
session.getTransaction().begin();
stat.setStatisticsEnabled(true);
Student s1 = (Student)session.get(Student.class, 1);
System.out.println(stat.getSecondLevelCacheHitCount());
System.out.println(stat.getSecondLevelCacheMissCount());
System.out.println(stat.getSecondLevelCachePutCount());
Student s2 = (Student)session.get(Student.class, 2);
System.out.println(stat.getSecondLevelCacheHitCount());
System.out.println(stat.getSecondLevelCacheMissCount());
System.out.println(stat.getSecondLevelCachePutCount());
stat.setStatisticsEnabled(false);
session.getTransaction().commit();
session.close();
/*
* 开启另外一个session
*/
System.out.println("------------------ another session -----------------");
session = sessionFactory.openSession();
/*
* 设置CacheMode
*/
session.setCacheMode(CacheMode.NORMAL);
stat = sessionFactory.getStatistics();
stat.clear();
session.getTransaction().begin();
stat.setStatisticsEnabled(true);
s1 = (Student)session.get(Student.class, 1);
System.out.println(stat.getSecondLevelCacheHitCount());
System.out.println(stat.getSecondLevelCacheMissCount());
System.out.println(stat.getSecondLevelCachePutCount());
s2 = (Student)session.get(Student.class, 2);
System.out.println(stat.getSecondLevelCacheHitCount());
System.out.println(stat.getSecondLevelCacheMissCount());
System.out.println(stat.getSecondLevelCachePutCount());
stat.setStatisticsEnabled(false);
session.getTransaction().commit();
session.close();
}
}
输出的情况如下:
Hibernate:
/* load com.yxy.bean.Student */ select
student0_.id as id0_0_,
student0_.name as name0_0_,
student0_.sex as sex0_0_,
student0_.register_date as register4_0_0_
from
student student0_
where
student0_.id=?
0
1
1
Hibernate:
/* load com.yxy.bean.Student */ select
student0_.id as id0_0_,
student0_.name as name0_0_,
student0_.sex as sex0_0_,
student0_.register_date as register4_0_0_
from
student student0_
where
student0_.id=?
0
2
2
------------------ another session -----------------
1
0
0
2
0
0
在第一个session中,由于默认的会首先去二级缓存中找数据,结果是: 命中0次,miss两次,放入两次. 这时二级缓存中已经存在id为1,2的Student的数据了,
在第二个session中,由于之前缓存的数据,所以两次都命中了,而且不会发出sql从db里面取数据. 这就是二级缓存的效果!
其他的几种CacheMode也可以做类似的测试,就不在这里弄了.
最后有一个值得注意的知识点: 查询缓存
上面的这些查询,基本上都是通过主键(ID)来获得一个实体,然后存入缓存,其实对于一堆数据,也是可以存入二级缓存的,即查询缓存.
对于查询缓存,当结果集很大的时候,也需要谨慎使用,因为毕竟它使用的是内存.
开启查询缓存的设置(hibernate.cfg.xml)
<property name="hibernate.cache.use_query_cache">true</property>
具体的示例就不在这里写了. Go for lunch first....
分享到:
相关推荐
"SVSE-S3冲刺题-Hibernate笔试题"这个标题表明这是一个针对SVSE(可能是软件版本、课程阶段或某个特定考试体系的缩写)第三阶段的冲刺复习资料,重点是Hibernate相关的笔试题目。Hibernate是一个开源的对象关系映射...
**J2EE复习积累(六)-Hibernate4.2** 在J2EE开发中,Hibernate作为一款流行的ORM(对象关系映射)框架,极大地简化了Java应用程序与数据库之间的交互。本篇复习将聚焦于Hibernate 4.2版本,该版本在前一版本的基础上...
《Hibernate达内五天复习笔记》是一份详细记录了Hibernate框架学习的资料,旨在帮助读者深入理解并掌握Hibernate这一强大的Java持久化框架。以下是笔记中的主要知识点: 1. **ORM原理**: - **对象持久化**:将...
而《Hibernate—Java对象持久化技术-Hibernate进阶.ppt》则深入讲解了高级特性和最佳实践,如缓存机制、事务管理和性能优化。 5. **上课笔记** 提供的三份上课笔记《上课笔记t1.txt》、《上课笔记.txt》和《上课...
本复习旨在深入理解Hibernate的核心概念、配置及常用API,帮助开发者提高开发效率。 一、Hibernate概述 Hibernate是Java领域中流行的ORM(Object-Relational Mapping)框架,它通过映射关系数据库与Java类,实现了...
- **缓存机制**: Hibernate 提供了两种级别的缓存:一级缓存是强制性的,二级缓存则是可选的。合理使用缓存可以显著提高应用程序的性能。 - **事务管理**: Hibernate 支持自动提交和手动提交模式,同时也支持声明式...
### Hibernate 3.6.0.Final 参考手册知识点概览 #### 1. 教程 **1.1 第一部分—第一...这些知识点不仅对初学者了解Hibernate的基本用法非常有帮助,对于已经有一定经验的开发者来说也是很好的复习和深入学习的机会。
- 使用缓存机制,如一级缓存和二级缓存。 - 适当使用批处理(batch-size)。 - 避免过多的N+1查询问题,通过JOIN fetch进行关联查询。 - 使用HQL或Criteria API代替原生SQL,减少数据类型转换的开销。 - 选择...
**标题:“Hibernate4.1.1的Demo实例”** **描述**:这个Demo实例深入浅出地展示了Hibernate 4.1.1版本的核心特性和使用方法。...同时,对于有经验的开发者,这也是复习和巩固Hibernate知识的一个好资料。
全面讲解hibernate,缓存,配置, 以及状态
9. **缓存机制**:为了提高性能,Hibernate引入了缓存,包括第一级缓存(Session级别的缓存)和第二级缓存(SessionFactory级别的缓存),以及第三方缓存插件如Ehcache。 10. **实体状态**:Hibernate定义了四种...
《传智播客2016 Hibernate框架学习笔记》是一份详实的教程,旨在帮助初学者和进阶者深入理解和掌握Hibernate框架。...这些笔记不仅适合初学者,也为有经验的开发者提供了一个复习和深化Hibernate知识的良好资源。
**标题:“Hibernate_使用示例代码”** **描述:** 这篇资源主要提供了关于Hibernate框架的实战应用示例,作者在iteye...对于初学者,这是一个很好的起点,对于有经验的开发者,也是复习和巩固Hibernate技能的好材料。
Java面试复习总结主要涵盖了几大框架的技术点,包括Tapestry、Struts、SpringMVC、Spring、Hibernate和MyBatis,以及拦截器和过滤器的相关概念。 1. **Tapestry**: - Tapestry是一个MVC+模板技术的前端框架,其...
在学习Hibernate之前,复习JDBC是必要的。JDBC提供了连接数据库、执行SQL语句、处理结果集等功能。主要接口包括: - `Connection`: 提供了数据库信息,如表、SQL语法等。 - `Driver`: 数据库驱动实现的接口。 - `...
在Java面试中,尤其涉及到企业级应用开发时,面试官常常会关注候选人在SSM(Spring、Spring MVC、MyBatis)和SSH(Spring、Struts、Hibernate)这些主流Java EE框架上的...通过复习和实践,可以提高在面试中的竞争力。
3. Hibernate配置文件的设置,包括数据源、实体扫描路径、二级缓存等配置。 4. HQL(Hibernate Query Language)和Criteria API的使用,进行复杂的数据库查询。 5. 日志系统的配置和使用,了解slf4j的基本原理和API...
本课程资料旨在提供全面、深入的Hibernate学习资源,帮助初学者快速掌握ORM的核心概念,同时也为有经验的开发者提供复习和深化理解的机会。 一、Hibernate概述 Hibernate是一个强大的持久化框架,它简化了Java应用...
8. **缓存机制**:为了提高性能,Hibernate提供了二级缓存机制。一级缓存是Session级别的,自动管理;二级缓存则可以跨Session共享,需要在配置文件中开启并选择合适的缓存提供商。 9. **配置连接池**:为优化...
本文将详细解析“Hibernate做题步骤”,为那些初学者或需要复习该主题的开发者提供一个清晰、系统的指南。 ### 一、理解Hibernate及其作用 Hibernate是一个开源的持久层框架,它简化了对象与关系数据库之间的映射...