当前位置: 首页 > 知识库问答 >
问题:

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

衡安晏
2023-03-14

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

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我们不会使用构造函数创建新对象,并且变量保持不变,而数据库中存在两个实体。

共有1个答案

单于海荣
2023-03-14

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

  • JPA做了大量工作来抽象“对象标识”与“具有相同主键的对象”这一事实。JPA 90%的复杂性源自引入该模型
  • 您正试图基于JPA试图抽象的行为显式构建您的逻辑

因此,您不是在使用JPA,而是在与之斗争。

如果你试图效仿,你最终会得到一些易碎和丑陋的东西-你也会感觉到JPA在某种程度上辜负了你(就像你试图用螺丝刀钉钉子一样)。

为了让它很好地工作,你需要做的是:

  • 要么在每次业务操作后丢弃EntityManager(这是EE web应用程序中的默认行为-EntityManager仅适用于单个事务,并被丢弃)。
  • 如果要复制对象,请执行以下操作:复制对象。为此编写(或生成)Java代码

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

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

 类似资料:
  • 我正在使用springboot jpa存储库保存方法 这是完整的错误:2020-06-09 15:49:02.371[nio-8080-exec-4]。M.M.A.ExceptionHandlerExceptionResolver:由处理程序执行导致的解析异常:org.springframework.dao.invalidDataAccessapiusageException:传递给persist

  • 问题内容: 提交表单时出现此错误: org.hibernate.PersistentObjectException:分离的实体传递给持久化:com.project.pmet.model.Account; 嵌套异常是javax.persistence.PersistenceException:org.hibernate.PersistentObjectException:传递给持久对象的分离实体:c

  • null 我能找到的使用JPA/Hibernate的唯一有效解决方案是执行以下步骤。这是因为hibernate将实体保留在第一级缓存中,直到事务结束。 创建新实体 强制快速刷新() 分离实体 这样做的开销是 null 使用JDBC或JdbcTemplate,但您必须为实体编写自己的插入 所以问题是:是否存在同时坚持和分离的可能性,或者甚至更好地坚持而不成为被管理的?

  • 问题内容: 我有一个JPA持久对象模型,其中包含多对一关系:一个具有许多。A 有一个。 这是一段代码: 我能够创建一个对象,向其中添加事务,并正确地持久保存该对象。但是,当我 使用现有的已经持久化的Account 创建一个事务并持久化 该Transaction时 ,出现一个异常: 引起原因:org.hibernate.PersistentObjectException:传递给持久对象的分离实体:c

  • 我在提交表单时遇到以下错误: org.hibernate.PersistentObjectException:传递给Persisted的分离实体:com.project.pmet.model.Account;嵌套异常为javax.persistence.persistenceException:org.hibernate.persistentObjectException:传递到persist的分

  • 摘自Java Persistence with Hibernate(Manning,2007)第419页: 我应该在会话上使用持久化()吗?Hibernate会话接口还具有一个持久化()方法。它与JPA的持久化()操作具有相同的语义学。但是,这两种操作在刷新方面有一个重要的区别。在同步期间,Hibernate会话不会将持久化()操作级联到关联的实体和集合,即使您使用此选项映射了关联。它只级联到调用