hibernate中持久化对象的状态
持久化对象有以下几种状态:
临时对象(Transient): 在使用代理主键的情况下,
OID 通常为 null
不处于 Session 的缓存中 在数据库中没有对应的记录
持久化对象(也叫”托管”)(Persist): OID 不为 null
位于 Session 缓存中
若在数据库中已经有和其对应的记录, 持久化对象和数据库中的相关记录对应
Session 在 flush 缓存时, 会根据持久化对象的属性变化, 来同步更新数据库
在同一个 Session 实例的缓存中, 数据库表中的每条记录只对应唯一的持久化对象
删除对象(Removed): 在数据库中没有和其 OID 对应的记录
不再处于 Session 缓存中 一般情况下,
应用程序不该再使用被删除的对象
游离对象(也叫”脱管”) (Detached): OID 不为 null
不再处于 Session 缓存中 一般情况需下,
游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录
持久化对象的状态转换:
对象状态转换的方法解析:
1. save() 方法:可以自动的检测当前save的对象是否已经在数据库中存在这个对象(其实检测时只是在Session缓存中检测,若Session缓存中没有这个对象,则会自动的运行insert语句,若Session的缓存中有这个对象则执行update语句:验证原理:
@Test
public void testUnsaveValue(){
News news=(News)session.get(News.class, 12);
session.clear(); news.setAuthor("jeremy"); news.setDate(new Date());
session.save(news); }
从数据库中获取对象,然后把Session的缓存清理掉,这时对象就变为游离对象了,数据库是有这个对象,但是Session缓存中没有,所以Session会认为你这对象是不存在的,所以就执行更新操作
)
1). 使一个临时对象变为持久化对象
2). 为对象分配 ID.
3). 在 flush 缓存时会发送一条 INSERT 语句.
4). 在 save 方法之前的 id 是无效的
5). 持久化对象的 ID 是不能被修改的!
@Test
public void testSave(){
News news = new News();
news.setTitle("CC");
news.setAuthor("cc");
news.setDate(new Date());
news.setId(100); System.out.println(news); session.save(news); System.out.println(news);
// news.setId(101);
}
persist(): 也会执行 INSERT 操作
1). 使一个临时对象变为持久化对象
2). 为对象分配 ID.
和 save() 的区别 :
在调用 persist 方法之前, 若对象已经有 id 了, 则不会执行 INSERT, 而抛出异常
@Test
public void testPersist(){
News news = new News();
news.setTitle("EE");
news.setAuthor("ee");
news.setDate(new Date());
news.setId(200); session.persist(news);
}
get():从数据库加载一个对象(立即加载)
load():从数据加载一个对象(延迟加载)--工作原理:load()会根据ID先生成一对象代理,等需要用到对象时才真正从数据加载对象,
* get VS load:
* 1. 执行 get 方法: 会立即加载对象.
* 执行 load 方法, 若不使用该对象, 则不会立即执行查询操作, 而返回一个代理对象
*
* get 是 立即检索, load 是延迟检索.
*
* 2. load 方法可能会抛出 LazyInitializationException 异常: 在需要初始化代理对象之前已经关闭了 Session,这个异常就是因为load的工作原理造成的,因为的对象没有被引用,所以load只是生成一个代理,并没有加载对象,而此时关闭了Session,那代理对象怎么初始化,所以只能抛出异常
*
* 3. 若数据表中没有对应的记录, Session 也没有被关闭.
* get 返回 null(比如你让我办事办不成我就返回null)
* load 若不使用该对象的任何属性, 没问题; 若需要初始化了, 抛出异常. (因为代理对象是生成了,但是不能初始化,那就要抛出一个异常了)(你让我办事我先答应了,但是真正办的时候我才知道办了不了,所以返回异常)
@Test
public void testLoad(){ News news = (News) session.load(News.class, 10);
System.out.println(news.getClass().getName()); // session.close();
// System.out.println(news);
} @Test
public void testGet(){
News news = (News) session.get(News.class, 1);
// session.close();
System.out.println(news);
}
update:
* 1. 若更新一个持久化对象, 不需要显示的调用 update 方法. 因为在调用 Transaction的 commit() 方法时, 会先执行 session 的 flush 方法.匹配到缓存和数据库不同会 自动发送upata语句,并不用显式调用
* 2. 更新一个游离对象, 需要显式的调用 session 的 update 方法. 可以把一个游离对象变为持久化对象
代码分析:
@Test
public void testUpdate(){
News news = (News) session.get(News.class, 1); transaction.commit();
session.close(); session = sessionFactory.openSession();
transaction = session.beginTransaction(); news.setAuthor("SUN");
就这个代码分析:
例如当我获取了一个对象后,我提交了事务。关闭了Session,此时我再打开Session和开启事务,然后再操作对象的属性(news.setAuthor("SUN")),此时还会自动发送update语句吗??不会,因为Session已经被关闭了,也就是说前一个Session的缓存被清理了,对象已经不再缓存中了(也就是游离对象),那你现在改变了对象的属性,而对象又不在缓存中,那我Session的缓存是感知不到了吧,感知不到那我就不发送update语句,那我就不发送你修改的对象的属性给数据库吧,
为了解决这问题那咋们就要手动的把对象添加到缓存里去吧,缓存的对象的状态和数据库记录不同时就会自动调用flush()方法吧,会自动发送update语句吧,所以此时数据库的记录会改变吧:
代码:
@Test
public void testUpdate(){
News news = (News) session.get(News.class, 1); transaction.commit();
session.close(); session = sessionFactory.openSession();
transaction = session.beginTransaction(); news.setAuthor("SUN");
Session.update();//就是在这里手动的调用update语句,是游离对象变为持久化对象,需要注意的是游离对象并不存在缓存中的,所以游离对象的所有操作是不被感知的
需要注意的:
* 1. 无论要更新的游离对象和数据表的记录是否一致, 都会发送 UPDATE 语句.
* 如何能让 updat 方法不再盲目的出发 update 语句呢(因为有时会盲目的触发update触发器,导致会出现很多错误) ? 在 .hbm.xml 文件的 class 节点设置
* select-before-update=true (默认为 false). 但通常不需要设置该属性. (因为这样会导致这个对象在每次更新操作都要先查询,降低了效率)
*
* 2. 若数据表中没有对应的记录, 但还调用了 update 方法, 会抛出异常(因为Session的缓存和数据库的记录要保持一致)
*
* 3. 当 update() 方法关联一个游离对象时,
* 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常. 因为在 Session 缓存中不能有两个 OID 相同的对象!
Session 的 saveOrUpdate() 方法同时包含了 save() 与 update() 方法的功能:
判定对象为临时对象的标准:
Java 对象的 OID 为 null
映射文件中为 <id> 设置了 unsaved-value 属性, 并且 Java 对象的 OID 取值与这个 unsaved-value 属性值匹配
注意:
* 1. 若 OID 不为 null, 但数据表中还没有和其对应的记录. 会抛出一个异常.
* 2. 了解: OID 值等于 id 的 unsaved-value 属性值的对象, 也被认为是一个游离对象
Session 的 delete() 方法既可以删除一个游离对象, 也可以删除一个持久化对象 若 OID 在数据表中没有对应的记录, 则抛出异常
Session 的 delete() 方法处理过程:
1)先执行一条select语句,把数据表的记录查询出来,放在Session缓存中
2)计划执行一条 delete 语句 把对象从 Session 缓存中删除, 该对象进入删除状态.
Hibernate 的 cfg.xml 配置文件中有一个 hibernate.use_identifier_rollback 属性, 其默认值为 false, 若把它设为 true,
将改变 delete() 方法的运行行为: delete() 方法会把持久化对象或游离对象的 OID 设置为 null, 使它们变为临时对象
evict: 从 session 缓存中把指定的持久化对象移除,对象就变为游离对象了,不会触发相应的操作,因为已经不在Session缓存的监视下了
hibernate中持久化对象的状态的更多相关文章
- Hibernate中的对象有三种状态
Hibernate中的对象有三种状态: 瞬时状态 (Transient),持久状态 (Persistent), 1. 脱管状态 (Detached) 1. 1. 瞬时状态 (Transient) 由 ...
- (转)Hibernate框架基础——在Hibernate中java对象的状态
http://blog.csdn.net/yerenyuan_pku/article/details/52760627 在Hibernate中java对象的状态 Hibernate把对象分为4种状态: ...
- hibernate中持久化对象的生命周期(三态:自由态,持久态,游离态 之间的转换)
三态的基本概念: 1, 暂时状态(Transient):也叫自由态,仅仅存在于内存中,而在数据库中没有对应数据.用new创建的对象,它没有持久化,没有处于Session中,处于此状态的对象叫暂时对象 ...
- hibernate中持久化对象的生命周期(转载)
三态的基本概念 1, 临时状态(Transient):也叫自由态,只存在于内存中,而在数据库中没有相应数据.用new创建的对象,它没有持久化,没有处于Session中,处于此状态的对象叫临时对象: 2 ...
- Hibernate中实体对象的状态
实体对象的状态 这里的实体对象是指Hibernate的O/R映射关系中的域对象(即O/R中的O).实体对象的生命周期是指实体对象由产生到被GC回收的一段过程,实体对象的生命周期包括3种状态:自由状态( ...
- Hibernate(二)持久化对象的状态
简介 以前学习Hibernate的笔记,整理一下便发出来了,防止弄丢.有错误的话麻烦各位留言评论,感激不尽. 持久化类 Hibernate完成了从面向对象模型表示的对象至关系模型表示的数据结构的映射, ...
- Hibernate -- 操作持久化对象
知识点2: session概述 Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口,它提供了基本的保存,更新, 删除和加载Java对象的方法. 知识点3:理解ses ...
- Hibernate中Java对象的三种状态
Hibernate中Java对象的三种 ...
- Hibernate之Session对象的相关方法以及持久化对象的状态
一.持久化对象的状态 站在持久化的角度, Hibernate 把对象分为 4种状态: 持久化状态,临时状态,游离状态,删除状态.Session 的特定方法能使对象从一个状态转换到另一个状 ...
随机推荐
- atitit.报表最佳实践oae 与报表引擎选型
atitit.报表最佳实践oae 与报表引擎选型 1. 报表的主要的功能and结构 2 1.1. 查询设计器(配置化,metadata in html) ,anno 2 1.2. 查询引擎 2 1.3 ...
- Cadence技巧01:利用Excel速新建原理图元件库
Cadence技巧01:利用Excel速新建原理图元件库 听语音 | 浏览:1698 | 更新:2015-07-02 09:41 | 标签:excel 1 2 3 4 5 6 7 分步阅读 一键约师傅 ...
- 50篇经典珍藏 | Docker、Mesos、微服务、云原生技术干货
概念篇 全方位探(tian)索(keng)Mesos各种存储处理方式 老肖有话说@Mesos User Group第四次约会 技术实践 | Mesos 全方位“烹饪”指南 回顾 JAVA 发展轨迹,看 ...
- JAVA类加载器概念与线程类加载器
类加载器的功能:通过一个类的全限定名来获取描述此类的二进制字节流的过程 java的类加载器大致可以分为两类,一类是系统提供的,一类是由应用开发人员编写的.系统提供的类加载器有以下三种: 引导类加载器( ...
- 每日英语:Why Chinese Companies Lack Homegrown Luxury Brand Power
Chinese companies build iPads, high-speed trains and world-class telecom gear, but they can't seem t ...
- Python正则表达式中的re.S的作用
在Python的正则表达式中,有一个参数为re.S.它表示“.”(不包含外侧双引号,下同)的作用扩展到整个字符串,包括“\n”.看如下代码: import re a = '''asdfhellopas ...
- std::string与output-operator"<<"的兼容问题
经查阅资料得知,“在某些编译器下std::string,需要使用c_str()才能作为output-operator "<<" 的参数” std::string tit ...
- Java 之泛型通配符 ? extends T 与 ? super T 解惑
简述 大家在平时的工作学习中, 肯定会见过不少如下的语句: List<? super T> List<? extends T> 我们都知道, 上面的代码时关于 Java 泛型的 ...
- 纯css3实现的鼠标悬停动画按钮
今天给大家带来一款纯css3实现的鼠标悬停动画按钮.这款按钮鼠标经过前以正方形的形式,当鼠标经过的时候以动画的形式变成圆形.效果图如下: 在线预览 源码下载 实现的代码. html代码: < ...
- 【sql绕过】Bypass waf notepad of def
文章是通过阅读<[独家连载]我的WafBypass之道 (SQL注入篇)>写的阅读笔记. Waf的类型 1.云waf云waf通常是CDN包含的waf,DNS在解析的时候要解析到cdn上面制 ...