现在的位置: 首页 > 综合 > 正文

hibernate 持久化对象的状态

2017年08月15日 ⁄ 综合 ⁄ 共 2878字 ⁄ 字号 评论关闭

站在持久化的角度, Hibernate 把对象分为 4 种状态: 持久化状态, 临时状态, 游离状态, 删除状态. Session 的特定方法能使对象从一个状态转换到另一个状态.

持久化对象的状态

临时对象(Transient): 

–在使用代理主键的情况下, OID
通常为null
不处于 Session的缓存中
在数据库中没有对应的记录

持久化对象(也叫”托管”)(Persist):

OID 不为null
位于 Session缓存中
–若在数据库中已经有和其对应的记录,持久化对象和数据库中的相关记录对应
Session flush缓存时,会根据持久化对象的属性变化,
来同步更新数据库
在同一个 Session实例的缓存中,数据库表中的每条记录只对应唯一的持久化对象

删除对象(Removed)

–在数据库中没有和其 OID 对应的记录
–不再处于 Session缓存中
–一般情况下, 应用程序不该再使用被删除的对象

游离对象(也叫”脱管”) (Detached):

OID 不为 null
不再处于 Session 缓存中
一般情况需下, 游离对象是由持久化对象转变过来的, 因此在数据库中可能还存在与它对应的记录

对象的状态转换图



save()与persist()

  • Session 的 save() 方法使一个临时对象转变为持久化对象
  • Session 的 save() 方法完成以下操作:
    News对象加入到
    Session缓存中,使它进入持久化状态
    选用映射文件指定的标识符生成器,
    为持久化对象分配唯一的OID.
    在使用代理主键的情况下, setId()方法为News对象设置OID是无效的.数据库会自动重新分配id
    计划执行一条 insert
    语句:在 flush缓存的时候

  • Hibernate 通过持久化对象的 OID 来维持它和数据库相关记录的对应关系. 当 News 对象处于持久化状态时,
    不允许程序随意修改它的 ID
  • persist() 和 save() 区别(persist()也会执行insert操作):

–当对一个 OID 不为Null的对象执行save()方法时,会把该对象以一个新的oid保存到数据库中;  但执行 persist()方法时会抛出一个异常.(在调用persist方法之前,若对象已经有id了,则不会执行insert,,而抛出一个异常)

get()与load()

  • 都可以根据跟定的 OID 从数据库中加载一个持久化对象
  • 执行load方法,若不使用该对象,则不会立即执行查询操作,而返回一个代理对象
  • 区别:
    –当数据库中不存在与OID对应的记录时,且session也没有被关闭,load()若不使用该对象没问题,若需要初始化了,会抛出 ObjectNotFoundException异常,而get()方法返回null
    –两者采用不同的延迟检索策略:load
    方法支持延迟加载策略。而get
    不支持。

    load()可能会抛出LazyInitializationException 异常:在需要初始化代理对象之前已经关闭了session

update()

  • 若更新一个持久化对象,不需要显示地调用update方法,因为在调用Transaction的commit()方法时,会先执行session的flush方法
  • Session 的 update() 方法使一个游离对象转变为持久化对象, 并且计划执行一条 update 语句.
  • 注意:
1.无论要更新的游离对象和数据库的记录是否一致,都会发送update语句
     如何能让update方法不盲目的触发update语句呢?若希望 Session 仅当修改了 News 对象的属性时, 才执行 update() 语句, 可以把映射文件中 <class> 元素的 select-before-update 设为 true. 该属性的默认值为 false,但通常不需要设置该设置该属性(在update的情况下需要多发一条select语句)
2.当 update() 方法关联一个游离对象时, 如果在数据库中不存在相应的记录, 也会抛出异常. 
3.当 update() 方法关联一个游离对象时, 如果在 Session 的缓存中已经存在相同 OID 的持久化对象, 会抛出异常。因为在session缓存中不能有两个oid相同的对象。

saveOrUpdate()

  • Session 的 saveOrUpdate() 方法同时包含了 save() 与 update() 方法的功能

  • 判定对象为临时对象的标准
    Java 对象的
    OID null
    –映射文件中为<id>设置了unsaved-value  属性,并且Java对象的OID取值与这个unsaved-value属性值匹配
  • 注意
1.若OID不为null,但数据表中还没有和其对应的记录,会抛出一个异常
2.了解:OID值等于id的unsaved-value属性的对象也被认为是一个游离对象

merge()




delete()

  • 执行删除操作,只要OID和数据表中一条记录对应,就会准备执行delete操作,若OID在数据表中没有对应的记录,则抛出异常
  • Session 的 delete() 方法既可以删除一个游离对象, 也可以删除一个持久化对象
  • Session的delete()方法处理过程
    –计划执行一条delete语句(提交之前该对象还是具有OID的,还是可以使用该对象)
    –提交之后把对象从Session缓存中删除,该对象进入删除状态.
  • Hibernate的cfg.xml配置文件中有一个hibernate.use_identifier_rollback属性,其默认值为false,若把它设为true,将改变delete()方法的运行行为:delete() 方法会把持久化对象或游离对象的 OID设置为null,使它们变为临时对象

evict()

  • 从session缓存中把指定的持久化对象移除

通过 Hibernate 调用存储过程

Work 接口: 直接通过 JDBC API 来访问数据库的操作

Session 的 doWork(Work) 方法用于执行 Work 对象指定的操作, 即调用 Work 对象的 execute() 方法. Session 会把当前使用的数据库连接传递给 execute() 方法.



Hibernate 与触发器协同工作

Hibernate 与数据库中的触发器协同工作时, 会造成两类问题

–触发器使Session的缓存中的持久化对象与数据库中对应的数据不一致:触发器运行在数据库中,它执行的操作对Session是透明的
–Session的update()方法盲目地激发触发器:无论游离对象的属性是否发生变化,都会执行update语句,而update语句会激发数据库中相应的触发器

解决方案: 

–在执行完Session的相关操作后,立即调用Session的flush()和refresh()方法,迫使Session的缓存与数据库同步(refresh()方法重新从数据库中加载对象)

-在映射文件的的 <class> 元素中设置 select-before-update 属性: 当 Session 的 update 或 saveOrUpdate() 方法更新一个游离对象时, 会先执行 Select 语句, 获得当前游离对象在数据库中的最新数据, 只有在不一致的情况下才会执行 update 语句

抱歉!评论已关闭.