Hibernate 中的对象状态

Hibernate 中的对象有 3 种状态:

  • Transient(瞬时状态)
  • Persistent(持久状态)
  • Detached(脱管状态)

在持久层的对象也称为 PO(PersistenceObject),瞬时对象和脱管对象也可称为 VO(ValueObject)。它们互相转化的状态图如下:

瞬时状态

由 new 命令分配内存空间,如果没有变量对它进行引用,它将被 JVM 回收。瞬时对象在内存中孤立存在,它的意义仅是携带信息的载体,不和数据库的数据有任何关联关系。通过 Session 的 save()和 saveOrUpdate()方法可以把一个瞬时对象和数据库相关联,并把瞬时对象携带的信息通过配置文件所做的映射插入到数据库中,这个瞬时对象就成为了持久化对象,并拥有和数据库记录相同的 id 标识(Hibernate 自动将 id 值赋予它)。

瞬时对象的特点是:

  1. 不和 Session 实例关联。
  2. 在数据库中没有和瞬时对象关联的记录。

持久化状态

持久 (Persistent) 的实例在数据库中有对应的记录,并拥有一个持久化标识 (identifier)。持久的实例可能是刚被保存的,或刚被加载的,无论那一种,按定义对象都仅在相关联的 Session 生命周期内保持这种状态。如果是直接进行数据库查询所返回的数据对象,例如使用 find()、get()、load() 和 iterater()等方法查询到的数据对象,则这些对象都与数据库中的字段相关,具有与数据库识别值相同的 id 值,它们也马上变为持久对象。另外,如果一个瞬时对象被持久化对象引用,则该对象也会自动变成持久化对象

如果使用 delete()方法,它就会变回瞬时对象。将删除数据库中这个对象关联的记录,对象与数据库不再有任何的关联。

持久对象总是与 Session 和 Transaction 相关联,在一个 Session 中,对持久对象的改变不会马上对数据库进行变更,而必须在 Transaction 终止,也就是执行 commit()之后,才在数据库中运行 SQL,持久对象的状态才会与数据库进行同步。在同步之前持久对象称为脏对象。

当一个 Session 执行 Close()或 clear()、evict()之后,持久对象会变为脱管对象,这时对象的 id 虽然拥有数据库识别值,但它们目前并不在 Hibernate 持久层的管理之下,它与瞬时对象本质上是相同的,只不过比瞬时对象多了数据标识的 ID 值。在没有任何变量引用的情况下,JVM 会在适当的时候将其回收。

持久对象的特点是:

  1. 和 Session 实例关联。
  2. 在数据库中有和持久对象关联的记录。

脱管状态

与持久对象关联的 Session 被关闭后,对象就变为脱管对象。对脱管对象的引用依然有效,对象可以继续被修改。脱管对象如果重新关联到某个新的 Session 上,会再次转变为持久对象。

脱管对象的特点是:

  1. 本质上和瞬时对象相同。
  2. 只是比瞬时对象多了一个数据库记录标识值 ID。

示例

对持久化的对象进行修改时,不用 session.update()方法,hibernate 自动会发出更新的 SQL 语句:

保存对象为持久化状态的对象后,该对象含有主键 id: