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
相关产品推荐
相关产品推荐

