Flyway迁移H2失败求助:Spring Boot测试环境验证异常
解决Spring Boot测试环境Flyway验证失败问题
我之前也碰到过类似的情况,这个错误本质是Flyway检测到H2数据库的flyway_schema_history表中存在版本1的迁移失败记录,而根源大多是迁移脚本只适配了MySQL,在H2数据库上执行出错,或者测试环境的数据库残留了之前的失败历史。下面给你几个可行的解决步骤:
1. 让迁移脚本兼容MySQL和H2
MySQL和H2的SQL语法存在不少差异,比如MySQL的ENGINE=InnoDB、CHARSET=utf8mb4,或者某些函数(比如NOW() vs CURRENT_TIMESTAMP())在H2里不兼容。你可以通过两种方式让脚本跨数据库兼容:
方式一:用数据库专属注释
在脚本中针对不同数据库写专属语法,H2会忽略MySQL的注释,MySQL会忽略H2的注释:
CREATE TABLE IF NOT EXISTS business_table ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP /* MySQL */ ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; /* H2 */ ; );
方式二:用Flyway占位符动态适配
在配置文件中添加数据库类型的占位符:
application-test.properties:spring.flyway.placeholders.db_type=h2application-prod.properties:spring.flyway.placeholders.db_type=mysql
然后在迁移脚本中使用条件判断:
CREATE TABLE IF NOT EXISTS business_table ( id BIGINT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(100) NOT NULL, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ${if db_type='mysql'}ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;${endif} ${if db_type='h2'};${endif} );
2. 清理测试环境的Flyway历史记录
因为之前迁移失败,H2数据库的flyway_schema_history表已经有了失败的记录,Flyway启动时会验证这些记录导致报错。你可以通过以下方式清理:
方式一:使用内存模式H2
把测试环境的H2改成内存模式,这样每次测试都会生成全新的数据库,彻底避免历史记录干扰。修改application-test.properties:
spring.datasource.url=jdbc:h2:mem:my_db;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
方式二:测试前自动清理数据库
利用flyway-spring-test的注解,在测试类上添加@FlywayTest(clean = true),确保每次测试前清理数据库:
@SpringBootTest @ActiveProfiles("test") @FlywayTest(clean = true) public class YourApplicationTests { // 测试方法 }
方式三:临时允许Flyway清理
在application-test.properties中添加:
spring.flyway.clean-disabled=false
注意:生产环境一定要把这个值设为true,避免误删生产数据!
3. 检查测试环境的Flyway配置
确认测试环境的Flyway配置是否正确:
- 确保
spring.flyway.schemas=PUBLIC和H2的默认schema一致; - 如果测试环境之前有手动创建的表,可以开启基线化:
spring.flyway.baseline-on-migrate=true
按照上面的步骤调整后,应该就能解决H2测试环境的Flyway验证失败问题了。
内容的提问来源于stack exchange,提问作者Yasharzb




