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

SpringBoot测试环境MySQL报错:inMemoryDatabaseShutdownExecutor创建失败

解决Spring Boot测试环境(MySQL)下的Bean创建异常与Session关闭问题

我之前碰到过类似的坑,结合你的场景来看,这两个错误其实是关联的——核心问题是H2内存数据库的自动关闭Bean在非开发环境(测试用MySQL)被错误触发,同时定时任务的生命周期没和Spring容器同步,导致容器销毁阶段出现冲突。咱们一步步来解决:

一、先搞定inMemoryDatabaseShutdownExecutor创建失败的问题

这个Bean是Spring Boot为H2内存数据库自动配置的销毁钩子,但你的测试环境用的是MySQL,完全不需要它。问题根源是H2依赖在测试环境也被加载了,导致Spring自动配置了这个多余的Bean。

方案1:只在开发环境引入H2依赖

修改你的pom.xml,把H2依赖的作用域限制为开发环境,或者用Maven Profiles来管理:

<!-- 方式1:直接限定scope为开发/测试专用 -->
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>test</scope>
</dependency>

<!-- 方式2:用Maven Profiles精准控制环境依赖 -->
<profiles>
    <profile>
        <id>dev</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <dependencies>
            <dependency>
                <groupId>com.h2database</groupId>
                <artifactId>h2</artifactId>
            </dependency>
        </dependencies>
    </profile>
    <profile>
        <id>test</id>
        <dependencies>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
    </profile>
</profiles>

方案2:在测试环境配置类中禁用H2自动配置

如果不想调整依赖结构,可以在测试环境的配置类上排除H2相关的自动配置:

@Configuration
@Profile("test")
@EnableJpaRepositories(basePackages = "com.calzada.backend.persistence.repositories")
@EntityScan(basePackages = "com.calzada.backend.persistence.domain.backend")
@EnableTransactionManagement
@EnableCaching
@PropertySource("file:///${user.home}/bonanza/application-test.properties")
@PropertySource("file:///${user.home}/bonanza/application-common.properties")
// 排除嵌入式数据库的自动配置,避免H2相关Bean被创建
@EnableAutoConfiguration(exclude = EmbeddedDatabaseAutoConfiguration.class)
public class TestConfig {
    // 测试环境专属配置Bean
}

二、解决定时任务的Session/EntityManager已关闭错误

这个错误是因为定时任务的生命周期比数据源连接池长,容器销毁时先关了数据库连接池,但定时任务还在跑,导致访问已关闭的Session。

方案1:配置定时任务的关闭策略

自定义TaskScheduler,让它在容器销毁时等待任务完成再关闭:

@Configuration
@Profile("test")
public class TestSchedulerConfig {

    @Bean(destroyMethod = "shutdown")
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("test-scheduler-");
        // 容器关闭时等待所有正在执行的任务完成
        scheduler.setWaitForTasksToCompleteOnShutdown(true);
        // 最多等待10秒强制关闭
        scheduler.setAwaitTerminationSeconds(10);
        return scheduler;
    }
}

方案2:在集成测试中手动终止定时任务

如果是在集成测试阶段出现这个问题,可以在测试结束时手动关闭任务调度器:

@SpringBootTest
@ActiveProfiles("test")
public class YourIntegrationTest {

    @Autowired
    private TaskScheduler taskScheduler;

    @AfterAll
    static void cleanUp(@Autowired TaskScheduler taskScheduler) {
        if (taskScheduler instanceof ThreadPoolTaskScheduler) {
            ((ThreadPoolTaskScheduler) taskScheduler).shutdown();
        }
    }
}

最后做个额外检查

  • 确认application-test.properties里的数据源配置完全指向MySQL,没有任何H2相关的配置项;
  • 检查定时任务代码,确保每次执行时都是获取新的EntityManager/Session,不要复用长期持有的实例。

内容的提问来源于stack exchange,提问作者Nunyet Calçada

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 07:39:17