开启Spring延迟初始化后嵌入式H2数据库未初始化问题
解决Spring Boot开启懒加载后H2初始化脚本不执行的问题
基于Spring Boot v2.7.18 + H2 v2.2.220的测试环境,开启spring.main.lazy-initialization=true后,test-schema.sql未执行,导致@Sql注解执行test-data.sql时提示表不存在。
问题根源
全局懒加载开启后,Spring Boot负责执行SQL初始化脚本的核心Bean(DataSourceScriptDatabaseInitializer,Spring Boot 2.5+引入)会被延迟初始化。而测试中的@Sql脚本执行时机(BEFORE_TEST_METHOD)早于该Bean的初始化,导致表还未创建就执行删除/插入操作,抛出表不存在异常。
可行解决方案
1. 精准排除SQL初始化相关Bean的懒加载
之前的排除列表遗漏了关键的DataSourceScriptDatabaseInitializer类,这是执行spring.sql.init配置脚本的核心Bean。修改你的LazyInitializationExcludeFilter,添加该类:
@Bean public static LazyInitializationExcludeFilter integrationLazyInitializationExcludeFilter() { return LazyInitializationExcludeFilter.forBeanTypes( DataSource.class, DataSourceScriptDatabaseInitializer.class, // 核心:负责执行SQL初始化脚本 DataSourceInitializer.class, // 兼容旧版本的初始化Bean H2ConsoleAutoConfiguration.class, EmbeddedDataSourceConfiguration.class, DataSourceAutoConfiguration.class, DatabasePopulator.class, DataSourceHealthContributorAutoConfiguration.class, DataSourcePoolMetadataProvidersConfiguration.class, JdbcTemplateAutoConfiguration.class ); }
2. 在测试类中强制提前初始化Schema
如果不想修改全局排除规则,可以在测试类的@BeforeAll阶段手动执行test-schema.sql,确保表在测试前创建:
import org.springframework.jdbc.datasource.init.ScriptUtils; import org.springframework.core.io.ClassPathResource; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; @SpringBootTest public class MyTests { @Autowired private DataSource dataSource; @BeforeAll void initSchema() { try (Connection conn = dataSource.getConnection()) { ScriptUtils.executeSqlScript(conn, new ClassPathResource("test-schema.sql")); } catch (SQLException e) { throw new RuntimeException("Schema初始化失败", e); } } @Sql(scripts = {"classpath:test-data.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Test void myTest() { // 测试逻辑 } }
3. 调整SQL初始化模式
将spring.sql.init.mode从embedded改为always,确保无论数据源类型如何,初始化脚本都会执行(虽然嵌入式环境下embedded本应生效,但懒加载可能干扰了触发条件):
spring: sql: init: mode: always data-locations: - classpath:test-schema.sql
验证注意事项
- 确保
test-schema.sql文件路径正确,且在测试类的classpath下 - 检查H2数据库URL中的
DB_CLOSE_DELAY=-1配置是否保留,避免数据库提前关闭
内容的提问来源于stack exchange,提问作者nonzaprej
相关产品推荐
相关产品推荐

