11. Hibernate 持久化对象的各种状态

news2024/9/20 18:48:44

1. 前言

本节课和大家聊聊持久化对象的 3 种状态。通过本节课程,你将了解到:

  • 持久化对象的 3 种状态;
  • 什么是对象持久化能力。

2. 持久化对象的状态

程序运行期间的数据都是存储在内存中。内存具有临时性。程序结束、计算机挂机…… 内存中的数据将不复存在。

重要的数据,需要使用持久化技术将数据保存到永久性设备上。Hibernate 能够通过 PO(持久化对象) 将数据持久化到数据库。

Hibernate 对 PO 进行操作期间,PO 本身会发生一系列的状态变化。

2.1 瞬时状态(Transient)

分析一段保存数据的实例:

使用 Hibernate 保存数据之前,须先在程序中创建一个名为 stu 的 PO

Student stu=new Student("PO对象的瞬时状态", "男");  

此 PO 在程序运行的内存中存在,数据库中没有。PO 此时处于瞬时状态 (Transient)

瞬时状态下的 PO 特征如下:

  • 程序中有、数据库中没有此对象的相关信息;
  • 对象的标识性属性(对应表中主键的那个属性) 为空;
  • 如果不使用 Session 对象的相关方法进行数据库请求操作,程序退出时瞬时状态的对象信息会丢失。

2.2 持久化状态( Persistent )

创建 PO 后,使用 Session 的相关方法,如 save() 方法向数据库提交保存请求:

Student stu=new Student("PO对象的瞬时状态", "男");
session.save(stu);  

此时 PO 在程序中有,数据库中也有,状态便由瞬时状态转变成为持久化状态(Persistent)

持久化状态下的 PO 有如下几个特征:

  • 程序、数据库中都有 PO 的信息;
  • 对象的标识属性的值为数据库中对应记录的主键值;
  • 持久化状态最大的特点是 PO 处于 Session 生命周期之内。此状态下的 PO 具有持久化能力。

2.3 游离状态(Detached)

PO 的持久化状态一直维持到 Session 对象关闭。如果 Session 对象关闭了,此 PO 的状态将由持久化状态转变成游离状态 (Detached)

游离状态时 PO 的特点:

  • 程序、数据库都有 PO 的信息;
  • 但是,此状态下的 PO 不具有持久化能力。

PO 不会一直停留在某一个状态上,PO 随时可以在 3 种状态之间进行切换。

从上图可看出,PO 的 3 种状态之间的相互演变都是通过调用 Session 对象的相关方法实现的。

由此看来,Session 对象被称为持久化容器是有道理的。

由上图可知,处于瞬时状态游离状态的对象才有可能被 JVM 垃圾回收器回收

3. 对象持久化能力

知道了 PO 的 3 种状态。自然会问:不同状态下的对象对实际操作有什么实际指导意义?

3 种状态中,持久化状态的意义最大,如果 PO 处于持久化状态,此时 PO 就具有持久化能力。

所谓对象持久化能力,通俗理解:

程序中的数据发生变化,会自动同步到数据库中。

演示一段数据更新实例,更新之前先查询数据:

try {
    transaction = session.beginTransaction();
    //查询学生
    Student stu=(Student)session.load(Student.class, new Integer(2));
    //修改学生信息
    
    //执行更新操作
    
    transaction.commit();
} catch (Exception e) {
    transaction.rollback();
} finally {
    session.close();
}  

通过 Session 的 get() 方法查询出来的 stu 对象,此时就处于持久化状态。

在” 修改学生信息 “的注释下添加一行代码:

stu.setStuName("持久化状态就是这么牛"); 

不需要调用 Session 中的任何其它方法,执行代码,程序中修改的数据立即同步到数据库中。

这就是持久化状态的特点:通过 PO 自动同步程序与数据库中的数据

所谓对象持久化能力本质上还是 Session 给的。
Session 记录对象是否处于持久化状态,并充当后台靠山。处于持久状态的对象与数据库之间的数据同步,只是不需要 Session 显示调用。

除了 get()、load()方法。save()、update()、saveOrUpdate()、persis()、megre() 方法都可称为持久化方法。

调用这些方法后,能让对象进入持久化状态,Session 记录并且默默维持 PO 中数据与数据库中数据的同步。

3.1 save() 和 persist() 方法

saveOrUpdate() 方法很好理解,是 save() 和 update() 方法的综合简化版,内在本质没改变。

save() 和 persist() 方法有细节上的区别。
save() 方法原型:

public Serializable save(Object object);

上一段 save () 方法的测试实例:

try {
    Student  stu = new Student("save()方法", "男");
    Serializable  stuId = session.save(stu);
    System.out.println("----------输出学生编号Id---------");
    System.out.println(stu.getStuId());
    System.out.println(stuId);
    System.out.println("----------事务在后面-------"); 
    transaction = session.beginTransaction();
    transaction.commit();
} catch (Exception e) {
    transaction.rollback();  
} finally {
    session.close();
}  

