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 对象的生命周期与本地线程绑定
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
随机推荐
- devDependencies和dependencies的区别
我们在使用npm install 安装模块或插件的时候,有两种命令把他们写入到 package.json 文件里面去,比如: --save-dev --save 在 package.json 文件里面 ...
- freemarker中判断对象是否为空
<#if xxx?exists> 或则 <#if xxx??>两个问号??最简单方便
- 函数ut_2_log
计算某个数的对数(最大的) 例如 16 计算后为 4 2的4次方为16 例如15 计算后为3 2的3次方为8 /******************************************** ...
- codeforces 333A - Secrets
题意:保证不能正好配齐n,要求输出可以用的最大硬币数. 注意如果用到某种硬币,那么这种硬币就有无穷多个.所以11=3+3+3+3,12=9+9,13=3+3+3+3+3 #include<cst ...
- LeetCode Factorial Trailing Zeroes (阶乘后缀零)
题意:如标题 思路:其他文章已经写过,参考其他. class Solution { public: int trailingZeroes(int n) { <? n/: n/+trailingZ ...
- exec、eval
#!/usr/bin/env python3 # -*- coding: utf-8 -*- #info #warning def log(message): print('------------- ...
- unsigned 和 signed
http://www.cnblogs.com/stonehat/archive/2011/10/14/2212141.html http://m.blog.csdn.net/blog/u0100862 ...
- vc2005编译ffmpeg以及ffplay
ffmpeg编译过程:1 http://ffmpeg.zeranoe.com/builds/下载官方提供的源码,win32库和dll.2 新建vc2005 console空工程,把ffmpeg.h,f ...
- uestc 1721 吴神,人类的希望
// 将n个相同的球放进m个盒子 盒子不为空的方法总数// dp[i][j] 表示i个盒子 j个球的方法总数// 递推关系 dp[i][j]=dp[i-1][j-1]+d[i][j-i]// a. i ...
- 【转】pdf 中如何把几页缩小成一页打印
我用的是Foxit PDF Reader,可以这样设置:文件-打印-打印处理下的页面排列选择“在每张纸上放置多页”-选择每页版数即可. 如果你用的是Adobe Reader,也可以自己找一下,看是否有 ...