gpt4 book ai didi

java - JPA:分离后保留(用于创建实体副本)会混淆 EntityManager 缓存

转载 作者:行者123 更新时间:2023-12-02 02:43:19 26 4
gpt4 key购买 nike

我使用此代码来制作实体的副本:

EntityClass obj = em.find(...);
em.detach(obj);
obj.setId(null);
obj.setName("New");
em.persist(obj);
em.flush();

所以问题是 - 如果我从这个创建的副本中创建一个新副本,它们都指向实体管理器缓存中最后创建的副本!

// Call#1 copy method
Entity obj = em.find(Entity.class, 1); // old object, id = 1
em.detach(obj);
obj.setId(null);
em.persist(obj); // created new object with id = 2
em.flush();

// Call#2 copy method
Entity obj2 = em.find(Entity.class, 2); // our copy, id = 2
em.detach(obj2);
obj2.setId(null);
em.persist(obj2); // created new object with id = 3
em.flush();

// Call another method
Entity someObj = em.find(Entity.class, 2); // returns last copy with id=3!
// it's like after persist obj2 (id=2) points
// to the same memory address as the new copy with id = 3

执行复制方法后,evictAll() 使其颠倒 - 现在 id=2 和 id=3 都指向 id=2 的原始副本。我认为这在某种程度上与以下事实有关:在 Java 中,我们不使用构造函数创建新对象,并且当数据库中存在两个实体时,变量保持不变。

最佳答案

问题的根源是你和JPA之间的主要冲突:

  • JPA 做了很多工作来抽象出“对象标识”与“具有相同主键的对象”不同这一事实。 JPA 90% 的复杂性源于引入此模型。
  • 您正尝试根据 JPA 试图抽象的行为来显式构建逻辑。

因此,您不是在使用 JPA,而是在对抗它。

如果您尝试效仿,您最终会得到一些脆弱且丑陋的东西 - 而且您还会感觉 JPA 在某种程度上让您失望(就像您尝试用 Screwdriver 钉钉子时的感觉一样)。

要使其正常工作,您需要做的是:

  • 要么在每次业务操作后丢弃 EntityManager(这是 EE Web 应用中的默认行为 - EntityManager 仅在单个事务中存在并被丢弃)
  • 如果你想复制一个对象,只需这样做:复制一个对象。编写(或生成)Java 代码来执行此操作。

您最终可能会得到优雅的、可测试的代码,没有显式的缓存操作、没有刷新、没有“合并”和“分离”。

抱歉,我知道这不是您想听到的建议类型。如果您想了解 JPA 思维模式并了解 JPA 行为的基本原理,请查看经典的 Fowler 企业模式,尤其是工作单元身份映射

关于java - JPA:分离后保留(用于创建实体副本)会混淆 EntityManager 缓存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45073980/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com