输出结果:

Hibernate: 
    insert 
    into
        Student
        (stuName, stuPassword, stuPic, stuSex) 
    values
        (?, ?, ?, ?)
----------输出学生编号Id---------
40
40
----------事务在后面------- 

结果即结论:

Save() 方法可以在事务之外执行;
有一个关键点需要引起重视:

无论是在事务之内还是事务之外,save() 方法都会向数据库发送了一条 Sql 语句请求,控制台输出结果是一样的。

但是:

  • 如果程序中 Hibernate 不显示发送事务提交指令,数据会回滚(丢失);
  • 只有当数据库系统接收到程序中发送过来的事务提交指令后,才会真正意义上保存。

很好理解,因为事务是交给 Hibernate 管理的,数据库接收到插入指令后,在没有明确事务提交指令之前,只会把数据缓存在内存中。
也就是说,虽然 save() 方法看起来不依赖事务就可插入数据,但,没有事务组件的指令,最后也是虚行一场。

persist() 方法原型:

public void persist(Object object);  

上一段 persist() 测试实例:

try {
    Student stu = new Student("persist()方法", "男");
    session.persist(stu);
    System.out.println("----------输出学生编号Id---------");
    System.out.println(stu.getStuId());
    System.out.println("----------事务在后面-------");
    transaction = session.beginTransaction(); 
    System.out.println("-------------事务提交---------------");
    transaction.commit();
    System.out.println(stu.getStuId());
} catch (Exception e) {
    transaction.rollback();
} finally {
    session.close();
}

输出结果:

----------输出学生编号Id---------
null
----------事务在后面-------
-------------事务提交---------------
Hibernate: 
  insert 
  into
  Student
  (stuName, stuPassword, stuPic, stuSex) 
  values
  (?, ?, ?, ?)
39 

persist() 方法只有当事务提交后,才会发送 Sql 请求,数据直接写入数据库,方法本身没有返回值。

save() 和 persist() 方法区别:

  • 在事务之内调用时,两者区别不大;事务之外,区别明显。
  • save() 返回主键值,persist() 方法没有返回值;
  • persist() 完全依赖事务组件,否则不会提交 Sql 请求;
  • persist() 方法除了可进行 save 操作,还可以进行 update 操作。

3.2 merge() 方法

方法原型:

 public Object  merge(Object object);  

merge() 方法和 persist() 方法类似, 区别在于:

  • merge() 方法接收一个 PO 作为参数,创建并返回此 PO 的副本对象;
  • 此副本对象具有对象持久化能力。这一点是 merge() 方法与其他方法最大的不同。

上一段实例:

try{
    transaction = session.beginTransaction();
    //查询出来的stu具有持久化能力
    Student stu = (Student) session.get(Student.class, new Integer(2));    
    //转stu对象持久化状态转变成游离状态
    session.clear();
    //stu_对象具有持久化能力
    Student stu_ = (Student) session.merge(stu);
    //这个操作不能同步到数据库
    stu.setStuName("我已经不具有持久化能力");
    //这个操作能同步到数据库
    stu_.setStuName("我具有持久化能力");
    transaction.commit();
} catch(Exception e) {
    transaction.rollback();
} finally {
    session.close();
}  

merge() 方法返回的 stu 对象的副本 stu_,此对象具有持久化能力。执行下面代码,数据能同步到数据库中。

stu_.setStuName("我具有持久化能力");  

Session 中提供的每一个方法都有其实际意义。

特别是 merge() 方法,既可以保护原对象中的数据不被污染,又能行使数据库同步操作。

在很多场景里都会有这个需求。

4. 小结

本节课程讲解 PO 对象的 3 种状态,以及 3 种状态之间的转化方式。了解处于持久化状态的 PO 具有持久化能力,这是 Hibernate 提供的一个很棒的 程序中对象数据库数据自动同步的方案。

也是一种快速开发方案。

本节课区分了几个常用方法的差异性。但真相似乎就是:大家都和持久化状态有关系。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1951486.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ElasticSearch核心之DSL查询语句实战

什么是DSL? Elasticsearch提供丰富且灵活的查询语言叫做DSL查询(Query DSL),它允许你构建更加复杂、强大的查询。 DSL(Domain Specific Language特定领域语言)以JSON请求体的形式出现。目前常用的框架查询方法什么的底层都是构建DSL语句实现的,所以你必…

linux 网络子系统

__netif_receive_skb_core 是 Linux 内核网络子系统中一个非常重要的函数,它负责将网络设备驱动层接收到的数据包传递到上层协议栈进行处理。以下是对该函数的一些关键点的详细解析: 一、函数作用 __netif_receive_skb_core 函数是处理接收到的网络数据…

HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据

HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据 📚MT6816相关资料(来自商家的相关资料): 资料:https://pan.baidu.com/s/1CAbdLBRi2dmL4D7cFve1XA?pwd8888 提取码:8888📍驱动代码编写&…

