Hibernate对象状态及方法详解

hibernate对象状态图

这里写图片描述

hibernate对象的三种状态及特征

1.三种状态:

瞬时 (Transient )/临时状态/自由状态
持久 (Persistent)
脱管 (Detached)/游离状态

2.特征:

瞬时对象特征:

  (1)不处于 Session 的缓存中,也可以说,不被任何一个 Session 实例关联。

  (2)在数据库中没有对应的记录。

持久化对象特征:

  (1)持久化对象总是被一个 session 关联。

  (2)持久化对象与数据库中的记录对应。

  (3)Session清理缓存的时候,会根据持久化对象的改变,更新数据库。

托管对象特征:

  (1)Session断开关联

  (2)持有OID

3.三种状态的区别分析:

  只要与session关联的就是持久态。

  Session没关联,没有OID就是瞬时状态。

  Session没关联,有OID的就是游离状态。

注意:

在Hibernate所有的操作只认OID,如果两个对象的OID一致,它就直接认为是同一个对象。

方法详解及区别

一、save 和update区别
把这一对放在第一位的原因是因为这一对是最常用的。
save的作用是把一个新的对象保存
update是把一个脱管状态的对象或自由态对象(一定要和一个记录对应)更新到数据库

二、update 和saveOrUpdate区别
这个是比较好理解的,顾名思义,saveOrUpdate基本上就是合成了save和update,而update只是update;引用hibernate reference中的一段话来解释他们的使用场合和区别
通常下面的场景会使用update()或saveOrUpdate():
程序在第一个session中加载对象,接着把session关闭
该对象被传递到表现层
对象发生了一些改动
该对象被返回到业务逻辑层最终到持久层
程序创建第二session调用第二个session的update()方法持久这些改动

