背景

产品迭代使用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. JS自制极简日历Demo

    这个日历界面不属于任何插件,纯粹用最基本的JS函数获取到每个位置对应的日期,然后再通过遍历拼接table表单的方式赋值到HTML里面进行展示,日历效果的显示,其中使用到的文件只需要一个Jquery的J ...

  2. Docker下elasticsearch8部署、扩容、基本操作实战(含kibana)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇记录了用docker搭建ElasticS ...

  3. 《Python魔法大冒险》008 石像怪的挑战:运算符之旅

    小鱼和魔法师继续深入魔法森林.不久,他们来到了一个巨大的魔法石圈旁边.石圈中心有一个闪闪发光的魔法水晶,周围则是一些神秘的符号.但令人意外的是,水晶的旁边还有一个巨大的石像怪,它的眼睛散发着红色的光芒 ...

  4. 「codeforces - 1208F」Bits and Pieces

    link. 考虑把原问题写成一个在 \(\left(\log_2 \max v \right) \times n\) 的矩阵里选出三列,我们首先预处理出 \(j \cap q\).具体,我们需要对于每 ...

  5. Go 1.22 中的 For 循环

    原文在这里. 由 David Chase and Russ Cox 发布于2023年9月19日 Go 1.21 版本包含了对 for 循环作用域的预览更改,我们计划在 Go 1.22 中发布此更改,以 ...

  6. DBeaver Ultimate 22.1.0 连接数据库(MySQL+Mongo+Clickhouse)

    前言 继续书接上文 Docker Compose V2 安装常用数据库MySQL+Mongo,部署安装好之后我本来是找了一个web端的在线连接数据库的工具,但是使用过程中并不丝滑,最终还是选择了使用 ...

  7. 解决在VS Code中运行有中文字符的Java代码(第三种方式),出现编码 GBK 的不可映射字符 (0x81)

    写代码时,我们不避免的会使用一些中文注释,这些在其他的语言中没有问题.但是在Java的注释里面如果有中文字符,就会报错.即使文件编码是utf-8也无济于事.是因为使用CMD运行java程序的时候,系统 ...

  8. TIM-有感BLDC转速解析

    TIM-有感BLDC转速解析 1.基本概念解析 霍尔传感器的原理:通电线圈产生的磁场会使得转子所在位置会产生磁场,其中离得最近的霍尔传感器的磁场最强,进而导致最近霍尔传感器会产生最大的电压信号,这个最 ...

  9. 【译】为什么命名“它”为依赖属性(DependencyProperty)

    当我们创建新的类和成员时,我们花费了大量的时间和精力是它们尽可能的好用,好理解,好发现.通常我们会遵循.Net框架设计指南,尤其是会不断地研究这个新类与其他类,未来计划等内容之间的关系. 当命名依赖属 ...

  10. 畅捷通T+任意文件上传(CNVD-2022-60632 )漏洞复现

    一.漏洞描述 022年8月29日和8月30日,畅捷通公司紧急发布安全补丁修复了畅捷通T+软件任意文件上传漏洞.未经身份认证的攻击者利用该漏洞,通过绕过系统鉴权,在特定配置环境下实现任意文件的上传,从而 ...