【问题标题】:JPA GeneratedValue generated and already existent IdJPA GeneratedValue 已生成且已存在的 Id
【发布时间】:2020-10-25 03:33:12
【问题描述】:

我正在开发一个使用 JPA 的 Spring 应用程序。具体来说,为了生成我的实体的 ID,我使用了 @GeneratedValue 注释。例如:

@Entity
public class SomeEntity {
  @Id
  @GeneratedValue
  private Long id;
  
  private String someField;

  // Getters and Setters...
}

问题是,我正在将数据预加载到数据库中。例如,在someFile.sql 我有常规的INSERT 语句:

INSERT INTO some_entity (id, some_field) VALUES (1, 'foo');
INSERT INTO some_entity (id, some_field) VALUES (2, 'bar');
...

然后,我只是使用mysql命令行客户端插入数据:

mysql someDB < someFile.sql

问题是,当尝试使用 JPA 持久化一个新实体时,将分配的第一个 id 是1。但是,该 ID 已被我预加载到数据库中的实体之一使用。这样,我得到一个重复的键错误:

2020-07-04 16:08:42.365 错误 847 --- [https-jsse-nio-8080-exec-9] ohengine.jdbc.spi.SqlExceptionHelper:密钥“PRIMARY”的重复条目“1”

我考虑过使用带有@SequenceGenerator 的初始值。但是,如果我要预加载的初始值数量增加,这种方法可能会导致不得不更改代码。

关于不同方法的任何想法?

【问题讨论】:

  • 从日志中,我看到您正在使用 Hibernate 作为持久性提供程序。你用的是哪个版本?

标签: jpa spring-data-jpa jpa-2.0


【解决方案1】:

嗯,最简单的解决方案是让脚本本身为下一个生成的 id 建立正确的值。

如果您使用 Hibernate hibernate.id.new_generator_mappings=false,您的设置将导致 id 成为 AUTO_INCREMENT 列。在这种情况下,只需添加

ALTER TABLE some_entity AUTO_INCREMENT = <last_inserted_id>

在脚本的末尾。或者,更好的是,如果可能的话,尝试完全摆脱硬编码的 id 值。您可以使用 LAST_INSERT_ID() 检索最后插入的 id,并使用该值在相关行中设置外键列。

另一方面,如果您在没有任何特殊配置的情况下使用 Hibernate 5,您应该在架构中找到一个 hibernate_sequence 表,该表存储了 Hibernate 使用的下一个生成的 id。您将需要添加以下内容:

UPDATE hibernate_sequence SET next_val= <max_inserted_id_for_any_table_plus_one>

作为旁注,if you're using the latter approach by accident, you might want to switch to the former

【讨论】:

  • 我最终将生成策略切换为IDENTITY,这似乎有效(id 现在是AUTO_INCREMENT)。我不知道AUTO 策略默认为TABLE 与MySQL,也不知道LAST_INSERTED_ID()。谢谢!
猜你喜欢
  • 1970-01-01
  • 2020-11-08
  • 2012-02-23
  • 1970-01-01
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 2021-12-14
相关资源
最近更新 更多