文档章节

hibernate中持久化对象的状态

jj_soft
 jj_soft
发布于 2016/06/04 15:24
字数 2077
阅读 2
收藏 0

持久化对象有以下几种状态:

临时对象(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缓存的监视下了

© 著作权归作者所有

jj_soft
粉丝 1
博文 96
码字总数 74097
作品 0
广州
程序员
私信 提问
简单理解Hibernate三种状态的概念及互相转化

本文描述了Hibernate三种状态的概念及互相转化。Java对象的生命周期中有三种状态,而且互相转化。它们分别是临时状态,持久化状态,以及游离状态。 AD:51CTO学院:IT精品课程在线看! 在Hib...

xiaml
2014/03/30
97
0
博为峰Java技术文章 ——JavaEE Hibernate实例状态

博为峰小博老师: Hibernate的实例状态分为3种,分别为瞬时状态(Transient)、持久化状态(Persistent)和脱管状态(Detached)。 瞬时状态(Transient) 实体对象是通过Java中的new关键字开辟内存空...

博为峰教研组
2016/12/27
8
0
Video-No.02 尚硅谷_Hibernate4视频教程

1、Ecplise hibernate插件安装: 下载zip格式的Eclipse插件,(http://sourceforge.net/projects/jboss/files/JBossTools/JBossTools4.1.x/hibernatetools-Update-4.1.1.Final2013-12-0801-......

蓝汀华韶
2015/07/11
261
0
关于hibernate中对象的三种状态分析

一、首先Hibernate中对象的状态有三种:瞬态、游离态和持久态,三种状态转化的方法都是通过session来调用,瞬态到持久态的方法有save()、saveOrUpdate()、get()、load();持久态到瞬...

大黄有故事
2016/10/23
0
0
hibernate映射对象三种状态的分析

一,首先hibernate中对象的状态有 三种:瞬态、游离态和持久态,三种状态转化的方法都是通过session来调用,瞬态到持久态的方法有save()、saveOrUpdate()、 get()、load();持久态到...

无信不立
2014/09/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

zk中选举Leader时的网络IO QuorumCnxManager解析

每台服务启动过程中,会启动一个QuorumCnxManager,负责各台服务器之间底层Leader选举过程中的网络通信 当集群中有服务器服务中断时,zk会重新选举leader 内部类 Message定义消息结构 包含了...

writeademo
14分钟前
2
0
使用mdBook 替代 gitbook。

###** 为什么要替代gitbook** gitbook 有个模板问题:如果md文件中有连续的大括号(比如:&{{父亲 40}}),gitbook会把{{ 父亲 40 }}中的父亲 40当做一个模板变量。如果这个变量不存在,会报...

王坤charlie
17分钟前
2
0
TL-A7HSAD采集卡硬件的处理器、NOR FLASH、DDR3

TL-A7HSAD是一款由广州创龙基于Xilinx Artix-7系列FPGA自主研发的高速数据采集卡,可配套广州创龙TMS320C6655、TMS320C6657、TMS320C6678开发板使用。该采集卡包含1个双通道250MSPS*12Bit的高...

Tronlong创龙
29分钟前
3
0
项目启动报fastjson版本可能过低

进行项目启动的过程中,之前都正常,这次启动突然就失败了: 查看日志说的是版本过低,后来查看官方网站版本,替换了最新版本: 选择了最新版本的1.2.60,1.2.62尝试后都不行,后来查看网上搜...

aiChuang
30分钟前
2
0
McDonald’s is using Alexa and Google to accepting job applications

McDonald’s today announced a new initiative the fast food chain is calling the “Apply Thru,” in which owners of Amazon Alexa or Google Assistant devices can begin job applic......

wowloop
33分钟前
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部