背景

产品迭代使用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. 在Windows下用VScode构造shell脚本的IDE

    在linux系统中,大家可以很轻松的开发.调试shell脚本.但是,对于不熟悉linux系统 的小白或者想在Windows下开发shell脚本的人来说,这就有点不友好了.本篇文章就 教大家,在Wind ...

  2. 商品详情api接口的应用方向有哪些?

    ​ 商品详情API接口的应用方向非常广泛,可以应用于以下领域: 电子商务平台:商品详情API接口可以提供商品的基本信息,如名称.描述.价格.图片等,帮助电子商务平台展示和推荐商品.此外,还可以提供商品 ...

  3. 如何通过抖音订单API接口获取订单详情

    要通过抖音订单API接口获取订单详情,您需要进行以下步骤: 1.获取Access Token:使用APP ID和APP Secret调用获取Access Token API接口来获取您的Access ...

  4. PowerDotNet平台化软件架构设计与实现系列(16):财务平台

    不同行业基本都会有自己独特的业务,甚至同行的不同企业之间的业务逻辑也会相差千里,只有最大程度抽象出通用性.标准性和普适性的系统才能够成为平台系统,平台系统开发的成本和难度可想而知. 个人深度参与或独立 ...

  5. Docker Swarm + Harbor + Portainer 打造高可用,高伸缩,集群自动化部署,更新。

    Docker Swarm是Docker官方自带的容器编排工具,Swarm,Compose,Machine合称Docker三剑客.Docker Swarm对于中小型应用来说,还是比较方便,灵活,当然K8 ...

  6. linux查看IP、域名、端口的网络是否相通

    linux查看IP.域名.端口的网络是否相通 1. ping # 检索当前域名对应的IP地址 ping 域名 # 查看IP是否相通 ping IP 2. tlenet # 查看指定IP的端口是否相通, ...

  7. Markdown 包含其他文件静态渲染工具

    1. 前言 在 GitHub 上写文档,很多时候要插入 uml,像 mermaid 这种可以直接在 GitHub/GitLab 中渲染的一般直接写个 code block 进去,但是这样造成一个问题就 ...

  8. 安装OpenStack的yum源

    # yum install https://buildlogs.centos.org/centos/7/cloud/x86_64/openstack-liberty/centos-release-op ...

  9. docker入门加实战—docker数据卷

    docker入门加实战-docker数据卷 容器是隔离环境,容器内程序的文件.配置等都在容器的内部,要读写容器内的文件非常不方便. 因此,容器提供程序的运行环境,但是程序运行产生的数据.程序运行依赖的 ...

  10. jq工具及其常用用法

    近来在工作中处理JSON处理较多,深入研究了一下jq,之前对jq的使用一直停留在JSON数据格式化的层面,实际它的能力远不止于此. 在处理JSON数据时,我们经常需要在命令行中进行过滤.查询和编辑的操 ...