【问题标题】:Seam/Hibernate/JPA -- Duplicate primary key exception?Seam/Hibernate/JPA——重复主键异常?
【发布时间】:2011-03-28 23:59:56
【问题描述】:

我有一个使用 Seam 和 JPA (Hibernate) 持久化的对象模型。它看起来像这样:

@Entity(name = "MyObject")
public class MyObject {

...

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_myobj")
@SequenceGenerator(name = "seq_myobj", sequenceName = "seq_myobj")
private Long id = null;

@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = false)
@NotNull
   private MySubObject subObjA=null;

@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = false)
@NotNull
   private MySubObject subObjB=null;

...

}

@Entity(name = "MySubObject")
public class MySubObject {

...

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq_mysubobj")
@SequenceGenerator(name = "seq_mysubobj", sequenceName = "seq_mysubobj")
private Long id = null;

}

我已经正确定义了我的@ManyToOne 注释以及所有内容。但是,如果我尝试保留一个MyObject 的实例,其中设置了subObjAsubObjB,我会得到一个异常,说我有一个重复的主键,其中一个子obj。什么会导致这种行为?两个对象的标识符类型都设置为 SEQUENCE,如果我设置一个或另一个我没有问题。只有当我同时设置两者时,我才会得到异常。

我正在运行 Seam 2.2,我的后端数据库是 PostgreSQL。关于可能导致这种奇怪行为的任何想法?我认为这两个对象将作为同一事务的一部分保留,并且将自动分配正确的主键。就像我说的,如果我只设置其中一个对象没有问题。只有当我同时设置它们时才会发生这种情况。非常感谢您提供的任何帮助。

编辑 但是,我在测试各种事物时注意到了一些奇怪的行为。如果我以编程方式创建 MyObject 并设置其所有属性(包括 subObj),它仍然没有问题。但是,如果我使用表单输入属性,则会收到错误消息。会不会跟交易有关?

【问题讨论】:

  • 您能向我们展示您应用的所有 JPA 注释吗?
  • 请告诉我们您是否在 MySubObject 类中覆盖 equals/hashCode。
  • 已编辑以在 subObjA/B 属性上包含注释
  • 是的,我在 MySubObject 上实现了 equals/hashCode
  • @Shadowman 您能否展示您的表单的简化版本以及如何保存 myObject 及其 mySubObject 属性?只是一个建议:未初始化的字段是隐含的 null,所以你不需要写 private MySubObject subObjA = null; 只需 private MySubObject subObjA; 就足够了。

标签: java hibernate jpa seam primary-key


【解决方案1】:

如果您在 MySubObject 类中覆盖 equals/hashCode,请确保这些方法仅检查代理键 id(在这种情况下,您应该完全避免使用它们)。

如果 equals/hashCode 方法适用于某些业务键属性,请确保这些键在持久化之前是唯一的。

【讨论】:

  • 我已经尝试过了,但仍然收到相同的错误。但是,在测试各种事物时,我注意到了一些奇怪的行为。如果我以编程方式创建 MyObject 并设置其所有属性(包括 subObj),它仍然没有问题。但是,如果我使用表单输入属性,则会收到错误消息。会不会跟交易有关?
  • 如果表单的行为如下,它可能与事务有关:第一个 subObj 在失败的事务中使用序列中的 ID 持久化。随后的异常被屏蔽,代码继续保持第二个 subObj,以便它获得相同的 ID。
  • 该表单是两步数据提交过程的一部分。在第一页,用户输入有关他们提交的数据的一些基本信息。在第二页上,他们输入了更详细的信息,包括设置 subObjA 和 subObjB 的属性。在用户单击第二页上的“提交”之前,不会进行 entityManager.update() 调用。这就是我看到异常的地方,所以现在我认为它与这个工作流程有关,因为我可以毫无问题地以编程方式创建对象。知道发生了什么吗?我应该尝试什么?
  • 并不是说这一定与重复密钥问题有关,但通常您不会在对话驱动的应用程序中调用 entityManager.update()。如果实体是持久的,则在 flush() 时对其进行更新,否则使用 entityManager.persist() 对其进行持久化。我建议打开 SQL 日志记录,看看在第 2 步期间数据库会发生什么情况。根据您描述的提交过程,第1步不应该有任何SQL命令。
  • 我说错了。我在存储数据时调用persist()。
【解决方案2】:

通过一系列测试和不同的场景,并找到了可行的场合。因此,当我提交并持久保存到数据库时,我的操作类中似乎存在错误。

【讨论】:

    猜你喜欢
    • 2018-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-29
    • 2020-08-12
    • 2018-02-02
    • 2011-02-18
    相关资源
    最近更新 更多