C++的auto关键字

一、auto关键字介绍 因为C是静态类型语言,即会在编译阶段进行类型检查。我们知道对象的类型决定一个对象所能参与的操作,因此如果类型检查过程中发现试图执行对象类型不支持的操作,编译器将会报错。 这要求我们在声明变量时必须指出变量的类…

php、mantis、showDoc部署

下载软件安装包:Mantis Bug Tracker 下载vs包:https://www.microsoft.com/en-us/download/details.aspx?id48145,解决“因为计算机中丢失msvcr110.dll”下载apache服务器:Apache VS17 binaries and modules download下载php:PHP For Windows: Binaries and source…

Kylin 入门教程

Apache Kylin 是一个开源的分布式数据仓库和 OLAP(在线分析处理)引擎,旨在提供亚秒级查询响应时间,即使在处理超大规模数据集时也是如此。Kylin 可以有效地将原始数据预计算为多维数据立方体(Cube),并利用这些预计算结果来提供快速查询。本文将带你从基础知识到操作实践…

【React】详解“最新”和“最热”切换与排序

文章目录 一、基本概念和初始化二、切换与排序功能的实现1. 函数定义和参数2. 设置活动 Tab3. 定义新列表变量4. 根据排序类型处理列表4.1 按时间降序排序4.2 按点赞数降序排序 5. 更新评论列表 三、渲染导航 Tab 和评论列表1. map 方法2. key 属性3. className 动态赋值4. onC…

五大设备制造商的 200 多种机型的安全启动功能完全失效

2012 年,一个由硬件和软件制造商组成的行业联盟采用了安全启动技术,以防范长期存在的安全威胁。这种威胁是恶意软件的幽灵,它可以感染 BIOS,即每次计算机启动时加载操作系统的固件。从那里,它可以保持不受检测和删除&a…

jenkins参数化构建在UI中定义脚本中使用

先看配置: 流水线脚本: pipeline {agent {//label "${server}"label "${28}"}stages {stage(Hello) {steps {echo "--------------------------"// 只有这个可以输出变量echo "${character_argument}"echo &q…

Pytorch使用教学5-视图view与reshape的区别

有同学后台留言问为什么view有时可对张量进行形变操作,有时就会报错?另外它和reshape功能好像一致,有什么区别呢?本文就带你了解PyTorch中视图的概念。 在PyTorch中对张量进行形变操作时,很多同学也会使用view方法&am…

kettle从入门到精通 第八十课 ETL之kettle kettle中的json对象字段写入postgresql中的json字段

场景:源数据库表为mysql的其中有json字段,通过kettle 查询出来 插入到目标数据库 postgresql中,对应的表中也有json字段。。但是报错,提示kettle查询出来是varchar的的字段,无法插入到目标数据库中。 1、创建测试表。 …

【VSCode实战】Golang无法跳转问题竟是如此简单

上一讲【VSCode实战】Go插件依赖无法安装 – 经云的清净小站 (skycreator.top),开头说到了在VSCode中Golang无法跳转的问题,但文章的最后也没给出解决方案,只解决了安装Go插件的依赖问题。 解决了插件依赖问题,无法跳转的问题也离…

echo,tail ,飘号和重定向符

1. 输出指定内容 echo 语法; echo 输出的内容 较多内容使用 “ 双引号 ”, 相当于 printf ; 2. 飘号 飘号,也就是我们通常所说的反引号,被飘号包括的内容会当作命令执行,常配合 echo 使用,输出结果为…

【python】python图书管理系统_普通用户+管理员菜单(源码+论文)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

Docker安装 OpenResty详细教程

OpenResty 是一个基于 Nginx 的高性能 Web 平台,它集成了 Lua 脚本语言,使得开发者可以在 Nginx 服务器上轻松地进行动态 Web 应用开发。OpenResty 的核心目标是通过将 Nginx 的高性能与 Lua 的灵活性结合起来,提供一个强大且高效的 Web 开发…

IO多路复用——select

仅一个线程、进程处理并发 IO多路转接(复用)之select 跨平台适用linux,windows 底层:线性表 IO多路转接(复用)之poll 适用linux 底层:线性表 IO多路转接(复用)之epo…

微信小程序支付流程

前端需要做的事情: 生成平台订单:前端调用接口,向后端传递购买的商品信息、收货人信息,(后端生成平台订单,返回订单编号)获取预付单信息:将订单编号发送给后端后,&#x…

2024最新Selenium面试题(附带答案),建议收藏备用

一.你在TestNG中使用了哪些注解? TestBeforeSuiteAfterSuiteBeforeTestAfterTestBeforeClassAfterClassBeforeMethodAfterMethod 二.如何从Excel中读取数据? FileInputStream fs new FileInputStream(“excel文件路径”); Workbook wb WorkbookFact…

Web前端知识视频教程分享(五) Bootstrap

资料下载地址: https://545c.com/f/45573183-1336822373-45bb4f?p7526 (访问密码: 7526)