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 对象的生命周期与本地线程绑定
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- 【Linux常用工具】03. Linux性能测试工具ab
在Apache服务器的套件中,有一个叫做 ab (ApacheBench) 的工具. ApacheBench 主要是用来测试Apache服务器执行效率用的 ApacheBench 可以针对某个特定的 ...
- Lua for windows中SciTe开启支持python的方法
打开Options-Open Global Options #import python的#去掉即可
- 自定义View(6)paint设置图图层重叠时的显示方式,包含清空canvas
Paint.setXfermode 这个函数设置两个图层相交时的模式 在已有的图层上绘图将会在其上面添加一层新的图层. 如果新的图层是完全不透明的,那么它将完全遮挡住下面的图层,而setXfermod ...
- git版本库底层命令
当我们在使用git的时候,有时候需要知道当前文件夹相对于工作目录根目录的相对路径等等,那么我们可以使用 git rev-parse 添加一个参数就可以实现,如: 显示当前仓库版本库 .git 目录所在 ...
- 进程控制的一些api
转自:http://blog.chinaunix.net/uid-26833883-id-3222794.html 1.fork() ,vfork() 创建进程 2‘ exec()类 在进程中执行其他 ...
- AngularJS promise()
实例说明一 <!DOCTYPE html> <html ng-app="my-app"> <head> <meta charset=&qu ...
- 【Java学习笔记】Hello world
package aaa; public class aaa { public static void main(String args[]){ System.out.println("hel ...
- 在linux下实现用ffmpeg把YUV420帧保存成图片
在网上搜了很久相关的问题,但是好像没有一个在linux下跑得比较完整的例子,不过经过自己一番搜索和总结,终于做出来了,哈哈,看下面的代码吧. 这个例子可以保存成bmp或者jpeg格式的图片. 下面的结 ...
- Uva 10881 Piotr’s Ants 蚂蚁
一根长度为 L 厘米的木棍上有 n 只蚂蚁,每只蚂蚁要么朝左爬,要么朝右爬,速度为 1 厘米/秒.当两只蚂蚁相撞时,二者同时调头(掉头用的时间忽略不计).给出每只蚂蚁的初始位置和朝向,计算 T 秒之后 ...
- Android 的实现TextView中文字链接的4种方法
Android 的实现TextView中文字链接的方式有很多种. 总结起来大概有4种: 1.当文字中出现URL.E-mail.电话号码等的时候,可以将TextView的android:autoLink ...