zoukankan      html  css  js  c++  java
  • SpringBoot实现Flyway的Callback回调钩子

    背景

    产品迭代使用CI/CD升级过程中,需要对不同发布环境的不同产品版本进行数据库迭代升级,我们在中间某次产品迭代时加入了Flyway中间件以实现数据库结构的自动化升级。

    需求

    由于是迭代过程中加入的Flyway,而不是一开始就使用,所以Flyway的版本表和版本记录数据在已经发布过的环境中是不存在的,而且每个环境的产品版本也不同,数据库结构迭代升级首先需要确定当前产品的版本,再执行相应的升级脚本。所以我们需要在发布环境升级时,在Flyway执行之前先根据数据库现状写入版本表和版本记录数据,才能让Flyway正常执行迭代升级脚本。

    Flyway Hooks/Callback

    查阅官方文档知道Flyway有个Hooks,官网文档,文档详细描述如下:

    Building upon that are the Java-based Callbacks when you need more power or flexibility in a Callback than SQL can offer you.

    They can be created by implementing the Callback interface:

    public class MyNotifierCallback implements Callback {
        
        // Ensures that this callback handles both events
        @Override
        public boolean supports(Event event, Context context) {
            return event.equals(Event.AFTER_MIGRATE) || event.equals(Event.AFTER_MIGRATE_ERROR);
        }
        
        // Not relevant if we don't interact with the database
        @Override
        public boolean canHandleInTransaction(Event event, Context context) {
            return true;
        }
        
        // Send a notification when either event happens.
        @Override
        public void handle(Event event, Context context) {
            String notification = event.equals(Event.AFTER_MIGRATE) ? "Success" : "Failed";
            // ... Notification logic ...
            notificationService.send(notification);
        }
    
        String getCallbackName() {
            return "MyNotifier";
        }
    }

    In order to be picked up by Flyway, Java-based Callbacks must implement the Callback interface. Flyway will automatically scan for and load all callbacks found in the db/callback package. Additional callback classes or scan locations can be specified by the flyway.callbacks configuration property.

    SpringBoot实现

    根据官方文档描述,需要实现Callback并配置flyway.callbacks参数,但是在springboot配置文件中并没有找到关于spring.flyway.callbacks或者flyway.callbacks的配置项

    查看了下源码找到了原因,callbacks属性被定义为了final,所以配置文件中不能设置callbacks配置项,关键代码截图如下:

    public class Flyway implements FlywayConfiguration {
    
        private final List<FlywayCallback> callbacks;
    
        public void setCallbacks(FlywayCallback... callbacks) {
            this.callbacks.clear();
            this.callbacks.addAll(Arrays.asList(callbacks));
        }
    
    }

    有个callbacks的set方法,可以尝试用spring注入的方式配置,实现代码如下:

    import lombok.SneakyThrows;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.commons.collections.CollectionUtils;
    import org.flywaydb.core.api.MigrationInfo;
    import org.flywaydb.core.api.callback.FlywayCallback;
    import org.springframework.context.annotation.Configuration;
    
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Flyway迭代升级SQL脚本钩子
     * 主要作用:
     * 1、初始化VERSION表
     * 2、写入当前迭代版本号,根据数据库中是否存在数据表判断
     */
    @Slf4j
    @Configuration
    public class InitFlywayCallback implements FlywayCallback {
        @Override
        public void beforeClean(Connection connection) {
    
        }
    
        @Override
        public void afterClean(Connection connection) {
    
        }
    
        @Override
        public void beforeMigrate(Connection connection) {
    
        }
    
        @Override
        public void afterMigrate(Connection connection) {
    
        }
    
        @Override
        public void beforeUndo(Connection connection) {
    
        }
    
        @Override
        public void beforeEachUndo(Connection connection, MigrationInfo migrationInfo) {
    
        }
    
        @Override
        public void afterEachUndo(Connection connection, MigrationInfo migrationInfo) {
    
        }
    
        @Override
        public void afterUndo(Connection connection) {
    
        }
    
        @Override
        public void beforeEachMigrate(Connection connection, MigrationInfo migrationInfo) {
    
        }
    
        @Override
        public void afterEachMigrate(Connection connection, MigrationInfo migrationInfo) {
    
        }
    
        @SneakyThrows
        @Override
        public void beforeValidate(Connection connection) {
            log.info("Flyway执行拦截");
        }
    
        @Override
        public void afterValidate(Connection connection) {
    
        }
    
        @Override
        public void beforeBaseline(Connection connection) {
    
        }
    
        @Override
        public void afterBaseline(Connection connection) {
    
        }
    
        @Override
        public void beforeRepair(Connection connection) {
    
        }
    
        @Override
        public void afterRepair(Connection connection) {
    
        }
    
        @Override
        public void beforeInfo(Connection connection) {
    
        }
    
        @Override
        public void afterInfo(Connection connection) {
    
        }
    }

    项目启动打印结果如下:

    2020-12-23 09:42:53.025 dassets 13092 [--] [ INFO] [org.flywaydb.core.internal.util.VersionPrinter.info:44] [           main] [Flyway Community Edition 5.0.7 by Boxfuse] 
    2020-12-23 09:43:03.461 dassets 13092 [--] [ INFO] [org.flywaydb.core.internal.database.DatabaseFactory.info:44] [           main] [Database: jdbc:mysql://10.101.6.105:3306/user (MySQL 5.7)] 
    2020-12-23 09:43:03.675 dassets 13092 [--] [ INFO] [com.cestc.dassets.interceptor.InitFlywayCallback.beforeValidate:76] [           main] [Flyway执行拦截] 

    至此,callback执行成功!

    最后附一个Flyway的Callback事件描述,官网文档

    NameExecution
    beforeMigrate Before Migrate runs
    beforeRepeatables Before all repeatable migrations during Migrate
    beforeEachMigrate Before every single migration during Migrate
    beforeEachMigrateStatement Flyway Teams  Before every single statement of a migration during Migrate
    afterEachMigrateStatement Flyway Teams  After every single successful statement of a migration during Migrate
    afterEachMigrateStatementError Flyway Teams  After every single failed statement of a migration during Migrate
    afterEachMigrate After every single successful migration during Migrate
    afterEachMigrateError After every single failed migration during Migrate
    afterMigrate After successful Migrate runs
    afterVersioned After all versioned migrations during Migrate
    afterMigrateError After failed Migrate runs
    beforeUndo Flyway Teams  Before Undo runs
    beforeEachUndo Flyway Teams  Before every single migration during Undo
    beforeEachUndoStatement Flyway Teams  Before every single statement of a migration during Undo
    afterEachUndoStatement Flyway Teams  After every single successful statement of a migration during Undo
    afterEachUndoStatementError Flyway Teams  After every single failed statement of a migration during Undo
    afterEachUndo Flyway Teams  After every single successful migration during Undo
    afterEachUndoError Flyway Teams  After every single failed migration during Undo
    afterUndo Flyway Teams  After successful Undo runs
    afterUndoError Flyway Teams  After failed Undo runs
    beforeClean Before Clean runs
    afterClean After successful Clean runs
    afterCleanError After failed Clean runs
    beforeInfo Before Info runs
    afterInfo After successful Info runs
    afterInfoError After failed Info runs
    beforeValidate Before Validate runs
    afterValidate After successful Validate runs
    afterValidateError After failed Validate runs
    beforeBaseline Before Baseline runs
    afterBaseline After successful Baseline runs
    afterBaselineError After failed Baseline runs
    beforeRepair Before Repair runs
    afterRepair After successful Repair runs
    afterRepairError After failed Repair runs
  • 相关阅读:
    MySQL_创建数据库和表
    MySQL注释的3中方法
    子查询概念和分类
    弱网测试如何进行
    Fiddler_ 移动端抓包配置IOS&Android,Fiddler获取APP端的流量
    Fiddler_HTTPS 如何抓包和浏览器设置
    Fiddler_弱网测试
    Three.js 游戏操作案例
    flex 教程
    JS知识
  • 原文地址:https://www.cnblogs.com/changxy-codest/p/14176849.html
Copyright © 2011-2022 走看看