JPA GeneratedValue 已生成且已存在的 Id

JPA GeneratedValue generated and already existent Id

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

@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 ERROR 847 --- [https-jsse-nio-8080-exec-9] o.h.engine.jdbc.spi.SqlExceptionHelper : Duplicate entry '1' for key 'PRIMARY'

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

对不同的方法有什么想法吗?

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

如果您将 Hibernate <5 或 Hibernate 5 与 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 table,它存储下一个生成的要使用的 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