在从 class 生成的模式和从文件加载的初始数据之后插入新条目时出现 JdbcSQLIntegrityConstraintViolationException

JdbcSQLIntegrityConstraintViolationException when inserting new entry after schema generated from class and initial data loaded from file

我有一个带有 h2 数据库的 spring 引导项目。

我有一个实体 class 从中生成模式:

@NoArgsConstructor
@Entity
@Table(name = "NAMES")
public class Name {

    @Id
    @GeneratedValue
    public Long id;

    @Column(nullable = false)
    public String name;

    public Name(String name) {
        this.name = name;
    }

}

我有一个 data.sql 文件:

insert into names (id, name) values (1, 'Alex');
insert into names (id, name) values (2, 'Bob');

我的 application.properties 是:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.defer-datasource-initialization=true
spring.jpa.show-sql=true

应用程序启动正常,我可以通过 localhost:8080/h2-console 确认数据已加载到数据库中。 但是我无法将新数据保存到 table with

//public interface NameRepository extends CrudRepository<Name,Long> {}

@RestController
@Service
public class MyController {

  @Autowired
  private final NameRepository nameRepository;

  @PostMapping("/triggerError")
  public ResponseEntity<Void> trigger() {

    Name newName = new Name("Chris");
    nameRepository.save(newName);
    return ResponseEntity.ok().build();
  }
}

错误信息是:

could not execute statement; SQL [n/a]; constraint [\"PRIMARY KEY ON PUBLIC.NAMES(ID) ( /* key:1 */ CAST(1 AS BIGINT), 'Alex')\"; SQL statement:
insert into names (name, id) values (?, ?) [23505-210]];

我假设这意味着 spring 想要在 id=1 处插入新名称,但没有意识到 id 1 和 2 已经在使用中。我想 @GeneratedValue 的正确参数可以修复它,但我不明白它们的含义以及选择哪个参数。

反复试验:

@GeneratedValue(strategy = GenerationType.AUTO) 是默认值,见上文。
@GeneratedValue(strategy = GenerationType.TABLE)同样的错误
@GeneratedValue(strategy = GenerationType.SEQUENCE)同样的错误
@GeneratedValue(strategy = GenerationType.IDENTITY) 不同的错误:

...
Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: NULL not allowed for column \"ID\"; SQL statement:\ninsert into names (id, name) values (null, ?) [23502-210]
...
could not execute statement; SQL [n/a]; constraint [null]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement

所以显然不是注释,而是其他东西。

我要放弃了,这是我的 MRE:https://github.com/timo-a/duckpond-spring-backend/tree/debug/saving

这是 hibernate 上的一个错误,特定于 h2 数据库。 https://hibernate.atlassian.net/browse/HHH-14985

您可以使用 id BIGINT GENERATED BY DEFAULT AS IDENTITY DEFAULT ON NULL PRIMARY KEY 列定义作为修复。

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(columnDefinition = "id BIGINT GENERATED BY DEFAULT AS IDENTITY DEFAULT ON NULL PRIMARY KEY")
private Long id;

@Shankar Ghimire 部分正确。这既是 Hibernate 错误也是 data.sql 问题。将您的 Hibernate 版本更新到 5.6.5:

implementation('org.springframework.boot:spring-boot-starter-data-jpa'){
  exclude group: 'org.hibernate', module: 'hibernate-core'
}
implementation 'org.hibernate:hibernate-core:5.6.5.Final'

并且由于您使用的是 h2 auto_increment,因此您应该删除 data.sql

中的 ID
insert into names (name)
values ('Alex'),('Bob');

序列不会递增,否则会导致唯一索引或主键冲突。


顺便说一下,您的存储库使用 Integer 作为您的主键,而您的实体使用 Long。由于问题被标记为 JPA,因此使用 :

public interface NameRepository extends JpaRepository<Name,Long> {}

你在一个名为“scores”的 table 中插入数据,但我认为这是一个打字错误。