Hibernate学习笔记--------3.缓存
一、一级缓存
一级缓存又称为“Session缓存”或者“会话级缓存”,通过Session从数据库查询实体时,会把实体在内存中存储起来,下一次查询同一实体时不再再次执行sql语句查询数据库,而是从内存中获取。一级缓存的生命周期和Session相同。一级缓存是无法取消的。
1.一级缓存中的数据可适用范围在当前会话之类,例如用同一个session查询两次user表和同两个session查询俩次user表,查询数据库的次数是不一样的。首先,像这样查询两次,可以看见打印的sql语句只有一次,因为第二次是直接从当前session缓存中取的。
但是把注释去掉,就会发现,sql打印了两次,因为他执行了两次数据库的查询操作。
/**
* 一级缓存
*/
@Test
public void cacheTest() {
Tb_User u = session.get(Tb_User.class, "1");
System.out.println(u.getName());
//session = sessionFactory.openSession();
u = session.get(Tb_User.class, "1");
System.out.println(u.getName());
}
2.evict 、clear
evict方法:清除一级缓存中的指定对象;
clear方法:清除一级缓存的所有对象。
这段代码打印的sql语句打印了两次,结果很明显。
@Test
public void cacheTest() {
Tb_User u = session.get(Tb_User.class, "1"); //清除一级缓存中的指定对象
//session.evict(u); //清楚一级缓存中的所有对象
session.clear(); u = session.get(Tb_User.class, "1");
}
3.query.list | query.getResultList
这两个方法是一样的,但是现在我看提示说query.list是废弃的。他们都不使用缓存,执行下面这段代码,可以很明确的看见打印了两次sql,这两个方法都是不使用缓存的,但是会把查询出来的数据存入缓存中。
/**
* 一级缓存
*/
@Test
public void cacheTest() { Query query = session.createQuery("From Tb_User");
List<Tb_User> list = query.getResultList();
for(Tb_User u : list){
System.out.println(u.getName());
} list = query.getResultList();
for(Tb_User u : list){
System.out.println(u.getName());
} }
4.query.iterate()
若用迭代器Iterator,从打印的sql来看,他只查询了id,然后还是打印了Name,因为query.iterate()用到了缓存,他也会把查询出来的数据存入缓存中。
/**
* 一级缓存
*/
@Test
public void cacheTest() { Query query = session.createQuery("From Tb_User");
List<Tb_User> list = query.getResultList();
for(Tb_User u : list){
System.out.println(u.getName());
} Iterator it = query.iterate();
while(it.hasNext()){
Tb_User u = (Tb_User)it.next();
System.out.println(u.getName());
} }
query.iterate()怎么使用缓存?
把代码query.getResultList()相关的几行注释掉,执行后,可以看见打印的sql语句,先查询了id,然后根据id用where去数据挨着查询出来,我的数据库里有3条数据,所有一共查询了4次数据库。
query.iterator会先去查询数据库中的id,然后根据id,先在缓存中查找是否有相应的数据,有则直接用,没有则从数据库中找。
解释下前面的代码结果:
若query.iterator遍历方法之前执行了list方法,list方法查询出来的数据被缓存了,但list方法不使用缓存,因此再次执行list时会重新查询数据库,而iterator方法只从数据库查询id,这时每个id在内存中都有对应的值,所以Name属性是从内存中取出来的。
若query.iterator遍历方法之前没有执行了list方法,那么此时数据并没有缓存在内存中,那么iterator方法依然会先查询id,在遍历时,发现内存中根据id找不到该数据,于是就发送sql到数据库中找,此时Name属性就是真的从数据库中现场查找出来的了。
若query.iterator遍历方法之前执行了query.iterator遍历方法,那么结果和第一种情况类似,他会先依次在数据库中查找,缓存到内存,然后第二次执行时,只查找了id值,其余的在内存中找到。
@Test
public void cacheTest() { Query query = session.createQuery("From Tb_User");
// List<Tb_User> list = query.getResultList();
// for(Tb_User u : list){
// System.out.println(u.getName());
// } Iterator it = query.iterate();
while(it.hasNext()){
Tb_User u = (Tb_User)it.next();
System.out.println(u.getName());
} // it = query.iterate();
// while(it.hasNext()){
// Tb_User u = (Tb_User)it.next();
// System.out.println(u.getName());
// }
}
二、二级缓存
hibernate的二级缓存又称为“全局缓存”,“应用级缓存”,二级缓存中的数据可适用方位是当前应用的所有会话,不随session关闭而关闭,他是可插拔式的缓存。二级缓存需要其他的jar包,自己去配置。配置步骤:
①.添加二级缓存对应的jar包
jar包在 \hibernate-release-5.2.1.Final\lib\optional\ehcache 中有三个ehcache-2.10.1.jar,hibernate-ehcache-5.2.1.Final.jar,slf4j-api-1.7.7.jar都需要添加进去
②.在hibernate的配置文件中添加Provider类的描述,即hibernate.cfg.xml中 添加属性
<!-- 开启二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>
<!-- 配置RegionFactory为Ehcache的RegionFactory -->
<property name="cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>
③.添加二级缓存的属性配置文件
在 \hibernate-release-5.2.1.Final\project\hibernate-ehcache\src\test\resources 目录下,可以找到ehcache.xml的配置文件,复制粘贴到hibernate.cfg.xml统一目录下,打开xml文件看到这么一段,注释写得很清楚,每个属性干嘛的。这个配置是默认的缓存策略。
<!--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 beforeQuery 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 beforeQuery 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"
/>
④.在需要被缓存的表所对应的映射文件中添加<cache />标签,作为class的子节点。usage属性表示的是事务模式,还有include属性,设置是否加载延迟加载的属性,region属性是Ehcache配置中,可以为表单独增加缓存策略,否则全部都是默认策略。
<cache usage="read-only" region="Tb_User"/>
若需要单独配置缓存策略,需要在ehcache.xml中加上一段,表示Tb_User使用当前的缓存策略,不用默认的。(不是必须配置的)
<cache name="Tb_User" maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" />
此时基本的配置就完成了,依然用第一个例子做测试
/**
* 一级缓存
*/
@Test
public void cacheTest() {
Tb_User u = session.get(Tb_User.class, "1");
System.out.println(u.getName());
//session = sessionFactory.openSession();
u = session.get(Tb_User.class, "1");
System.out.println(u.getName());
}
此时,无论是否打开一个新的session,都只会打印一条sql语句,若把cache.use_second_level_cache 属性值设为false,那么就可以关闭二级缓存。
三、一级缓存和二级缓存比较
补充:在映射文件中的cache标签的usage有四种属性
read-only: 对于永远不会被修改的数据可以采用这种并发访问策略,它的并发性能是最高的。但必须保证数据不会被修改,否则就会出错,使用场景可以是OA系统中比较常用的字典表/枚举表
nonstrict-read-write: 非严格读写不能保证缓存与数据库中数据的一致性,如果存在两个事务并发地访问缓存数据的可能,则应该为该数据配置一个很短的过期时间,以减少读脏数据的可能。对于极少被修改,并且可以容忍偶尔脏读的数据可以采用这种并发策略。
read-write: 对于经常被读但很少修改的数据可以采用这种策略,它可以防止读脏数据。
transactional:它可以防止脏读和不可重复读这类的并发问题。
transactional策略是事务隔离级别最高,read-only的隔离级别最低。事务隔离级别越高,并发性能就越低。
Hibernate学习笔记--------3.缓存的更多相关文章
- Hibernate学习笔记(二)
2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...
- Hibernate学习笔记(一)
2016/4/18 19:58:58 Hibernate学习笔记(一) 1.Hibernate框架的概述: 就是一个持久层的ORM框架. ORM:对象关系映射.将Java中实体对象与关系型数据库中表建 ...
- Hibernate 学习笔记一
Hibernate 学习笔记一 今天学习了hibernate的一点入门知识,主要是配置domain对象和表的关系映射,hibernate的一些常用的配置,以及对应的一个向数据库插入数据的小例子.期间碰 ...
- Hibernate学习笔记-Hibernate HQL查询
Session是持久层操作的基础,相当于JDBC中的Connection,通过Session会话来保存.更新.查找数据.session是Hibernate运作的中心,对象的生命周期.事务的管理.数据库 ...
- Hibernate学习笔记(二)—— 实体规则&对象的状态&一级缓存
一.持久化类 1.1 什么是持久化类? Hibernate是持久层的ORM映射框架,专注于数据的持久化工作.所谓的持久化,就是将内存中的数据永久存储到关系型数据库中.那么知道了什么是持久化,什么又是持 ...
- HIbernate学习笔记(八) hibernate缓存机制
hibernate缓存 一. Session级缓存(一级缓存) 一级缓存很短和session的生命周期一致,因此也叫session级缓存或事务级缓存 hibernate一级缓存 那些方法支持一级缓存: ...
- Hibernate学习笔记二:Hibernate缓存策略详解
一:为什么使用Hibernate缓存: Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序访问物理数据库的频次,从而提高应用程序的性能. 缓存内的数据是对物理数据源的复制,应用 ...
- Hibernate学习笔记(六) — Hibernate的二级缓存
我们知道hibernate的一级缓存是将数据缓存到了session中从而降低与数据库的交互.那么二级缓存呢? 一.应用场合 比方.在12306购票时.须要选择出发地与目的地,假设每点一次都与数据库交互 ...
- Hibernate学习笔记
一.Hibernate基础 1.Hibernate简介 Hibernate是一种对象关系映射(ORM)框架,是实现持久化存储的一种解决方案.Java包括Java类到数据库表的映射和数据查询及获取的方法 ...
随机推荐
- HDU 2602 Find a way BFS搜索
题意:找到总时间最少的KFC 分析:两遍BFS 找KFC比较一下 注:有些地方的KFC可能到达不了,wa了一次 #include <iostream> #include <cstdi ...
- HDU 5607 graph 矩阵快速幂 + 快速幂
这道题得到了学长的助攻,其实就是一个马尔科夫链,算出一步转移矩阵进行矩阵快速幂就行了,无奈手残 这是我第一回写矩阵快速幂,写的各种毛病,等到调完了已经8点44了,交了一发,返回PE,(发现是少了换行) ...
- 企业移动互联网O2O微信支付流程图
过去一周里最受关注的应该就是微信了,腾讯合作伙伴大会微信分论坛的火爆现场,没有亲临其境是无法想象的,近3000人报名,2000多人来到现场,试图进入只能容纳300人的会场…… 闲话不表,进入正题吧,本 ...
- dataStructure@ Check whether a given graph is Bipartite or not
Check whether a given graph is Bipartite or not A Bipartite Graph is a graph whose vertices can be d ...
- dataStructure@ Check if a directed graph has cycles
#include<iostream> #include<cstdio> #include<cstring> #include<limits> #incl ...
- Redis的探究
之前大四时候实习的公司有使用过Redis,不过那时所有配置均由主管完成了,而我也只是处于能使用的阶段. 时隔1年多,近期回想起这货,在研究中,想把它整合进现在公司的网站系统中,做做数据快照(已完成)和 ...
- 跟着Android官网学习Activity
1.Activity介绍 An Activity is an application component that provides a screen with which users can int ...
- C/S 和 B/S 模式的区别与联系
如果要比较两种事物之间的相同点和不同点,首先,我们要分别对这两种事物有一个最基本的了解. 一.C/S与B/S的定义 C/S (Client/Server)结构,即大家熟知的客户机和服务器结构.它是软件 ...
- php做EXCEL数据导出导入开发的一些小问题
前两天刚刚做开发CRM系统项目,在做要做EXCEL导出导入功能,因为以前做.NET开发用的是NPOI,但可是没找到PHP版本的,所以就网搜找了个国外的开源PHPEXCEL , 一开始只是做了简单的导入 ...
- java实现生产者消费者问题
引言 生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一个存储空间,如下图所示,生产者向空间里存放数据,而消费者取用数据,如果不加以协调可能会出现以下情况: 生产者消费者图 ...