You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

集成测试中RestController早于Hibernate建表的解决方法

集成测试中H2数据库表未创建导致RestController调用失败的解决方法

在集成测试场景下使用H2数据库时,RestController会在Hibernate完成数据库Schema创建前被调用,导致测试因表不存在失败(当前ddl-auto配置为update)。需要解决两个问题:

  • 如何确保控制器在数据库完全创建完成后再被使用?
  • Hibernate是否提供可供控制器依赖的Bean?

报错信息

Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "_USER" not found (this database is empty); SQL statement:
select u1_0.id,u1_0.company_id,u1_0.country_id,u1_0.created_at,u1_0.created_by,u1_0.disabled,u1_0.email,u1_0.email_confirmed,u1_0.full_access,u1_0.full_name,u1_0.gender,u1_0.mfa,u1_0.mfa_secret,u1_0.modified_at,u1_0.modified_by,u1_0.notification_email,u1_0.notification_slack_webhook,u1_0.notification_slack_webhook_enabled,u1_0.password,u1_0.phone,u1_0.role,u1_0.temp_mfa_secret from _user u1_0 [42104-220]
  at org.h2.message.DbException.getJdbcSQLException(DbException.java:514) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.message.DbException.getJdbcSQLException(DbException.java:489) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.message.DbException.get(DbException.java:223) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.message.DbException.get(DbException.java:199) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.getTableOrViewNotFoundDbException(Parser.java:8548) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.getTableOrViewNotFoundDbException(Parser.java:8532) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.readTableOrView(Parser.java:8521) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.readTablePrimary(Parser.java:1911) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.readTableReference(Parser.java:2391) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseSelectFromPart(Parser.java:2844) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseSelect(Parser.java:2950) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseQueryPrimary(Parser.java:2834) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseQueryTerm(Parser.java:2690) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseQueryExpressionBody(Parser.java:2669) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseQueryExpressionBodyAndEndOfQuery(Parser.java:2662) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseQueryExpression(Parser.java:2655) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parseQuery(Parser.java:2624) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parsePrepared(Parser.java:732) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parse(Parser.java:697) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.parse(Parser.java:669) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.command.Parser.prepareCommand(Parser.java:577) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.engine.SessionLocal.prepareLocal(SessionLocal.java:634) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.engine.SessionLocal.prepareCommand(SessionLocal.java:557) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1116) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:92) ~[h2-2.2.220.jar:2.2.220]
  at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:288) ~[h2-2.2.220.jar:2.2.220]
  at com.zaxxer.hikari.pool.ProxyConnection.prepareStatement(ProxyConnection.java:327) ~[HikariCP-5.0.1.jar:na]
  at com.zaxxer.hikari.pool.HikariProxyConnection.prepareStatement(HikariProxyConnection.java) ~[HikariCP-5.0.1.jar:na]
  at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$1.doPrepare(StatementPreparerImpl.java:91) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
  at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:177) ~[hibernate-core-6.2.6.Final.jar:6.2.6.Final]
  ... 211 common frames omitted

解决方案

1. 监听Hibernate初始化事件

通过@EventListener监听Hibernate的SessionFactoryInitializedEvent事件,该事件在SessionFactory初始化完成(包含Schema创建)后触发。用CountDownLatch阻塞控制器逻辑,直到事件触发:

import org.hibernate.event.spi.SessionFactoryInitializedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import java.util.concurrent.CountDownLatch;

@Component
public class HibernateStartupListener {
    private final CountDownLatch latch = new CountDownLatch(1);

    @EventListener
    public void onSessionFactoryInitialized(SessionFactoryInitializedEvent event) {
        latch.countDown();
    }

    public void waitForInitialization() throws InterruptedException {
        latch.await();
    }
}

在测试类或控制器初始化时注入该Listener,调用waitForInitialization()确保Schema创建完成后再执行后续逻辑。

2. 使用@DependsOn强制依赖顺序

让RestController依赖Hibernate的核心Bean(如entityManagerFactory或sessionFactory),确保控制器在这些Bean初始化完成后再创建:

@RestController
@DependsOn("entityManagerFactory")
public class UserController {
    // 业务逻辑
}

3. 调整DDL配置(测试环境专用)

将测试环境的spring.jpa.hibernate.ddl-auto设置为create或create-drop,相比update,create会直接创建Schema而非检查更新,能更快完成表创建,避免时序问题:

spring.jpa.hibernate.ddl-auto=create

4. 提前执行数据库初始化脚本

使用Spring的@Sql注解在测试前执行Schema脚本,确保表提前存在:

@SpringBootTest
@Sql(scripts = "/schema.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)
public class UserControllerIntegrationTest {
    // 测试用例
}

其中/schema.sql存放创建表的SQL语句,测试方法执行前会自动运行该脚本。

内容的提问来源于Stack Exchange,提问作者Ahmed Ashour

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 17:57:03