saveOrUpdate(po)做下面的事:
如果该po对象已经在本session中持久化了,在本session中执行saveOrUpdate不做任何事
如果savaOrUpdate(新po)与另一个与本session关联的po对象拥有相同的持久化标识(identifier),抛出一个异常
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [org.itfuture.www.po.Xtyhb#5]
saveOrUpdate如果对象没有持久化标识(identifier)属性,对其调用save() ,否则update() 这个对象

三、persist和save区别
这个是最迷离的一对,表面上看起来使用哪个都行,在hibernate reference文档中也没有明确的区分他们.
这里给出一个明确的区分。(可以跟进src看一下,虽然实现步骤类似,但是还是有细微的差别)
主要内容区别:
1、persist把一个瞬态的实例持久化,但是并”不保证”标识符(identifier主键对应的属性)被立刻填入到持久化实例中,标识符的填入可能被推迟到flush的时候。

2、 save, 把一个瞬态的实例持久化标识符,及时的产生,它要返回标识符,所以它会立即执行Sql insert

四、saveOrUpdate,merge和update区别
比较update和merge
update的作用上边说了,这里说一下merge的
如果session中存在相同持久化标识(identifier)的实例,用用户给出的对象覆盖session已有的持久实例
(1)当我们使用update的时候,执行完成后,会抛出异常
(2)但当我们使用merge的时候,把处理自由态的po对象A的属性copy到session当中处于持久态的po的属性中,执行完成后原来是持久状态还是持久态,而我们提供的A还是自由态

五、flush和update区别
这两个的区别好理解
update操作的是在自由态或脱管状态(因session的关闭而处于脱管状态)的对象//updateSQL
而flush是操作的在持久状态的对象。
默认情况下,一个持久状态的对象的改动(包含set容器)是不需要update的,只要你更改了对象的值,等待hibernate flush就自动更新或保存到数据库了。hibernate flush发生在以下几种情况中:
1、 调用某些查询的和手动flush(),session的关闭、SessionFactory关闭结合
get()一个对象,把对象的属性进行改变,把资源关闭。
2、transaction commit的时候(包含了flush)

六、lock和update区别
update是把一个已经更改过的脱管状态的对象变成持久状态
lock是把一个没有更改过的脱管状态的对象变成持久状态(针对的是因Session的关闭而处于脱管状态的po对象(2),不能针对因delete而处于脱管状态的po对象)
对应更改一个记录的内容,两个的操作不同:
update的操作步骤是:
(1)属性改动后的脱管的对象的修改->调用update
lock的操作步骤是:
(2)调用lock把未修改的对象从脱管状态变成持久状态–>更改持久状态的对象的内容–>等待flush或者手动flush
* *
clear完整的清除session缓存
evcit(obj)把某个持久化对象从session的缓存中清空。

P.S.
1、save和perisit
几乎一样,都是持久化一个临时对象;
只是persist持久化的时间可能推迟到flunsh之前,而且perisit传入的对象为托管对象时,会报错,而save托管对象不会报错只是将id置null。

可以看出,在持久化一个临时对象时,只用save就行了。

2、saveOrUpdate和merge
saveOrUpdate将unsaved对象持久化或托管对象持久化;
merge,从名字也能猜到是合并,跟saveOrUpdate相似,可以持久化托管和临时对象。
不同的是:在更新时候,merge将托管对象的属性复制到session中有相同标识符(但不相等)的持久对象(如果不存在,就从db load),也就是先select 后 update;倘若找不到相同标识符的对象,则置id为null,保存临时对象。返回的是持久对象,但是merge传入的对象还是托管的。

可以看出,只有在session中已经存在一个具有相同标识符的持久对象的时候,应该采用merge,此时用saveOrUpdate会报错。当然如果碰到这类情形,将对象属性copy到已经持久化的那个相同标识符对象上也是可以的,正因为如此我一般都没用过merge。再者merge在session中不存在相同标识对象时,会多一条select,往往我们并不需要。

3、 merge和replicate
replicate,通过复制来持久化当前已经脱离session的托管对象,这点上看有点像merge,但是当传入一个临时对象则会报错,而且replicate后的传入的那个对象将是持久的,这也是跟merge不同。
通过参数ReplicationMode可以控制遇到相同记录时的行为。
如果是 ReplicationMode.EXCEPTION,则在复制时如果有重复的行数据,则抛出异常。ReplicationMode.IGNORE则忽略 异常。
ReplicationMode.OVERWRITE则会覆盖掉已有行数据。ReplicationMode.LATEST_VERSION则是在有重复时使用最新的版本进行控制。

可以看出,replicate在执行复制的时候,比起merge还是有更多可控行为,ReplicationMode.LATEST_VERSION还可以保证并发修改时只更新最新的版本。

4、lock和refresh
相类似的,都将托管对象又重新持久化,而且可以指定查询时候的锁:
* 当用户显式的使用数据库支持的SQL格式SELECT … FOR UPDATE 发送SQL的时候,锁定级别设置为LockMode.UPGRADE
* 当用户显式的使用Oracle数据库的SQL语句SELECT … FOR UPDATE NOWAIT 的时候,锁定级别设置LockMode.UPGRADE_NOWAIT
*当Hibernate在“可重复读”或者是“序列化”数据库隔离级别下读取数据的时候,锁定模式 自动设置为LockMode.READ。这种模式也可以通过用户显式指定进行设置。
*LockMode.NONE 代表无需锁定。在Transaction结束时, 所有的对象都切换到该模式上来。与session相关联的对象通过调用update() 或者saveOrUpdate()脱离该模式。
以上只有 LockMode.NONE,先从缓存查找持久对象;其他的都直接从数据库查找。

有些不同的是,lock还有检查对象版本的能力,如果指定的锁定模式是READ, UPGRADE 或 UPGRADE_NOWAIT,那么Session.lock()就 执行版本号检查。

refresh提供了比load更方便的查找能力,一个刚脱离了session的持久对象,如果用load还需要用id查找,那么refresh就可以直接传入托管对象刷新其状态了。

5、delete和evict
evict,从session的缓存中去除当前实例。执行后对象的改变将不再和数据库保持同步。当指定级联风格为’evict’时,会级联操作关联对象。在用于批量操作的时候,清空缓存,防止内存紧张。
delete,也会从session的缓存中去除当前实例,但flunsh时会执行数据库delete,之后对象就成了临时状态。
可以看出delete比起evict,不仅从session删除,还会从数据库删除。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

离水的鱼儿

一分也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值