2 实体操作
2.2 实体实例的生命周期
这章描述 EntityManager 用于管理实体实例生命周期的方法。实体实例可以 是 new、managed、detached、或者 removed。
z 新实体实例没有持久化唯一标识,还没有和持久化上下文建立关联。
z 受管理的实体实例具有持久化标识,和一个持久化上下文建立了关联。
z 脱管的实体实例具有持久化标识,但没有或不再和持久化上下文有关联。
z 移除的实体实例具有持久化标识,和持久化上下文有关联,它将被从数 据库中删除。
下面的章节描述了生命周期操作对实体产生的影响。cascade 注解元素用于 迁移这些影响到相关的实体上。Cascade 典型的应用在父子关系中。
2.2.1 持久化实体实例
通过调用 pesist 方法或者通过层级产生的持久化可以使新实体变成受管理的 和持久化的。
下面的描述就是持久化操作语义应用到实体 X 的效果:
z 如果 X 是一个新实体,那么他变成受管理的。实体 X 将在事务提交之 前/时或执行 flush 操作后保存到数据库中。
z 如果 X 是已经存在的受管理的实体,那么它将被持久化操作忽略。然而,
如 果 X 到 它 引 用 的 实 体 间 的 关 系 被 注 解 为 cascade=PERSIST 或 cascade=ALL,那么持久化操作将会传递到 X 引用的实体。在 XML 配
置文件中同样配置也是可以的。
z 如果 X 是一个 removed 实体,它变成受管理的实体。
z 如果 X 是脱管的,那么执行持久化操作就会抛出 EntityExistsException,
或者在 flush 或提交时抛出 EntityExistsException 或 PersistenceException。
z 对于 X 引用的所有实体 Y,如果指向 Y 的关系(字段)被注解为 cascade=PERSIST 或 cascade=ALL,那么持久化操作应用到 Y。
2.2.2 Removal
当调用 remove 方法或被 remove 方法层级到受管理的实体时,受管理的实例 变成可删除的。
Remove 操作应用到实体 X 上的语义如下所述:
z 如果 X 是新实体,那么 remove 操作将忽略它。然而,如果 X 到它引用 的实体间的关系被注解为 cascade=REMOVE 或 cascade=ALL,那么 remove 操作将会传递到 X 引用的实体。在 XML 配置文件中同样配置也 是可以的。
z 如果 X 是受管理的,那么 remove 操作将使它变成可删除的。如果 X 到 它引用的实体间的关系被注解为 cascade=REMOVE 或 cascade=ALL,那 么 remove 操作将会传递到 X 引用的实体。
z 如 果 X 是 脱 管 的 , 那 么 执 行 remove 操 作 就 会 抛 出 IllegalArgumentException(或者事务提交失败)。
z 如果 X 是可删除实体,那么它被 remove 操作忽略。
z 可删除实体 X 将在事务提交时或在 flush 操作执行后从数据库中删除。
在实体被删除后,它的状态(除了生成的状态)将是 remove 操作被调用时 刻的状态。
2.2.3 数据库同步
持久化实体的状态在事务提交时被同步到数据库中。同步会引起对持久化实
体及其关联的实体的更新持久化到数据库中。 体上。EntityManager 和 Query 的 setFlushMode 方法用于控制同步语义。
FlushModeType.AUTO 在 2.6.2 章节中定义。如果指定为 FlushModeType.COMMIT,
那么在事务提交时执行 flush;持久化供应商可以但不要求在其他时间执行 flush。
如果没有活动事务,那么持久化供应商不必执行 flush。
Flush 操作应用到实体 X 上的语义如下所述:
z 如果 X 是受管理实体,它被同步到数据库。
对于 X 引用的所有实体 Y,如果指向 Y 的关系被注解为 cascade=PERSIST 或 cascade=ALL,则持久化也应用到 Y。
对于 X 引用的所有实体 Y,如果指向 Y 的关系没有被注解为 cascade=PERSIST 或 cascade=ALL,那么:
如果 Y 是 new 或者 removed,则执行 flush 操作时抛出
IllegalStateExcpetion 异常,并且回滚事务,或者事务提交失败。
如果 Y 是脱管的,同步的语义依赖于关系的拥有者。如果 X 拥 有关系,对关系的任何改变都会同步到数据库;否则,如果 Y 是关系的拥有者,如何处理没有规定。
z 如果 X 是将删除的实体,那么它将从数据库中删除。不需要层级设置。
2.2.4 脱管实体
如果使用事务范围的容器管理的实体管理器(参见 2.3),那么提交事务、回 滚事务、清除持久化上下文、关闭实体管理器、以及序列化实体或按值传递一个 实体(如在分布式应用中,通过远程接口传递等)都会产生脱管实体。
脱管实体实例一直存在于持久化上下文的外部,它们的状态不再保证和数据 库一致。
在持久化上下文结束后,应用可以获取可以获取的脱管实体实例的可读取状 态。可读取的状态包括:
z 标志不为 fetch=LAZY 的任何可持久化字段或属性。
z 任何可以被应用获取的字段或属性。
如果持久化字段或属性是关系字段,那么只有关联实例是可以获取时,才可 以安全地获取关联的实例的状态。可获取的实例包括:
z 任何用 find()方法获取的实体实例。
z 任何用查询获取的或显式地在 FETCH JOIN 语句中要求的实体实例。
z 任何可被应用获取的实体实例,这些实体实例的变量持有非主键的持久 化状态。
z 任何可以通过标记为 fetch=EAGER(即非 LAZY 方式)的迁移关系从其 他实体实例间接获取的实体实例。
2.2.4.1 合并(Merge)脱管实体状态
Merge 操作使得脱管实体转变成被 EntityManager 管理的持久化实体。
Merge 操作的语义用实体 X 说明如下:
z 如果 X 是脱管实体,那么它被复制到一个和它具有相同标识的预先存在 的受管理实体实例 X’,或者创建一个新的 X 的复制品。
z 如果 X 是新实体实例,那么会创建一个新的受管理的实体实例 X’,并
且 X 的状态会被复制到 X’。
z 如 果 X 是 一 个 被 删 除 实 体 实 例 , 在 merge 操 作 中 将 抛 出 IllegalArgumentException(或者事务提交失败)。
z 如果 X 是受管理实体,merge 操作将忽略它,但是,merge 操作将被层 级传递到 X 引用的标志有 cascade=MERGE 或 cascade=ALL 实体上。
z 对所有 X 引用的标志为 cascade=MERGE 或 cascade=ALL 的实体,Y 将 被迭代成 Y’。对 X 引用的这些 Y,X’将引用相应的 Y’。(注意,如果 X 是受管理的,那么 X 和 X’是同一个对象)。
z 如果 X 引用的所有 Y 没有标志为 cascade=MERGE 或 cascade=ALL,那 么 X’会产生一个对受管理实体 Y’的引用,这个 Y’与 Y 有相同的标识。
持久化提供商不必 merge 标记为 LAZY 且还没有被读取的字段,在 merge 时,必须忽略这些字段。
持久化运行时实现在 merge 时或/和在 flush 或在提交时,必须检查任何被实 体使用的 Version 列。没有 Version 列时,在 merge 时不需要执行检查。
2.2.4.2 脱管实体和懒惰加载
当使用懒惰的属性或字段和/或关系时,不同的提供商序列化实体和 merge 实体到持久化上下文可以不同。
供应商需要支持在分离的 JVM 间对脱管实体实例的序列化和反序列化,以 及 merge(这些实例可以包含还没有加载的懒惰的属性或字段和/或关系),在这 些 JVM 中,运行时实例既可以获取实体类,也可以获取持久化实现的类。
当多个供应商之间协作时,应用不要使用懒惰加载。
2.2.5 管理实体实例
应用应当确保实例只在一个持久化上下文中。没有规定同一个 Java 实例在 多个持久化上下文中如何处理。
Contains()方法用于确定一个实体实例是否被当前的持久化上下文管理。
在下列情况下,Cotains 方法返回 true:
z 如果实体已经从数据库中取出,但还没有被删除或脱管。
z 如果实体实例是新的,并且已经调用 persist 方法,或者持久化操作层级 到这个实体。
在下列情况下,contains 方法返回 false:
z 如果实例已经脱管。
z 如果已经调用 remove 方法,或者 remove 操作层级到这个实体上。
z 如果实体是新的,但 persist 方法还没有被调用,或者 persist 方法还没有 层级到这个实体上。
注意:contains 方法会立即知道 perist 或 remove 方法的层级影响,但是对数 据库的真正的插入、删除在事务的最后才真正产生。