Hibernate H2指定删除表顺序

6
我遇到了与这个用户类似的问题。Hibernate不能在每次SpringBootTest之后(例如运行mvn test时)删除我的内存测试数据库表格。希望的行为是ddl-auto=create-drop,但这不起作用。
我认为原因可能是DROP TABLE语句的顺序无效,因此Hibernate尝试删除其他表格仍依赖的表格。
我的data.sql脚本仅包含INSERT语句,并且基于我的实体自动创建模式。我尝试将DROP TABLE语句添加到data.sql的顶部,它们都通过了(ddl-auto=create),因为我可以指定它们必须被删除的顺序。另一方面,我现在也必须在data.sql中指定模式创建。
有没有办法在不必指定模式创建的情况下指定删除语句的顺序?或者有人知道最初的问题的解决方法?
编辑:
我想给出一个例子。我有一个User实体,它与其他实体具有关系(M:N、1:N、1:1)。当模式创建时,Hibernate会删除所有表格,创建它们并添加约束:
// first test file:
Hibernate: drop table user if exists
... // drop other tables
Hibernate: create table user (username varchar(255) not null, ... , primary key (username))
... // create other tables
Hibernate: alter table X add constraint FKgi38hy0tsrdm332gdjrc0uhm3 foreign key (username) references user
Hibernate: alter table Y add constraint FK5svpy1b71l4jxni0xylrbbdtv foreign key (username) references user
Hibernate: alter table Z add constraint FK5a8fxbb0ug3eo1lisdrrxbbj foreign key (username) references user

// next test file:
Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Cannot drop "USER" because "FKGI38HY0TSRDM332GDJRC0UHM3, FK5SVPY1B71L4JXNI0XYLRBBDTV, FK5A8FXBB0UG3EO1LISDRRXBBJ" depends on it; SQL statement:
drop table user if exists [90107-200]

在第一个测试文件之后,该过程无法运行,因为它违反了限制条件。这就是我想指定删除顺序的原因。

我没有在实体上使用CascadeType,这可能会导致问题吗?


你能展示一下你的映射和删除语句吗? - Simon Martinelli
首先发布删除语句,并告诉我们在哪个删除语句上失败了。然后我们会看看是否存在映射问题。 - Simon Martinelli
1
@SimonMartinelli,看起来并不是这样。使用replace=none选项和springboot 2.2.2时,情况并非如此。虽然在2.0.4版本中是这样的,但使用这个选项和springboot 2.2.2后,数据库只会被初始化一次,而不是被删除,因此下一个测试文件的初始化将失败。 - Martin Mucha
@MartinMucha 是的,你说得对。 - Simon Martinelli
@MarmiteBomber 谢谢你的回复。对我来说很难从项目中提取一个例子。但是正如你提到的级联选项:原因可能是我的实体关系缺乏CascadeType规范吗? - Melkor
显示剩余6条评论
2个回答

7

我终于找到了解决我的问题的方法。正如我所说,错误是由于尝试删除其他表仍然依赖的表而引起的。我认为这可能与缺少CascadeType规范有关,但我无法解决它。

然后我发现了这个答案,对我很有用。除了我的data.sql文件(其中插入了所有数据到自动创建的模式中),我现在还有一个drop-tables.sql文件,可以指定正确的DROP语句顺序。该文件在自动模式创建之前执行,因此解决了我的问题。

application.properties:

spring.jpa.properties.javax.persistence.schema-generation.database.action=drop-and-create
spring.jpa.properties.javax.persistence.schema-generation.drop-source=script-then-metadata
spring.jpa.properties.javax.persistence.schema-generation.drop-script-source=drop-tables.sql

2
它对我没用。我找到了一个解决方案https://dev59.com/FlIH5IYBdhLWcg3wfu5c#60012915,它适合我。如果这个方法适合您,请告诉我。 - gtiwari333

-1
您必须使用DirtiesContext注释您的测试类:
@DirtiesContext(methodMode = MethodMode.BEFORE_CLASS)

这将重建测试上下文,并且也会创建/删除您的模式。

请阅读更多相关信息:https://www.baeldung.com/spring-dirtiescontext


1
我认为你的意思是 ClassMode.BEFORE_CLASS,但这并不能解决我的问题。是的,它会触发删除数据库模式,但仍然会抛出链接问题中描述的错误。 - Melkor
在spring-boot 2.2.2中,即使设置replace=none也无济于事。我不知道2.0.4和2.2.2之间发生了什么变化,我想控制它,但我不知道如何做到,并且无法在任何地方找到答案。如果您知道如何在每个测试文件(在我的情况下@DataJpaTest)之后强制Spring重新初始化数据库,即使replace=none已经存在,请帮助我。我对replace=none并不习惯,但是另一件我无法做的事情是强制自动配置的数据源创建模式 :( - Martin Mucha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接