背景

产品迭代使用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事件描述,官网文档

Name Execution
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

SpringBoot实现Flyway的Callback回调钩子的更多相关文章

  1. ObCallback回调钩子检测

    ObCallback回调钩子检测 2013-12-20 Nie.Meining Ring0 在 PatchGuard 的摧残下,通过 ObRegisterCallbacks 函数注册回调钩子已经成了 ...

  2. JavaScript Callback 回调函数

    JavaScript callback回调函数 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这 ...

  3. v-if和v-show的区别以及callback回调函数的体会

    今天总结一下最近一周碰到的一些问题 一.v-if和v-show的区别 v-show用的是css属性中的display="block/none",元素被隐藏了但是节点还在页面中,但是 ...

  4. js中promise解决callback回调地狱以及使用async+await异步处理的方法

    1.callback回调地狱 function ajax(fn) { setTimeout(()=> { console.log('你好') fn() }, 1000) } ajax(() =& ...

  5. C# Callback 回调实用讲解 [原创]

    这个是2011年写的一个技术贴,现在看可能有点过时了,有兴趣的朋友也可以看一下. 一. 描述 在开发winform程序时不会考虑页面刷新问题,只要控制好线程别导致假死就ok了,但是在开发web页面程序 ...

  6. 关于js的callback回调函数的理解

    回调函数的处理逻辑理解:所谓的回调函数处理逻辑,其实就是先将回调函数的代码 冻结(或者理解为闲置),接着将这个回调函数的代码放到回调函数管理器的队列里面. 待回调函数被触发调用的时候,对应的回调函数的 ...

  7. callback回调函数的理解

    callback采用的设计模式是:模板模式,他的设计理念是基于面向对象中的多态的. 我们的程序中走到某个地方他会出现不一样的动作的时候,我们在这儿就使用回调函数.我们利用的就是 多态的原理,我们传递不 ...

  8. callback 回调函数

    把函数a当做一个参数传入函数b <script> Array.prototype.mysort = function(callback){ let s = this; //准备向回调函数里 ...

  9. callback回调函数-python

    链接:http://www.zhihu.com/question/19801131/answer/27459821来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 编程分 ...

  10. callback回调函数【转】

    请给作者点赞--> 原文链接 什么是回调函数? 我们绕点远路来回答这个问题. 编程分为两类:系统编程(system programming)和应用编程(application programmi ...

随机推荐

  1. 【pandas小技巧】--数据转置

    所谓数据转置,就是是将原始数据表格沿着对角线翻折,使原来的行变成新的列,原来的列变成新的行,从而更方便地进行数据分析和处理. pandas中DataFrame的转置非常简单,每个DataFrame对象 ...

  2. [ABC212E] Safety Journey

    2023-01-08 题目 题目传送门 翻译 翻译 难度&重要性(1~10):2 题目来源 AtCoder 题目算法 dp 解题思路 首先就想到暴力 dp,用三个循环枚举:\(1.\) 时间, ...

  3. Azure Data Factory(六)数据集类型为Dataverse的Link测试

    一,引言 之前有讲过 Azure Data Factory 的 Copy Data 的操作,演示了将 Blob Storage1 的数据通过 Azure Data Factory 复制到 Blob S ...

  4. 深入理解Linux内核——内存管理(2)

    提要:本系列文章主要参考MIT 6.828课程以及两本书籍<深入理解Linux内核> <深入Linux内核架构>对Linux内核内容进行总结. 内存管理的实现覆盖了多个领域: ...

  5. 使用 OpenTelemetry 构建 .NET 应用可观测性(2):OpenTelemetry 项目简介

    前世今生 OpenTracing OpenTracing 项目启动于 2016 年,旨在提供一套分布式追踪标准,以便开发人员可以更轻松地实现分布式追踪. OpenTracing 定义了一套 Traci ...

  6. pygame 入门实例教程 1 - 复古方块赛车游戏

    作者自我介绍:大爽歌, b站小UP主 ,直播编程+红警三 ,python1对1辅导老师 . 本教程步骤明确,过程清晰简明,最终代码量250行上下,适合学习pygame的新手. 项目代码已上传到我的gi ...

  7. Fetch设置超时请求

    promise + fetch + AbortController + setTimeOut 这是一段正常的fetch请求 fetch('www.baidu.com',{}) .then(res=&g ...

  8. burpsuite验证码爆破后台夺权

    目录 准备工作 爆破 同时爆破用户名密码和验证码 筛查爆破结果的成功输出 创建新用户远程桌面连接 准备工作 安装python 安装muggle_ocr库 运行xp_CAPTCHA服务端 burpsui ...

  9. 使用Eclipse生成CHM帮助文档(图解)

    使用Eclipse生成CHM帮助文档(图解) 博客分类: System Operate javadoc生成chm文档java生成api帮助文档api帮助文档生成工具 Eclipse JavaDoc和j ...

  10. 教育法学第九章单元测试MOOC

    第九章单元测试 返回 本次得分为:100.00/100.00, 本次测试的提交时间为:2020-09-06, 如果你认为本次测试成绩不理想,你可以选择 再做一次 . 1 单选(5分) 作为教师最基本的 ...