如何让SpringBoot中依赖服务的Flyway迁移启动后自动执行
问题背景
我在user表中新增了time_zone字段,需要为所有存量记录填充该字段值。
字段值需基于同表的postal_code字段,通过OpenCage地理服务转换得到。
我计划编写Flyway迁移实现如下逻辑:
- 逐行读取user表记录,获取
postal_code字段值 - 调用地理服务API,传入
postal_code参数 - 接收接口返回的时区信息
- 将时区值写入对应记录的
time_zone字段
该地理服务是应用内的SpringBoot @Service组件,因此需要在迁移类中通过@Autowired注入该服务。我期望该迁移在应用启动完成后自动执行,而非通过flyway:migrate命令手动触发。
当前实现与问题
我当前的实现如下,存在的问题是迁移无法在应用启动后自动执行:
public class V151__CalculateTimeZoneForExistingUsers extends BaseJavaMigration { @Autowired private GeocodingService geocodingService; public void migrate(Context context) throws Exception { try (Statement select = context.getConnection().createStatement()) { try (ResultSet rows = select.executeQuery("SELECT id, postal_code FROM user")) { while (rows.next()) { long id = rows.getLong(1); String postalCode = rows.getString(2); JOpenCageResult jOpenCageResult = geocodingService.geocode(postalCode); if (jOpenCageResult != null && jOpenCageResult.getAnnotations() != null && jOpenCageResult.getAnnotations().getTimeZone() != null) { String timeZone = jOpenCageResult.getAnnotations().getTimeZone().getName(); try (Statement update = context.getConnection().createStatement()) { update.execute("UPDATE user SET time_zone = '" + timeZone + "' WHERE id=" + id); } } } } } } }
该迁移类存放路径为src\main\java\org\LayerOne\LayerTwo\db\migration\V151__CalculateTimeZoneForExistingUsers.java。
在pom.xml中,Flyway配置如下:
<configuration> <user>username</user> <password>password</password> <url>jdbc:mysql://localhost:3306/myDB</url> <baselineOnMigrate>true</baselineOnMigrate> <baselineVersion>0.0</baselineVersion> <locations> <location>classpath:db/migration, classpath:org/LayerOne/LayerTwo/db/migration</location> </locations> </configuration>
执行flyway:info命令可以看到该迁移已被识别,但应用启动后不会自动运行,需要调整配置让迁移按预期执行。
解决方案
核心问题出在两个配置/实现逻辑上,对应修复即可:
- Flyway路径配置格式错误:你在maven插件配置中用逗号分隔多个路径写在单个
<location>标签内是无效语法,Flyway不会自动拆分逗号分隔的路径值。更关键的是,你只在maven插件中配置了自定义迁移路径,没有同步配置Spring Boot启动时的Flyway自动配置参数,应用启动时Flyway默认只会扫描classpath:db/migration路径,自然识别不到你存放在org/LayerOne/LayerTwo/db/migration下的Java迁移类。
修复方式:- 在Spring Boot配置文件(application.yml/properties)中添加Flyway配置,保证启动时扫描路径正确:
spring: flyway: enabled: true baseline-on-migrate: true baseline-version: 0.0 locations: - classpath:db/migration - classpath:org/LayerOne/LayerTwo/db/migration- 修正pom.xml中maven插件的location配置,每个路径单独声明:
<locations> <location>classpath:db/migration</location> <location>classpath:org/LayerOne/LayerTwo/db/migration</location> </locations> - Java迁移类默认不支持Spring依赖注入:Flyway默认会自己实例化Java迁移类,实例不归Spring容器管理,类上的
@Autowired注解不会生效,就算迁移被扫描到,执行时也会因为geocodingService为null抛空指针。
修复方式:如果使用Flyway 6.2.0及以上版本,直接给迁移类加上@Component注解,把类交给Spring管理,Flyway会自动从Spring上下文获取完成依赖注入的迁移实例执行。如果是更低版本,可以自定义FlywayMigrationStrategy,在应用上下文初始化完成后手动触发迁移,或者通过ApplicationContextAware工具类手动获取对应的Service Bean。 - 额外优化提示:你当前代码中直接拼接SQL字符串存在SQL注入风险,建议替换为
PreparedStatement通过参数占位符设置值,不要直接拼接用户相关字段到SQL语句中。
内容的提问来源于stack exchange,提问作者Snookums
相关产品推荐
相关产品推荐

