Hibernate一级缓存Session和对象的状态
建议看原文:https://blog.csdn.net/qq_42402854/article/details/81461496
一、session简介
首先,SessionFactory 是线程安全的,SessionFactory 用到了工厂模式。
session接口:
Session 接口负责执行被持久化对象的CRUD操作。 Session 接口是一个非线程安全的,避免多个线程共享一个Session实例。
Session 被称为持久化管理器。Session对象是Hibernate技术的核心,持久化化对象的生命周期、事务的管理和持久化对象的查询、更新和删除都是通过Session对象来完成的。
Session 是一个轻量级对象。通常将每一个Session实例和一个数据库事务绑定。每执行一个数据库事务,不论执行成功与否,最后都因该调用Session的 Close() 方法,关闭Session释放占用的资源。
session作用:
1)减少访问数据库的频率
2)保证缓存中的对象与数据库中的相关记录数据保持同步
session清理缓存的时机
清空缓存
当调用 session.evict(customer); 或者session.clear(); 或者session.close()方法时,Session的缓存被清空。
清理缓存
Session具有一个缓存,又叫 Hibernate 的一级缓存,位于缓存中的对象处于持久化状态,它和数据库中的相关记录对应,Session能够在某些时间点,按照缓存中持久化对象的属性变化来同步更新数据库,这一过程被称为清理缓存。
在默认情况下,Session会在下面的时间点清理缓存。
当应用程序调用org.hibernate.Transaction的commit()方法的时候,commit()方法先清理缓存,然后在向数据库提交事务;
当应用程序调用Session的list()或者iterate()时(【注】get()和load()方法不行),如果缓存中持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能能反映持久化对象的最新状态;
当应用程序显式调用Session的flush()方法的时候
在Session清理缓存的时候,会自动进行脏检查,如果发现Session缓存中的对象和数据库记录不一致,就会根据对象的最新属性去同步更新数据库。
Hibernate5 清理缓存的模式不止三种
Junit测试类:
SessionFactory sessionFactory = null;
Session session = null;
Transaction transaction = null;
@Before
public void init() {
// 1. 创建一个 SessionFactory 工厂类: 通过它建立一个与数据库连接回话 session
// 配置类: 封装有我们的配置文件里的配置信息, 返回的 configuration 包含有配置文件里的具体信息
Configuration configuration = new Configuration().configure();
// Hibernate5规定: 所有配置或服务要生效, 必须将其注册到一个服务注册类中
StandardServiceRegistry serviceRegistry = configuration.getStandardServiceRegistryBuilder().build();
sessionFactory = new MetadataSources(serviceRegistry).buildMetadata().buildSessionFactory();
// 2. 通过工厂类开启 Session 对象
session = sessionFactory.openSession();
// 3. 开启事务
transaction = session.beginTransaction();
}
@After
public void destory() {
// 5. 提交事务
transaction.commit();
// 6. 关闭 Session
session.close();
// 7. 关闭工厂类
sessionFactory.close();
}
1. get方法 load方法
@Test
public void testGet() {
//get方法/load方法: 通过id,获取数据中对应记录数据,返回对象,放到 session 的缓存中
Student student = session.get(Student.class, 1); //发起sql查询语句
student = null;
Student student2 = session.get(Student.class, 1); //没有发起sql, 而是从缓存中获取数据
System.out.println(student);
System.out.println(student2);
}
结论: session作用一证实
get() 方法与 load() 方法区别
1. get 是立即索引, load 是延迟索引
执行 get() 方法:会立即加载对象
执行 load() 方法: 若不使用该对象,则不会立即执行查询操作,而是生成一个代理对象,
2. load() 方法可能会抛出 LazyInitializationException异常:在需要初始化代理对象之前已经关闭了session.
3. 若数据表中没有对应id 记录, session 也没有关闭
get方法 返回 null
load 方法:若不使用该对象的任何属性,没问题;若需要初始化,则抛出ObjectNotFoundException异常
2. flush方法与reflush方法
@Test
public void testFlush() {
Student student = session.get(Student.class, 1); //发起sql查询语句
student.setName("张三"); // 该student对象处理后,放进session缓存中
// 此时,session缓存中的student对象数据,和数据库中的数据不一致。
//session.flush();//判断,一致:不会发起sql, 不一致: 发起一条update语句,但是不会提交事务, 可省略不写
//transaction.commit(); // 真正提交事务之前(且只会)针对于持久对象,自动调用一次flush方法判断。
}
@Test
public void testReflush() {
Student student = session.get(Student.class, 1); //发起sql查询语句
student.setName("李四"); //修改缓存中的数据
System.out.println(student);
// 此时,session缓存中的student对象数据,和数据库中的数据不一致。
session.refresh(student);//不判断是否一致:都会发起sql,在判断缓存中的对象数据和数据库中非数据,一致: 不动作, 不一致,一条update语句,修改缓存中的数据与数据库数据一致,数据库记录没变化
System.out.println(student);
}
结论: session作用二证实
flush() 方法与 reflush() 方法区别:
flush() 方法: 强制让session缓存中的数据与数据库中的记录数据保持一致,
若不一致,则发起update语句修改数据库数据让其一致。
a. flush() 可能会发送sql语句,但不会提交事务
b. 在事务commit()提交之前先自动调用session的flush()方法,然后提交事务。
reflush() 方法:强制发送一条select语句,保证让数据库中的记录数据与session缓存中的数据保持一致,
若不一致,会修改session缓存中的数据让其一致
3. clear() 方法 : 清空session缓存中的数据
@Test
public void testClear() {
Student student = session.get(Student.class, 1); //发起sql查询语句
System.out.println(student);
session.clear(); //清空session中的数据
//缓存中中不到id=1的student对象数据,重新发起sqlsql查询语句
Student student2 = session.get(Student.class, 1);
System.out.println(student2);
}
二、对象的主要三种状态:
1. 临时 / 瞬态状态(transient):OID 通常为 null
没有session与其关联,数据库中也没有数据与之对应,一般是new出来的对象.超过作用域会被 JVM 垃圾回收器回收.
@Test
public void test1() {
//student是Hibernate将要处理的对象,刚new出来,此时对象处于临时(瞬态)状态,即student为临时对象
Student student = new Student("王五","男",new Date());
//把临时对象放到session缓存中,并发起insert语句(在事务提交时才真正插入到数据库),此时临时对象转为持久状态,即student为持久对象:
session.save(student);
/*持久对象特征:
* 1. 该对象被session托管,在session的缓存中要存在该对象
* 2. 该对象的数据要在数据库的记录中有与之对应(对象OID和数据库记录id)的数据记录,这个Hibernate会拿到数据记录对象的id,即OID
*/
transaction.commit();
}
2、持久状态(persistent): OID 不为 null
有相关联的session,并且相关联的session没有关闭,事务没有提交。数据库中也有数据与之对应.持久态对象发生改变,
数据库中相关联的对象也会跟着改变.在事务提交时会影响到数据库,hibernate能够检测得到它的改变。
@Test
public void test1() {
//student为临时对象
Student student = new Student("王五","男",new Date());
session.save(student); //student为持久对象
student.setName("zs");
transaction.commit(); // flush 会判断
}
@Test
public void test() {
//student为持久对象
Student student = session.get(Student.class, 1);
student.setName("zs");
transaction.commit(); //(且只会)针对于持久对象,自动调用一次flush方法判断。
}
@Test
public void test() {
//student为持久对象
Student student = session.load(Student.class, 1);
student.setName("lisi");
session.clear();
transaction.commit(); //不动作, 无update语句。
}
3、游离 / 脱管状态(detached): OID 不为 null ,不在 session 缓存中。
数据库中有数据与之对应,但没有 session 与其关联,脱管态的对象发生改变,hibernate 是检测不到的。
1)save() 方法与 update() 方法
Hibernate规定: 持久状态对象的id值不准修改,临时状态对象的id可以修改,游离状态对象的id可以被修改,但是没任何效果,,Hibernate会按照自己的机制,重构 id.
@Test
public void test() {
//临时对象
Student student = new Student("李四","男",new Date());
//游离对象: student有id,但是这个对象是new出来的,没有被session托管,即没在session缓存里。
student.setId(1); //id=1;数据库中有id=1的记录
//studet从游离状态转为持久状态
//session.save(student); //对游离状态的对象,设置的id无效, Hibernate会按照自己的机制发起insert语句,插入id值.
//studet从游离状态转为持久状态
//update作用: 更新,将处理的对象,先放到session缓存中,然后做更新数据库中对应id的记录值(无对应id报错)
session.update(student);
//student.setId(2); //再次修改id 提交报错, Hibernate规定 持久状态对象的id值不准修改,临时状态对象的id可以修改
transaction.commit();
}
2)delete() 方法作用:把student对象从session缓存中删除,然后删除数据库对应id的记录
@Test
public void test3() {
//临时对象
Student student = new Student("李四","男",new Date());
//游离对象
student.setId(1); //id=1;数据库中有id=1的记录
//studet从游离状态转为临时状态, 同时数据库对应id的记录会被删除,发起delete语句。
session.delete(student);
//delete方法作用:把student对象从session缓存中删除,然后删除数据库对应id的记录
transaction.commit();
}
3)saveOrUpdate() 方法
saveOrUpdate方法作用:save方法和update的综合体,
如果student对象为临时状态: 调用save方法
如果student对象为游离状态: 调用update方法
@Test
public void test4() {
//临时对象
Student student = new Student("admin","男",new Date());
Student student2 = new Student("admin","女",new Date());
//游离对象
student.setId(2); //id=2;数据库中有id=2的记录
session.saveOrUpdate(student); //调用update方法
session.saveOrUpdate(student2); //调用save方法
transaction.commit();
}
4)update() 方法
Hibernate 不允许session缓存中有两个或两个以上相同 ID 值的对象存在。
@Test
public void test5() {
//student持久对象
Student student = session.get(Student.class, 2);
//student2临时对象
Student student2 = new Student();
//student2游离对象
student2.setId(2); //id=2;数据库中有id=2的记录
session.update(student2); //update:将student2对象放进缓存时,报错NonUniqueObjectException
transaction.commit();
}
三、Hibernate 拿到 jdbc 原生的 connection
doWork() 方法: jdbc 操作 存储过程,批量操作。
import org.hibernate.jdbc.Work;
@Test
public void test() {
session.doWork(new Work() {
public void execute(Connection arg0) throws SQLException {
System.out.println(arg0); //com.mysql.jdbc.JDBC4Connection@30b34287
}
});
}
Hibernate一级缓存Session和对象的状态的更多相关文章
- hibernate一级缓存及对象的状态
hibernate中实体类对象的状态 在hibernate中实体类对象有三种状态 (1)瞬时态(临时态) 瞬时态:即我们自己创建一个对象,还没有保存到数据库就叫临时态,其实也可以说是对像没有id值,跟 ...
- Hibernate一级缓存和三种状态
Hibernate一级缓存又称session缓存,生命周期很短,跟session生命周期相同. 三种状态:1.transient(瞬时态):刚new出来的对象,既不在数据库中,也不在session管理 ...
- hibernate - 一级缓存和三种状态解析
转载自:http://www.cnblogs.com/whgk/p/6103038.html 一.一级缓存和快照 什么是一级缓存呢? 很简单,每次hibernate跟数据库打交道时,都是通过sessi ...
- Hibernate一级缓存(补)
------------------siwuxie095 什么是缓存 缓存是介于应用程序和永久性数据存储源(如:硬盘上的 ...
- hibernate一级缓存
理解 Hibernate 一级缓存 Hibernate 一级缓存默认是打开,不需要任何的配置.实际上,你无法强制禁止它的使用. 如果你理解了一级缓存实际上和会话是关联的,就很容易理解一级缓存.总所周知 ...
- Hibernate一级缓存(基于查询分析)
首先我们应该弄清什么是hibernate缓存:hibernate缓存是指为了降低应用程序对物理数据源的访问频次,从而提高应用程序的运行性能的一种策略.我们要将这个跟计算机内存或者cpu的缓存区分开. ...
- Hibernate一级缓存和二级缓存详解
(1)一级缓存 是Session级别的缓存,一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中,如果短时间内这个session(一定要同一个session)又做了同一个操作,那么h ...
- hibernate一级缓存和快照
摘自网络: Hibernate中的一级缓存的底层是以Map形式存在的,key是主键,value是对象,所以它的泛型为Map<Serializable,Object>,key的泛型为串行化是 ...
- Hibernate一级缓存测试分析
Hibernate 一级缓存测试分析 Hibernate的一级缓存就是指Session缓存,此Session非http的session会话技术,可以理解为JDBC的Connection,连接会话,Se ...
随机推荐
- POJ-3258 (最小值最大化问题)
POJ - 3258 River Hopscotch Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & ...
- Android尺寸单位
px:pixels(像素),1px的长度对应屏幕一个像素点的大小. dp/dip:(density-independent pixels,设备无关像素) sp:scaled pixels(可缩放像素) ...
- 装WIN7的一点心得
一.为什么要装WIN7 长久以来个人的习惯,WIN10用不来,总体安装思路是:下官方版,找方法激活 二.安装镜像的来源 这个网上版本五花八门,各种系统网站,但都会有软件捆绑等行为,还有浏览器中强制捆了 ...
- 安装postgresql后找不到服务 postgresql service
问题再现 环境: postgresql: 11.5 windows 10 企业版LTSC 64位 使用postgresql-11.5-1-windows-x64.exe安装后,让重新启动,但是重启后, ...
- 监控系统负载与CPU、内存、硬盘、登录用户数,超出警戒值则发邮件告警。
zzx@zzx:~$ cat warning.sh #!/bin/bash #监控系统负载与CPU.内存.硬盘.登录用户数,超出警戒值则发邮件告警. 前提安装mail服务nh=`uname -r ...
- C++逐行读取txt
C++读取txt文件的时候可以使用std::ifstream来实现,如果打开文件失败的话,其变量会是空的,所以可以用来判断是否打开成功. #include <stdlib.h> #in ...
- GFlags 处理内存越界、野指针问题研究
从官方文档可以看到,从gflags的GUI上,我们是无法判断他打开的是full page heap verification 还是Standard page heap verification, 所以 ...
- JVM探秘:jstat查看JVM统计信息
本系列笔记主要基于<深入理解Java虚拟机:JVM高级特性与最佳实践 第2版>,是这本书的读书笔记. jstat命令用来查看JVM统计信息,可以查看类加载信息.垃圾收集的信息.JIT编译信 ...
- PHP 框架: CodeIgniter 分页教程
PHP 框架: CodeIgniter 分页教程 分类: PHP2009-04-23 11:09 3209人阅读 评论(0) 收藏 举报 框架phpbooksdatabaseurl数据库 目录(?)[ ...
- [极客大挑战 2019]Secret File
0x00知识点 没有过滤file 使用php的file伪协议去读取文件 ?file=php://filter/convert.base64-encode/resource=flag.php 0x01解 ...