当前位置: 首页 > 面试题库 >

JPA 2 @SequenceGenerator @GeneratedValue产生唯一约束冲突

岳彬炳
2023-03-14
问题内容

问题概述

在看似随机的时间,我们会收到一个异常“
PostgreSQL重复键违反了唯一约束”。我确实认为我知道我们的问题是什么,但是我不想在没有可重现的测试用例的情况下对代码进行更改。但是由于除了随机生产之外,我们无法在任何环境中复制它,因此我要求SO的帮助。

在这个项目中,我们有多个postgres数据库,并且为每个数据库中的每个表配置了主键序列。这些序列是这样创建的:

create sequence PERSONS_SEQ;
create sequence VISITS_SEQ;
etc...

我们使用以下序列来为实体生成主键,如下所示:

@Entity
@Table(name = "visits")
public class Visit {
  @Id
  @Column(name = "id")
  @SequenceGenerator(name = "seq", sequenceName = "visits_seq")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
  private int id;
  ...
}

@Entity
@Table(name = "person")
public class Person {
  @Id
  @Column(name = "id")
  @SequenceGenerator(name = "seq", sequenceName = "persons_seq")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
  private int id;
  ...
}

分析

我认为此配置存在2个问题:

1)两个@SequenceGenerators都指定相同的name属性,即使它们应该映射到不同的数据库序列。

2)@SequenceGenerator
distributionSize属性默认为50(我们使用hibernate模式作为JPA提供程序),因此我认为创建序列语法应指定序列应增加多少,特别是增加50才能匹配allocationSize。

基于这种猜测,我认为应该将代码修改为如下形式:

create sequence PERSONS_SEQ increment by 50;
create sequence VISITS_SEQ increment by 50;
etc...

@Entity
@Table(name = "visits")
public class Visit {
  @Id
  @Column(name = "id")
  @SequenceGenerator(name = "visits_seq", sequenceName = "visits_seq")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "visits_seq")
  private int id;
  ...
}

@Entity
@Table(name = "person")
public class Person {
  @Id
  @Column(name = "id")
  @SequenceGenerator(name = "persons_seq", sequenceName = "persons_seq")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "persons_seq")
  private int id;
  ...
}

我只是测试一下,而不是问SO的问题,但是同样,我们还无法在任何其他环境中重现此生产问题。甚至在生产中,唯一约束违反也只会在看似随机的时间发生。

问题:

1)我在分析更改以解决此唯一约束冲突方面是否正确?

2)将hibernate用作JPA提供程序时,使用序列生成器的最佳实践是什么?


问题答案:
  1. 是的,您的分析是正确的。您已正确确定问题所在(我们有类似的问题)。而且…如果您要将其投入生产,请不要忘记:

    • 要么为具有正确的初始值/初始ID的新序列生成器手动生成序列表(否则,hibernate将从1开始,您将再次获得)
    • 或在代码中设置该值(签initalValue@SequenceGenerator)。
    • 我无法列举最佳实践,但我想您可以降低50的极限。我也没有PostgreSQL的经验,但是在MySQL中,您有一个简单的seq表。generator和hibernate使整个过程变得完整。


 类似资料:
  • 问题内容: 如何在hibernatePOJO上实现我的唯一约束?假设数据库不包含任何内容。 我在注解中看到了唯一属性,但无法正常工作吗? 如果我想将此约束应用于多个列怎么办? 问题答案: 基本上,没有数据库支持就无法实现唯一约束。 和属性是架构生成工具生成相应约束的指令,它们本身并没有实现约束。 您可以在插入新实体之前进行某种手动检查,但是在这种情况下,您应该意识到并发事务可能存在的问题。 因此,

  • 我有一个Spring MVC应用程序,它使用Spring Data JPA作为我的JPA提供者来持久化Hibernate。我有一个数据库表,在列上有一个唯一的约束,因此为什么保存相应的实体可能会导致唯一的约束冲突。我想检测这是否发生在我的服务层中,以便我可以向用户呈现有意义的错误消息。以下是我的服务方法。 我的Spring Data JPA存储库看起来像这样: 现在,当发生唯一的约束冲突时,我得到

  • 我的桌子有两个独特的列: 我想写保存或更新方法 My jooq code: 但我遇到了异常: “错误:没有唯一或排除约束匹配ON CONFLICT规范” 请帮助。

  • 我有一个用户创建屏幕,它记录了各种用户详细信息以及名字和手机号码。我有一个对应的用户表,其中名字和手机号码构成一个复合唯一键。此表中还定义了其他完整性约束。 当在创建用户屏幕上输入违反此约束的用户数据时,需要向用户显示“用户友好”错误消息。 当这种违反发生时,我从MySQL数据库中得到的异常是: 有两个选项可以显示有意义的消息(例如:“错误:给定手机号码的用户名已存在,请更改其中一个”)。 选项1

  • 当尝试使用PostgreSQL执行时,我遇到了一个我不理解的行为。文档似乎指示语句的冲突目标可以是索引表达式或约束名称。但是,当试图引用约束名称时,我得到了一个“列...不存在”错误。 我的第一次尝试是创建一个索引,它可以很好地处理约束推理: 在描述上表时,我在“索引”下看到了以下内容: 我的第二次尝试是将唯一约束显式地放在创建表中: 在描述上表时,“索引:”的输出略有不同(“唯一约束”与前一示例

  • 主要内容:在创建表时设置唯一约束,在修改表时添加唯一约束,删除唯一约束MySQL 唯一约束(Unique Key)是指所有记录中字段的值不能重复出现。例如,为 id 字段加上唯一性约束后,每条记录的 id 值都是唯一的,不能出现重复的情况。如果其中一条记录的 id 值为‘0001’,那么该表中就不能出现另一条记录的 id 值也为‘0001’。 唯一约束与主键约束相似的是它们都可以确保列的唯一性。不同的是,唯一约束在一个表中可有多个,并且设置唯一约束的列允许有空值,但