Hibernate之Session缓存以及操作Session缓存的相关方法
1、Session概述
A、Session 接口是 Hibernate 向应用程序提供的操纵数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载 Java 对象的方法.
B、 Session 具有一个缓存, 位于缓存中的对象称为持久化对象, 它和数据库中的相关记录对应. Session 能够在某些时间点, 按照缓存中对象的变化来执行相关的 SQL 语句, 来同步更新数据库, 这一过程被称为刷新缓存(flush).
C、站在持久化的角度, Hibernate 把对象分为 4 种状态: 持久化状态, 临时状态, 游离状态, 删除状态. Session 的特定方法能使对象从一个状态转换到另一个状态.
2、操作 Session 缓存
上述的图表描述了Session缓存相关方法的作用和意义,即:
flush():按照缓存中对象的属性的变化来同步更新数据库
reflesh():根据数据库中的记录信息来更新缓存对象中的信息
clear() : 清除缓存中的持久化对象信息
3、Session对象相关方法:
下面通过代码我们来分别对Session的各个方法进行测试说明,其它相关配置文件在这里不做特殊说明,有问题可直接看HelloWorld中的相关配置。
首先,新建一个单元测试类如下所示:
package com.elgin.hibernate.test; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import com.elgin.hibernate.entity.News; public class HibernateTest { //如此声明只为方便测试,正式环境不能这么用
private SessionFactory sessionFactory;
private Session session;
private Transaction transcation; @Before
public void init(){
Configuration cfg=new Configuration().configure();
ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
sessionFactory=cfg.buildSessionFactory(serviceRegistry);
session=sessionFactory.openSession();
transcation=session.beginTransaction();
} @After
public void destory(){
transcation.commit();
session.close();
sessionFactory.close();
}
}
一、首先来测试Session缓存,在上述代码基础上增加如下测试方法:
@Test
public void testSessionCache(){
News news=(News) session.get(News.class, 1);
System.out.println(news.toString());
News news2=(News) session.get(News.class, 1);
System.out.println(news2.toString());
System.out.println(news==news2);
}
运行之后,会在控制台打印出如下信息:
Hibernate:
select
news0_.ID as ID1_0_0_,
news0_.TITLE as TITLE2_0_0_,
news0_.AUTHOR as AUTHOR3_0_0_,
news0_.DATE as DATE4_0_0_
from
NEWS news0_
where
news0_.ID=?
News [id=1, title=少年闰土, author=Oracel, date=2015-07-28 00:00:00.0]
News [id=1, title=少年闰土, author=Oracel, date=2015-07-28 00:00:00.0]
true
对于同一个id对应的对象,如果在Session缓存中存在,那么就不会再去从数据库查询,而是直接从Session缓存中读取
二、Session接口的flush() 方法测试:
/**
* flush()方法使数据表中的记录和session缓存中对象状态保持一致,为了保持一致,则可能向数据库发送对应的sql语句
* 1.调用commit()方法中,是先调用flush()方法,再提交事务
* 2.fulsh()方法可能会发送sql语句,但不会提交事务
* 注意:在未提交事务或者显式的调用session.flush()方法之前,也有可能执行flush()方法
* 1、执行HQL、QBC查询的,会先进行flush()操作,以得到数据库中最新的数据
* 2、若记录的id是使用数据库自增的方式生成,则在调用save()方法之后,会立即发送insert语句来保证对象的id是存在的
*/
@Test
public void testSessionFlush(){
News news=(News) session.get(News.class, 1);
news.setAuthor("李白");
}
执行之后,你会发现数据库中对应的author变成了李白,并没有使用update方法来更新数据库,为什么数据库内的内容会发生变化?
其实,这就是Session的flush()方法在起作用了,也许你还会问,这里也并没有调用flush()方法呢,因为在调用commit()方法来提交事务的时候,在commit()方法的实现中调用了flush()方法,可以在commit()方法处打断点,然后debug,你会发现,在执行commit()方法之前,数据库的内容并没有发生变化,除了get方法发出的sql查询语句,并没有发出sql语句。控制台内容如下:
Hibernate:
select
news0_.ID as ID1_0_0_,
news0_.TITLE as TITLE2_0_0_,
news0_.AUTHOR as AUTHOR3_0_0_,
news0_.DATE as DATE4_0_0_
from
NEWS news0_
where
news0_.ID=?
Hibernate:
update
NEWS
set
TITLE=?,
AUTHOR=?,
DATE=?
where
ID=?
三、Session的refresh()方法测试:
/**
* refresh()方法会强制发送select语句,以使缓存中对象的信息跟数据表中信息一致
*
*/
@Test
public void testRefresh(){
News news=(News) session.get(News.class, 1);
System.out.println(news);
//debug执行到这一步之前,改变表中数据测试
session.refresh(news);
System.out.println(news);
}
测试refresh方法,使用debug运行Junit,断点打在refresh方法那一行,在执行refresh() 方法之前,打印语句之后,任意改变数据库中词条记录中的内容,然后执行剩余方法。由于知道了refresh方法的作用,预期news中的内容会变成数据库中我们修改后最新的信息,如果你使用的数据库是MySQL,那么你会发现,2次打印出的内容是一致的,第二次打印出的内容并不包含我们修改后的信息,这是为什么呢?
其实这个数据库事务的隔离级别有关系,MySQL默认的隔离级别是:REPEATABLE READ,也就是可重复度。具体作用是确保事务可以多次从一个字段中读取相同的值,在这个事务持续期间,禁止其它事务对这个字段进行更新,可以避免脏读和不可重复读,但幻读依旧存在。
在Hibernate中,我们可以在Hibernate的配置文件中设置事务的隔离级别,
每一个隔离级别都对应一个整数:
1. READUNCOMMITED
2. READ COMMITED
4. REPEATABLEREAD
8. SERIALIZEABLE
Hibernate 通过为 Hibernate 映射文件指定hibernate.connection.isolation 属性来设置事务的隔离级别
在Hibernate的配置问价中增加如下配置语句:
<!--设置hibernate事务的隔离级别 -->
<property name="connection.isolation">2</property>
之后重新按照刚才的方法运行,会发现2次打印出来的news对象不同,这正是refresh() 方法的作用:refresh()方法会强制发送select语句,以使缓存中对象的信息跟数据表中信息一致。
四、Session的clear() 方法测试
@Test
public void testClear(){
News news=(News) session.get(News.class, 1);
session.clear();
News news2=(News) session.get(News.class, 1);
}
执行上述测试代码发现,Hibernate分别发送了2条sql语句来进行查询,之前我们说,对于同一个id对应的对象,如果在Session缓存中存在,那么就不会再去从数据库查询,而是直接从Session缓存中读取,而在此却是查询了2次数据库,这说明在执行clear() 方法时,将Session缓存清空了。
Hibernate之Session缓存以及操作Session缓存的相关方法的更多相关文章
- 六十一:Flask.Session之flask操作session
1.设置session:使用flask.session就可以操作字典,操作方式和操作字典一样:session['key']=value2.获取session,和获取字典的值一样:session['ke ...
- hibernate学习系列-----(3)Session 缓存和持久化生命周期以及Session 基本操作
Session缓存原理 为了能够在控制台更好的看到我们的hibernate干了些什么,可以在hibernate.cfg.xml文件中写入如下配置: <!-- print all generate ...
- hibernate笔记--缓存机制之 一级缓存(session缓存)
一级缓存: 又称为session缓存,它和session生命周期相同,周期非常短.是事务级别的缓存: 还是以Book和Category这两个表为例,我们用代码观察一个缓存的存在: 假设现在我要去查询i ...
- Redis-基本概念、java操作redis、springboot整合redis,分布式缓存,分布式session管理等
NoSQL的引言 Redis数据库相关指令 Redis持久化相关机制 SpringBoot操作Redis Redis分布式缓存实现 Resis中主从复制架构和哨兵机制 Redis集群搭建 Redis实 ...
- hibernate的flush()、refresh()、clear()针对一级缓存的操作的区别
首先session是有一级缓存的,目的是为了减少查询数据库的时间,提高效率,一级缓存的生命周期和session是一样的, session.flush()和session.clear()就针对sessi ...
- 2522-Shiro系列--使用缓存对认证session和授权Cache进行存储
如何进行session的缓存? 原理: Shiro有1个类,AuthorizingRealm AuthenticatingRealm,里面有个获取认证信息的方法, AuthenticatingReal ...
- 缓存Cookie、session、localStorage的区别
cookie Cookie就是服务器暂存放在你计算机上的一笔资料,好让服务器用来辨认你的计算机.当你在浏览网站的时候,Web服务器会先送一小小资料放在你的计算机上,Cookie 会帮你在网站上所打的文 ...
- 学习笔记16_页面缓存/进程外Session
*页面缓存:适用于访问量较高的网站 <%@OutputCache Duration="15"//缓存15秒 VaryByParam='*' //请求的任何一处发生改变,缓存 ...
- [原创]java WEB学习笔记94:Hibernate学习之路---session 的管理,Session 对象的生命周期与本地线程绑定
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- dex
数字交叉连接设备(Dendenkosha Electronic Exchange),就是常说的电子交换器. 数字交叉连接设备完成的主要是STM-N信号的交叉连接功能,它是一个多端口器件,它实际上相 ...
- sdut 2351 In Danger (找规律)
题目:http://acm.sdut.edu.cn/sdutoj/problem.php?action=showproblem&problemid=2351 题意:xyez, xy表示一个十进 ...
- bzoj1566
好题,这道题体现了换一个角度计数的思想 a1^2+a2^2+……ak^2=(变成第1种输出序列的操作序列数目)^2+(变成第2种输出序列的操作序列数目)^2…… 脑洞大一点,这就相当于两个操作序列变成 ...
- uvalive 4255 Guess(拓扑排序)
算好题目,反正我没想到可以用图论做(虽然现在做的是图论专题= =) 首先是要把求每个位置上的值转化为求 “前缀和之差”,这是一个很有用的技巧 其次,由输入的(n+(n-1)+...+2+1)个符号,可 ...
- codeforces 334A - Candy Bags
忘了是偶数了,在纸上画奇数画了半天... #include<cstdio> #include<cstring> #include<cstdlib> #include ...
- qt创建android项目后需要加入的参数
默认用qtcreator5.2.0创建了一个quick项目,却报如下错误: error:cstdlib.h no such file or directory 解决方法: 打开项目文件untitled ...
- Java [Leetcode 228]Summary Ranges
题目描述: Given a sorted integer array without duplicates, return the summary of its ranges. For example ...
- wifi详解(三)
1 WLAN驱动结构介绍 1.1 SDIO驱动 在drivers/mmc下面是mmc卡,SD卡和SDIO卡驱动部分,其中包括host驱动,card驱动和core部分,由于网络接 ...
- POJ 1042 Gone Fishing
题意:一个人要在n个湖中钓鱼,湖之间的路径是单向的,只能走1->2->3->...->n这一条线路,告诉你每个湖中一开始能钓到鱼的初始值,和每钓5分钟就减少的数量,以及湖之间的 ...
- java web 学习十(HttpServletRequest对象1)
一.HttpServletRequest介绍 HttpServletRequest对象代表客户端的请求,当客户端通过HTTP协议访问服务器时,HTTP请求头中的所有信息都封装在这个对象中,通过这个对象 ...