Flyway版本提交前如何在不修改迁移文件的前提下验证数据库状态
可行方案
方案1:使用Flyway原生SQL回调(无需改代码,最简便)
Flyway 内置了按命名规则自动识别的SQL回调机制,无需修改现有迁移文件,只需要在你的迁移SQL根目录下新增名为afterEachMigrate.sql的文件,写入你的校验逻辑即可:
--#SET TERMINATOR @ CALL COMPILE_SCHEMAS()@
afterEachMigrate的触发时机正好满足你的要求:
- 位于单条迁移文件的所有语句执行完成之后
- 位于向
flyway_schema_history插入新版本记录之前 - 和迁移逻辑共用同一个连接、同一个事务,如果校验逻辑抛出异常,整个迁移事务会直接回滚,不会残留脏数据,也不会生成版本记录
方案2:使用代码级回调(适合集成在Java/Scala/Kotlin项目中)
如果你是在项目代码中集成Flyway,可以实现Flyway的Callback接口,重写afterEachMigrate方法,在方法中执行你的重编译校验逻辑:
import org.flywaydb.core.api.callback.Callback; import org.flywaydb.core.api.callback.Context; import org.flywaydb.core.api.callback.Event; public class CompileSchemaCallback implements Callback { @Override public boolean supports(Event event, Context context) { return event == Event.AFTER_EACH_MIGRATE; } @Override public boolean canHandleInTransaction(Event event, Context context) { return true; } @Override public void handle(Event event, Context context) { try (var stmt = context.getConnection().createStatement()) { stmt.execute("CALL COMPILE_SCHEMAS()"); } catch (Exception e) { throw new RuntimeException("存储过程重编译校验失败", e); } } @Override public String getCallbackName() { return "compile-schema-callback"; } }
之后将这个实现类注册到Flyway的配置中即可生效。
触发器方案失效的原因
Flyway 设计上确实是用两个独立连接分别处理迁移执行和版本表操作,目的是保证即使迁移事务回滚,也能将失败记录写入版本表,所以你在版本表上绑定的触发器会在独立的连接中执行,此时主迁移事务还未提交,操作的对象上持有排他锁,自然会触发锁超时,这个逻辑是Flyway的固有设计,没有配置项可以关闭。
内容的提问来源于stack exchange,提问作者Lennart - Slava Ukraini
相关产品推荐
相关产品推荐

