@Sql 注解可在 JUnit 5 中按测试方法粒度执行 SQL 脚本初始化 H2 内存数据库数据,但需配合正确事务配置(如 BEFORE_COMMIT 阶段)、禁用冲突的 spring.sql.init.mode、确保脚本路径正确及语法兼容 ANSI SQL。

JUnit 5 中的 @Sql 注解可以配合 H2 内存数据库,在每个测试方法执行前自动执行 SQL 脚本初始化数据,但需注意几个关键点才能真正生效——它本身不创建表结构,只执行 DML 或 DDL;必须搭配正确的事务配置和数据源环境。
确保 H2 数据库已正确配置为测试专用内存库
在 src/test/resources/application-test.yml(或 application-test.properties)中明确配置 H2 为内存模式,并启用 SQL 初始化支持:
spring:
datasource:
url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
driver-class-name: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
path: /h2-console
sql:
init:
mode: always # 确保每次启动都执行 schema.sql/data.sql(可选)
schema: classpath:schema-h2.sql
data: classpath:data-h2.sql
⚠️ 注意:@Sql 和 spring.sql.init.* 是两套机制。前者按测试方法粒度控制,后者按应用上下文粒度控制。若只想对特定测试用 @Sql,建议关闭 spring.sql.init.mode(设为 never),避免干扰。
使用 @Sql 在测试方法或类上声明初始化脚本
@Sql 支持指定 SQL 文件路径(classpath 或文件系统)、执行时机(默认 BEFORE_TEST_METHOD)、错误处理策略等。常用写法如下:
立即学习“Java免费学习笔记(深入)”;
- 单个脚本,方法前执行:
@Sql("/sql/init_user.sql") - 多个脚本,按顺序执行:
@Sql({"/sql/clear.sql", "/sql/insert_users.sql"}) - 指定执行阶段与异常忽略:
@Sql(scripts = "/sql/test-data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, config = @SqlConfig(errorMode = SqlConfig.ErrorMode.CONTINUE_ON_ERROR))
SQL 文件放在 src/test/resources/sql/ 下,内容示例(init_user.sql):
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
INSERT INTO user (id, name, email) VALUES (1, 'Alice', 'alice@example.com'); INSERT INTO user (id, name, email) VALUES (2, 'Bob', 'bob@example.com');
必须启用事务管理并合理控制回滚行为
H2 内存库默认每个连接独占一个数据库实例,但 Spring Test 默认开启事务并在测试结束后回滚——这会导致 @Sql 插入的数据在测试方法中“看不见”,除非显式提交或禁用回滚。
解决方式有两种:
-
推荐:保持事务 + 使用 @Sql 的 BEFORE_COMMIT 模式
@Sql(scripts = "/sql/init.sql", executionPhase = Sql.ExecutionPhase.BEFORE_COMMIT)
这样 SQL 在事务提交前执行,数据对当前测试方法可见,且仍享受自动回滚带来的隔离性。 -
替代:禁用事务(仅限简单场景)
@Transactional(propagation = Propagation.NOT_SUPPORTED)或直接去掉@Transactional(前提是你的测试类没被@TransactionalTest等全局注解包裹)
⚠️ 若使用 Spring Boot 2.4+,还需确认已添加依赖:testImplementation 'org.springframework.boot:spring-boot-starter-test'(内含 JUnit 5 和 spring-test)
验证脚本能被正确加载和执行
常见失败原因包括:
- 脚本路径错误(如漏掉
/开头,或文件不在 classpath)→ 启动时抛Cannot find script - H2 不支持某些 MySQL/PostgreSQL 语法(如
IF NOT EXISTS、反引号)→ 改用双引号或标准 ANSI SQL - 脚本含多条语句但未用分号分隔 → H2 默认不支持批量执行,需设置
;DB_CLOSE_DELAY=-1并在@SqlConfig中启用separator = ";" - 表不存在就插入数据 → 先用
@Sql执行建表语句,或确保 schema 已由 Flyway/Liquibase 或schema.sql提前创建
调试技巧:打开 H2 控制台(http://localhost:8080/h2-console),连接 jdbc:h2:mem:testdb,手动查表确认初始化是否成功。

















