背景

产品迭代使用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. 文心一言 VS 讯飞星火 VS chatgpt (78)-- 算法导论7.4 2题

    二.如果用go语言,证明:在最好情况下,快速排序的运行时间为 Ω(nlgn). 文心一言: 在最好情况下,快速排序的运行时间为Ω(nlgn)的证明如下: 快速排序是一种分治算法,它将一个数组分成两个子 ...

  2. LeetCode 周赛上分之旅 #43 计算机科学本质上是数学吗?

    ️ 本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 和 BaguTree Pro 知识星球提问. 学习数据结构与算法的关键在于掌握问题背后的算法思维框架,你的思考越 ...

  3. QA|selenium打开浏览器后没有执行后面的代码(get请求)|UI自动化测试

    Q:selenium打开浏览器后没有执行后面的代码(get请求) 代码如图: 原因:webdriver_path应该给的是chromedriver.exe的路径,而不是chrome.exe的路径,写错 ...

  4. Xshell7 / Xftp7 永久免费,官网直连下载地址

    主要目的是让大家随时随地从官网下载Xshell和Xftp免费版(个人/家庭/学校免费) 最新变动:官方目前仅提供最新版以及上一个版本的软件下载!其他版本不提供下载 免费版5版本(最后一个版本,无任何限 ...

  5. PYQT5学习(13):QMidArea同时显示多个窗口,创建多个独立的窗口

    QMidArea  参考文章:https://blog.csdn.net/jia666666/article/details/81670569 一种同时显示多个窗口的方法,创建多个独立的窗口,这些独立 ...

  6. Solution Set -「CF 1520」

    「CF 1520A」Do Not Be Distracted! Link. 模拟. #include<bits/stdc++.h> char now; char get_char(){ch ...

  7. Springboot+Mybatisplus+ClickHouse集成

    核心依赖引入 <dependency> <groupId>ru.yandex.clickhouse</groupId> <artifactId>clic ...

  8. Vue2系列(lqz)——Vue介绍

    文章目录 Vue入门 零:前端目前形势 前端的发展史 一:Vue介绍 和 基本使用 1.Vue介绍 渐进式框架 网站 2.Vue特点 易用 灵活 高效 3.M-V-VM思想 ① MVVM介绍 ② MV ...

  9. fmpeg 多张图片转视频,视频转gif,截取视频,截取视频里的帧

    ffmpeg 多张图片转视频,视频转gif,截取视频,截取视频里的帧 月色下的独轮车 于 2017-06-20 17:32:01 发布 6250 收藏 3文章标签: ffmpeg版权 android学 ...

  10. 高可用mongodb集群(分片+副本):用户权限配置

    目录 ■ 创建副本集认证的key文件 ■ 修改配置文件指定keyfile ■ 重新启动节点 ■ 创建帐号和认证 ■ 用管理员帐号可查看整体的分片情况 ■ 用普通帐号访问数据 ■ 客户端连接多个mong ...