我编写了带有@SpringBootTest 注释的集成测试。为了运行测试,我将数据从测试资源中的 data.sql 插入到 H2 数据库。
我有一种情况,第一次测试成功运行,多次后,我有一个错误,它告诉我,H2 无法在表中插入数据,因为找不到该表。每次下一次启动测试时,都会出现不同的原始错误。在同一个日志中,我看到在异常发生之前创建了这个表并且其他插入操作成功执行。我看到我的 5 个测试中有 4 个是绿色的,一个是红色的。它可以在不同的时间进行不同的测试。
IDE 的重启使测试再次成功运行 3-4 次。之后,错误返回。
我尝试在我的测试类和测试方法中使用@DirtiesContext(),但它并没有解决问题。
我猜测问题的根源可能是我初始化数据库的方式。对于这两个数据库,我都使用一个 data.sql 文件的引用。我没能找到一种方法将它们分成不同的 *.sql 文件。
第二个猜测是在创建表之前开始插入数据库。我现在通过将所有插入移动到测试代码中来检查这个理论。但是我不确定它是否会有所帮助,因为我播种记录表是在插入开始之前创建的。
我在每次测试运行前都使用“mvn clean”。
我将非常感谢您在解决此问题方面的建议。
我的实体:
@Entity
@Table(name = "entity1", schema = "schema1")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SomeEntityClass extends GenericEntity<Long> { ...}
@MappedSuperclass
public abstract class GenericEntity<ID extends Serializable> implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
protected ID id;
//getter, setter
}
在我的 data.sql 文件中初始化如下所示:
create schema if not exists schema1;
create schema if not exists schema2;
drop table if exists schema1.table1;
create table schema1.table1
(....structure of the table...)
drop table if exists schema2.table2;
create table schema2.table2
(....structure of the table...)
INSERT INTO schema1.table1
(...)
VALUES (...)
... many insertions
INSERT INTO schema2.table2
(...)
VALUES (...)
... many insertions
这是application.properties中的H2配置,在test/resources中:
# The first database
spring.datasource.url=jdbc:h2:mem:database01;INIT=RUNSCRIPT FROM 'src/test/resources/data.sql'
spring.datasource.username=user1
spring.datasource.password=abc
spring.datasource.driver-class-name=org.h2.Driver
spring.jpa.generate-ddl=true
# The second database
spring.datasource.security.url=\
jdbc:h2:mem:dbo_security_db:database02;INIT=RUNSCRIPT FROM 'src/test/resources/data.sql'
spring.datasource.security.username=user1
spring.datasource.security.password=abc
spring.datasource.security.driver-class-name=org.h2.Driver
spring.jpa.hibernate.ddl-auto=update
spring.jpa.properties.hibernate.format_sql=true
错误日志:
08-09-2021 09:00:08.729 DEBUG [o.s.jdbc.datasource.init.ScriptUtils] - 0 returned as update count for SQL: create table schema1.table1( ….)
08-09-2021 09:00:08.730 DEBUG [o.s.jdbc.datasource.init.ScriptUtils] - 1 returned as update count for SQL: INSERT INTO schema1.table1(...) VALUES ()
///...other insertions into this table performed well
08-09-2021 09:00:08.735 WARN [o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext] - Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Invocation of init method failed; nested exception is org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #36 of URL [file:/home/nikiforov-java/Documents/.../target/test-classes/data.sql]: INSERT INTO schema1.table1(...) VALUES (...); nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "TABLE1" not found; SQL statement: ...
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
08-09-2021 09:00:08.782 ERROR [o.s.boot.SpringApplication] - Application run failed
将此属性添加到
application.properties
:
spring.jpa.defer-datasource-initialization=true
根据Spring Boot 2.5 RELEASE notes:
默认情况下,
脚本现在在 Hibernate 初始化之前运行。这使基于脚本的基本初始化行为与 Flyway 和 Liquibase 的行为保持一致。如果要使用data.sql
填充 Hibernate 创建的模式,请将data.sql
设置为spring.jpa.defer-datasource-initialization
.true
添加后:
spring.jpa.defer-datasource-initialization=true
到你的 application.properties 文件,如果你仍然有相同的:
"Exception "org.h2.jdbc.JdbcSQLSyntaxErrorException:Table "NAME" not found
例外,
仔细检查实体中的所有列名。
确保您没有使用保留关键字,如果使用了,请使用以下方法添加别名:
@Column(name = "<YOUR NOT RESERVED KEYWORD COLUMN NAME>")