JPA 持久性更新
JPA persistence updates
EclipseLink 2.5.2、NetBeans 8.0.2、Java8、德比:
我有一个 DB 结构,具有树状层次结构和使用外键的交叉引用。例如,它具有以下关键关系
- T1 是 parent。
- T2、T3 和 T4 是 T1 的 children。
- T5 是 T4
的 child
T1、T3 和 T5 都有指向 T2 的外键。由于它在 JPA 中实例化为 class 引用或集合引用,因此 T2 的内存对于所有这些保持同步至关重要。
我已验证以下序列会更改我系统中的 T5
- 新T5()
- T5.setT2(T1.getT2.get(0))
- em.persist(T5)
- T4.update(x, y, z)
- em.merge(T4)
因为 T4 有一个集合,所以在上面的第 5 步之后,EclipseLink 已经刷新了 T5 中 T2 的值,但是在 T1 和 T3 所指的不同内存位置。
这合理吗?当数据的位置不同时,我不明白如何信任共同的引用。我错过了什么吗?
我已经升级到 eclipseLink 2.6.0 并切换到 MySQL 并确定这与我发布的关于列表中 NULL 的另一个问题有关。经过几个月的研究,我可以很容易地重现它,但不明白我做错了什么。
虽然 SQL 和数据库完整性完好无损,但我以某种方式破坏了持久性缓存。
该应用程序是关于高尔夫的,为了演示有 3 个相关实体:锦标赛、球员和回合。锦标赛是 parent,其中包含玩家列表。每个玩家都有一个返回锦标赛的外键。玩家有一个回合列表,每一回合都有一个 FK 返回给玩家。
比赛完全配置后,组织者将按下一个按钮为每个玩家创建回合。业务层 (EJB) 执行以下操作:
- em.merge(锦标赛)
- 每个玩家
- 新一轮()
- em.persist(圆)
- player.roundList.add(圆)
- em.merge(玩家)
- em.merge(锦标赛)
- em.find(锦标赛) - 这只是作为查看修改后的参考指针的测试
所有这些都发生在业务层的一次实例化期间,生成的 SQL 正是我所期望的,数据库完整性很好。
要重现,我只需要一个玩家和一个回合,并观察到 em.update(玩家)之后,锦标赛中玩家的参考位置与同一玩家的回合中的参考位置不同。我对此的解释是,它对同一实体有两个内存引用,表明持久性上下文中存在损坏。
最终结果是,在从 EJB 层和 re-reading 锦标赛列表返回后,同一玩家的列表中可能有 NULL 回合。应用程序启动时会发生一些事情,因为这要么会 100% 发生,要么永远不会使用完全相同的代码和顺序来重现它。但是重新启动应用程序后,保存的数据就可以了。
我的业务需求一定很普遍,所以我假设我做错了什么。然而,除了 em.update(player) 这可能是不必要的,我不知道它是什么。任何帮助将不胜感激。
EntityManager 上下文将为您维护通过它读入的所有实体的对象标识。但是每个 EntityManager 都应该像事务一样使用,因此在一个事务中对实体所做的更改不会反映在从另一个 EntityManager 读入的实体中,除非提交事务并刷新实体。这是它们应该是轻量级的并根据需要获取的原因之一,并且在不再使用上下文本身后缓存实体并不是一个好主意。
当您处理从不同上下文中读入的对象时,您将 运行 遇到问题,因为 X' 可能不是 X 的同一个实例,即使它们具有相同的标识 - 您可能会尝试避免传递从中读入的对象尽可能不同的上下文,而是在需要进行更改时获取实体。
EclipseLink 2.5.2、NetBeans 8.0.2、Java8、德比: 我有一个 DB 结构,具有树状层次结构和使用外键的交叉引用。例如,它具有以下关键关系
- T1 是 parent。
- T2、T3 和 T4 是 T1 的 children。
- T5 是 T4 的 child
T1、T3 和 T5 都有指向 T2 的外键。由于它在 JPA 中实例化为 class 引用或集合引用,因此 T2 的内存对于所有这些保持同步至关重要。
我已验证以下序列会更改我系统中的 T5
- 新T5()
- T5.setT2(T1.getT2.get(0))
- em.persist(T5)
- T4.update(x, y, z)
- em.merge(T4)
因为 T4 有一个集合,所以在上面的第 5 步之后,EclipseLink 已经刷新了 T5 中 T2 的值,但是在 T1 和 T3 所指的不同内存位置。
这合理吗?当数据的位置不同时,我不明白如何信任共同的引用。我错过了什么吗?
我已经升级到 eclipseLink 2.6.0 并切换到 MySQL 并确定这与我发布的关于列表中 NULL 的另一个问题有关。经过几个月的研究,我可以很容易地重现它,但不明白我做错了什么。
虽然 SQL 和数据库完整性完好无损,但我以某种方式破坏了持久性缓存。
该应用程序是关于高尔夫的,为了演示有 3 个相关实体:锦标赛、球员和回合。锦标赛是 parent,其中包含玩家列表。每个玩家都有一个返回锦标赛的外键。玩家有一个回合列表,每一回合都有一个 FK 返回给玩家。
比赛完全配置后,组织者将按下一个按钮为每个玩家创建回合。业务层 (EJB) 执行以下操作:
- em.merge(锦标赛)
- 每个玩家
- 新一轮()
- em.persist(圆)
- player.roundList.add(圆)
- em.merge(玩家)
- em.merge(锦标赛)
- em.find(锦标赛) - 这只是作为查看修改后的参考指针的测试
所有这些都发生在业务层的一次实例化期间,生成的 SQL 正是我所期望的,数据库完整性很好。
要重现,我只需要一个玩家和一个回合,并观察到 em.update(玩家)之后,锦标赛中玩家的参考位置与同一玩家的回合中的参考位置不同。我对此的解释是,它对同一实体有两个内存引用,表明持久性上下文中存在损坏。
最终结果是,在从 EJB 层和 re-reading 锦标赛列表返回后,同一玩家的列表中可能有 NULL 回合。应用程序启动时会发生一些事情,因为这要么会 100% 发生,要么永远不会使用完全相同的代码和顺序来重现它。但是重新启动应用程序后,保存的数据就可以了。
我的业务需求一定很普遍,所以我假设我做错了什么。然而,除了 em.update(player) 这可能是不必要的,我不知道它是什么。任何帮助将不胜感激。
EntityManager 上下文将为您维护通过它读入的所有实体的对象标识。但是每个 EntityManager 都应该像事务一样使用,因此在一个事务中对实体所做的更改不会反映在从另一个 EntityManager 读入的实体中,除非提交事务并刷新实体。这是它们应该是轻量级的并根据需要获取的原因之一,并且在不再使用上下文本身后缓存实体并不是一个好主意。
当您处理从不同上下文中读入的对象时,您将 运行 遇到问题,因为 X' 可能不是 X 的同一个实例,即使它们具有相同的标识 - 您可能会尝试避免传递从中读入的对象尽可能不同的上下文,而是在需要进行更改时获取实体。