Hibernate对象状态之间的神奇转换
状态分类
在Hibernate框架中,为了管理持久化类,Hibernate将其分为了三个状态:
- 瞬时态(Transient Object)
- 持久态(Persistent Object)
- 脱管态(Detached Object)
有很多人好像对这些概念和它们之间的转换不太明白,那么本篇文章就是来解决这些问题的,看完了还不会你来找我。(开个玩笑~~)
详细描述
我们先来详细地了解一下三种状态:
1、瞬时态
对象由new操作符创建,且尚未与Hibernate中的Session关联的对象被认为处于瞬时态。瞬时态对象不会被持久化到数据库中,也不会赋予持久化标识,如果程序中失去了瞬时态对象的引用,瞬时态对象将被垃圾回收机制销毁。
2、持久态
持久化实例在数据库中有对应的记录,并拥有一个持久化标识。持久化的实例可以是刚刚保存的,也可以是刚刚被加载的。无论哪一种,持久化对象都必须与指定的Session对象关联。
3、脱管态
某个实例曾经处于持久化状态,但随着与之关联的Session被关闭,该对象就变成脱管状态。脱管状态的引用引用依然有效,对象可继续被修改。如果重新让脱管对象与某个Session关联,该脱管对象会重新转换为持久化状态。
瞬时态 | 持久态 | 脱管态 | |
是否存于Session缓存中 | × | √ | × |
数据库中是否有对应记录 | × | √ | √ |
例如:
public class HibernateTest {
private Session session;
private Transaction transaction;
@Before
public void before() {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
}
@After
public void after() {
transaction.commit();
session.close();
}
@Test
public void test() {
Person p = new Person();
p.setPname("张三");
p.setAge(20);
session.save(p);
}
}
那么在这样的一个例子中,从创建Person对象到给name和age属性赋值,这些过程都处于瞬时态,而当调用了session对象的save()方法之后,该对象才从瞬时态转为了持久态。而当session关闭之后,该对象又从持久态转为了脱管态。
对象状态之间的转换
了解了三种对象状态的相关概念后,我们来看一看三种对象状态之间是如何神奇地相互转换的。
瞬时态 <——> 持久态
我们知道当创建一个对象之后,该对象即为瞬时态,那么它将如何转换为持久态呢?
看一个例子:
@Test
public void test() {
Person p = new Person();
p.setPid(2);
p.setPname("李四");
p.setAge(30);
session.save(p);
//session.saveOrUpdate(p);
}
给name和age属性赋值时,该对象仍然处于瞬时态,这个前面已经说过了。但需要注意的是,当给主键也就是Pid属性赋值时,该对象将不再处于瞬时态,而是转换为脱管态,因为此时已经有了持久化标识,但是并没有与Session发生关联。而当调用session对象的update()或者saveOrUpdate()方法时,该对象才会转换为持久态。
当然,调用session对象的get()、load()、query、find()等方法从数据库中查询得到的对象也处于持久态。
而仅仅当session对象调用delete()方法将一个持久化的对象从数据库中删除后,该对象才从持久态转为了瞬时态。
持久态 <——> 脱管态
当调用session对象的close()、clear()等方法后,该session所关联的对象将从持久态转为脱管态,此时这些对象失去了相关session的关联。而要想从脱管态转回持久态,只需调用save()、saveOrUpdate()等方法即可。
瞬时态 ——> 脱管态
这个前面也已经说过了,当创建对象后调用setXXX()方法设置主键属性时,该对象就从瞬时态转为脱管态,前提是这个主键是数据库中存在的。
对象生命周期
下面以一个对象从创建到保存至数据库的流程做一个分析:
try {
Session session = HibernateUtil.openSession();
//开始事务
session.beginTransaction();
//person对象进入瞬时状态态
Person p = new Person();
p.setPname("王五");
p.setAge(40);
//person对象进入持久化状态
session.save(p);
//提交事务,隐式包含了session.flush()的动作
session.getTransaction().commit();
//提交完成后,person处于游离状态
} catch (HibernateException e) {
e.printStackTrace();
if (session != null)
session.getTransaction().rollback();
} finally {
if (session != null)
session.close();
}
当一个对象被实例化后,该对象是瞬时状态,当调用session.save(Object)后,该对象被加入到session缓存中,进入持久化状态,这时数据库中还不存在对应的记录。当session提交事务后,数据库生成了对应的记录,但是这里需要注意一点,因为事务提交的时候默认会去调用session.flush()方法来清空缓存,相当于调用了clear()方法,而我们知道,调用了clear()方法,对象会从持久态转为脱管态。而处于脱管态的对象会被垃圾回收机制销毁。这就是一个对象从创建到保存至数据库的完整生命周期过程。
其它
对于对象状态有了一定的了解之后,可以用来解释很多现象。
在Hibernate中,唯有当对象从其它状态转为持久态时,它才会去自动生成sql语句,其它时候是不会去重复生成sql,这就是Hibernate框架提高效率的关键所在。
例如:
@Test
public void test2() {
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
Person p = new Person();
p.setPname("李四");
p.setAge(30);
session.save(p);
p.setPname("王五");
session.update(p);
transaction.commit();
session.close();
}
我在transaction.commit();这条语句上打了一个断电,然后调试运行。
可以看到,控制台只输出了一条sql语句,也就是执行save()方法时生成的插入语句,但是执行update()方法却并没有生成sql。这是因为在执行update()方法时,Hibernate框架会去判断当前对象的状态,它发现当前对象处于持久态,所以不重复生成sql,只是将持久态对象的值改变而已,然后调用commit()方法进行事务提交的时候才去生成更新语句。
我们继续看一个例子:
@Test
public void test2() {
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
Person p = new Person();
p.setPname("张三");
p.setAge(30);
session.save(p);//此时该对象从瞬时态转为持久态,生成sql语句
p.setPname("王五");
session.save(p);//此时该对象为持久态,不生成sql语句
p.setPname("赵六");
session.update(p);//此时该对象为持久态,不生成sql语句
transaction.commit();
session.close();
}
你要知道,这跟你调用哪个方法是无关的,关键在于对象的状态,只有转为持久态时才会生成sql语句。所以上面的程序段依然只会产生两条sql,一条是save()方法产生的,一条是commit()方法产生的。
控制台信息如下:
Hibernate:
insert
into
PERSON
(PNAME, AGE)
values
(?, ?)
Hibernate:
update
PERSON
set
PNAME=?,
AGE=?
where
PID=?
理解Hibernate的三种状态,将更有利于理解Hibernate的运行机制,这些可以让你在开发中对疑点问题的定位产生关键性的帮助。
Hibernate对象状态之间的神奇转换的更多相关文章
- Hibernate对象状态
对象状态 瞬时(transient) 自己new出来的对象,数据库没有记录与之对应,与session也没有关联 持久(persistent) 数据库中有记录与之对应,当前与session有关联,相关的 ...
- hibernate对象状态 的小问题
Class classA{ List a; public void setA(List a) { this.a =a; } public List getA() { return this.a; } ...
- hibernate 对象状态异常:object references an unsaved transient instance - save the transient instance before flushing
我的问题出在,删除的对象对应的表中有一个外键,关联着另外一个表,可是另外一个表中没有数据,所以报了这个错误. 参考http://www.cnblogs.com/onlywujun/archive/20 ...
- hibernate框架学习之对象状态
lHibernate对象共有三种状态 •瞬时状态:瞬时对象 •持久化状态:持久化对象 •托管状态:托管对象 l瞬时对象(Transient Object),简称TO l瞬时对象指的是应用程序创建出来的 ...
- hibernate 对象三态(瞬态、持久态、脱管态)之我见
刚开始学习hibernate时,对其对象的三种状态理解的模模糊糊,一直停留在一知半解的状态,前两天又回顾了一下,顿时醒悟,原来三种状态理解起来是很容易的. 先看一下对Hibernate对象状态的解释: ...
- hibernate对象的三种状态及转换
一.hibernate对象三种状态 Transient(瞬时状态):没有session管理,同时数据库没有对应记录 举例:new 出来的对象还没有被session管理,此时该对象处于Transient ...
- Hibernate对象的状态
站在持久化的角度, Hibernate 把对象分为 4 种状态: 1. 持久化状态 2. 临时状态 3. 游离状态 4. 删除状态 Session 的特定方法能使对象从一个状态转换到另一个状态. 下面 ...
- Hibernate持久化对象状态
在Hibernate中,持久化对象再被操作过程中分为三个时期.这三个时期和session周期相关. 各自是瞬时(Transient),持久太(persistent)和游离态(Detached) 瞬时状 ...
- Hibernate(四)之对象状态及一级缓存
一.Hibernate中的对象状态 1.1.瞬时态(临时态) 没有与Hibernate产生关联 与数据库中的记录没有产生关联(有关联就是与数据库中表的id相对应) 获得:一般都只直接创建(new) 瞬 ...
随机推荐
- springboot基础(随笔)
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot ...
- 《VR入门系列教程》之8---GearVR
高端移动虚拟现实设备---三星GearVR Oculus Rift也许是虚拟现实头显的典范,但是它还是存在许多问题.首先,它需要基于一个具有强大图形计算能力的计算机,而使用一般的笔记本.苹果A ...
- JAVA项目从运维部署到项目开发(五. Nginx)
<Nginx与Nginx-rtmp-module搭建RTMP视频直播和点播服务器>一文简单介绍了关于直播数据流的nginx相关配置,下面简单介绍下各种项目如何配置nginx. web项目. ...
- Uploadify.js引用导致浏览器宽度计算错误,布局混乱
首先,本人新手,高手勿喷,请忽略.谢谢. 今天在写代码的时候遇到一个奇葩问题,我再在页面加载完成以后,动态计算DIV宽度,将整个层铺满浏览器.一切正常.单当我引入jquery.uploadify.js ...
- httpclient 方式提供接口
在后台写好自己的方法: 打开shiro验证,设置url访问: 提供包调用http方式连接后台获取数据: String url = getUrl(); HttpClient client = new H ...
- 下载Opencv和OpencvSharp,让我们开始图像之旅
我们学习和使用OpencvSharp,还下载Opencv干什么?很简单,研究人家的源码是最好和最快速的学习方式. 第一Opencv源码下载,网络上很多,请大家自行搜索,版本请下载4.1.0.当前你要用 ...
- 关于Hibernate查询对象调用set方法自动同步到数据库解决方案
Hibernate的get和load方法查询出的实体都是持久化对象,拿到该对象后,如果你调用了该对象的set方法,如果再同一个事务里面,那么在事务递交的时候,Hibernate会把你设置的值自动更新到 ...
- Java类的加载 链接 初始化
原文地址 Java类的加载.链接和初始化.Java字节代码的表现形式是字节数组(byte[]),而Java类在JVM中的表现形式是java.lang.Class类的对象.一个Java类从字节代码到能够 ...
- PAY8 数字货币支付结算系统,全球付!实时结算!秒到账!
数字货币支付是历史发展的必然 如今已经有越来越多的地方接受加密数字货币作为支付消费了,比如泰国电影院连锁店 Cineplex Group 可用加密货币买爆米花和电影票,西班牙一精品酒店接受数字货币支付 ...
- codeforces 371A K-Periodic Array
很简单,就是找第i位.i+k位.i+2*k位...........i+m*k位有多少个数字,计算出每个数出现的次数,找到出现最多的数,那么K-Periodic的第K位数肯定是这个了.这样的话需要替换的 ...