如何在 Postgres 和 H2 中处理同一事务中的插入和删除而不发生唯一索引冲突?
我有一个 Spring Boot 项目,其中有一个用于生产的 postgreSQL 数据库和一个用于测试的 h2 数据库。我正在通过 JpaRepository::save 更新嵌套对象。该对象保存其组件的列表,每个组件都有自己的 id 和一个在 SQL 模式中定义的唯一约束下的值。以下是精简版本:
@Entity
class Class {
@Id
int id
@OneToMany(fetch = FetchType.EAGER, mappedBy = "class", orphanRemoval = true, cascade = { CascadeType.ALL })
List<Pupil> pupils;
}
@Entity
class Pupil {
@Id
int id
int bookId;
}
我可能会更新现有的 Class 4567
,其中唯一值已更改,例如删除了 pupil 1
并添加了新的 pupil 21
添加了之前由学生 1
持有的书 8486
。由于唯一约束仍然有效,我希望 jpa 能够毫无问题地执行更新,因为“后状态”有效。 然而,情况并非如此,而是根据
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PUPIL_UNIQUE_INDEX_4 ON PUBLIC.PUPIL(CLASS_ID, BOOK_ID) VALUES (4567, 8486)"; SQL statement:
insert into PUPIL (PUPIL_ID, BOOK_ID) values (?, ?) [23505-191]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PUPIL_UNIQUE_INDEX_4 ON PUBLIC.PUPIL(CLASS_ID, BOOK_ID) VALUES (4567, 8486)"; SQL statement:
insert into PUPIL (PUPIL_ID, BOOK_ID) values (?, ?) [23505-191]];
...
这篇文章: https://mossgreen.github.io/JPA-parent-children-updating-violates-constraint/ JPA实际上并没有意识到之后的状态将是有效的,但先插入然后已经抱怨。该帖子建议将 DEFERRABLE INITIALLY DEFERRED
添加到唯一约束中,但是尽管我有 application.properties,但这在 h2 上不起作用:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
我不想丢失 bookId
我不能仅仅删除 h2 作为测试数据库。我怎样才能在一个 JpaRepository::save
中进行插入和删除工作?
I have a spring boot project with a postgreSQL database in production and an h2 database for testing. I am updating a nested object via JpaRepository::save
. The object holds a list of its components who each have their own id and a value under a unique constraint, defined in the SQL schema. Below is a condensed version:
@Entity
class Class {
@Id
int id
@OneToMany(fetch = FetchType.EAGER, mappedBy = "class", orphanRemoval = true, cascade = { CascadeType.ALL })
List<Pupil> pupils;
}
@Entity
class Pupil {
@Id
int id
int bookId;
}
It can happen that I update an existing Class 4567
where the unique values have changed, e.g. pupil 1
is removed and a new pupil 21
is added with book 8486
which was previously held by pupil 1
. As the unique constraint is still valid I expect jpa to execute the update without issues as the "after state" is valid.
However, this is not the case, instead I get
org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint ["PUPIL_UNIQUE_INDEX_4 ON PUBLIC.PUPIL(CLASS_ID, BOOK_ID) VALUES (4567, 8486)"; SQL statement:
insert into PUPIL (PUPIL_ID, BOOK_ID) values (?, ?) [23505-191]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement
...
Caused by: org.h2.jdbc.JdbcSQLException: Unique index or primary key violation: "PUPIL_UNIQUE_INDEX_4 ON PUBLIC.PUPIL(CLASS_ID, BOOK_ID) VALUES (4567, 8486)"; SQL statement:
insert into PUPIL (PUPIL_ID, BOOK_ID) values (?, ?) [23505-191]];
...
According to this post: https://mossgreen.github.io/JPA-parent-children-updating-violates-constraint/ JPA does not in fact realize that the after state will be valid but inserts first and then already complains. The post reccomends adding DEFERRABLE INITIALLY DEFERRED
to the unique constraint, however that doesn't work on h2 despite my application.properties:
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
I do not want to lose the unique constraint on bookId
and I cannot just drop h2 as a test database. How can I still make inserts and deletions in one JpaRepository::save
work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论