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事件描述,官网文档:
| 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回调钩子的更多相关文章
- ObCallback回调钩子检测
ObCallback回调钩子检测 2013-12-20 Nie.Meining Ring0 在 PatchGuard 的摧残下,通过 ObRegisterCallbacks 函数注册回调钩子已经成了 ...
- JavaScript Callback 回调函数
JavaScript callback回调函数 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这 ...
- v-if和v-show的区别以及callback回调函数的体会
今天总结一下最近一周碰到的一些问题 一.v-if和v-show的区别 v-show用的是css属性中的display="block/none",元素被隐藏了但是节点还在页面中,但是 ...
- js中promise解决callback回调地狱以及使用async+await异步处理的方法
1.callback回调地狱 function ajax(fn) { setTimeout(()=> { console.log('你好') fn() }, 1000) } ajax(() =& ...
- C# Callback 回调实用讲解 [原创]
这个是2011年写的一个技术贴,现在看可能有点过时了,有兴趣的朋友也可以看一下. 一. 描述 在开发winform程序时不会考虑页面刷新问题,只要控制好线程别导致假死就ok了,但是在开发web页面程序 ...
- 关于js的callback回调函数的理解
回调函数的处理逻辑理解:所谓的回调函数处理逻辑,其实就是先将回调函数的代码 冻结(或者理解为闲置),接着将这个回调函数的代码放到回调函数管理器的队列里面. 待回调函数被触发调用的时候,对应的回调函数的 ...
- callback回调函数的理解
callback采用的设计模式是:模板模式,他的设计理念是基于面向对象中的多态的. 我们的程序中走到某个地方他会出现不一样的动作的时候,我们在这儿就使用回调函数.我们利用的就是 多态的原理,我们传递不 ...
- callback 回调函数
把函数a当做一个参数传入函数b <script> Array.prototype.mysort = function(callback){ let s = this; //准备向回调函数里 ...
- callback回调函数-python
链接:http://www.zhihu.com/question/19801131/answer/27459821来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 编程分 ...
- callback回调函数【转】
请给作者点赞--> 原文链接 什么是回调函数? 我们绕点远路来回答这个问题. 编程分为两类:系统编程(system programming)和应用编程(application programmi ...
随机推荐
- 2023-08-20:用go语言写算法。给定一个由'W'、'A'、'S'、'D'四种字符组成的字符串,长度一定是4的倍数, 你可以把任意连续的一段子串,变成'W'、'A'、'S'、'D'组成的随意状
2023-08-20:用go语言写算法.给定一个由'W'.'A'.'S'.'D'四种字符组成的字符串,长度一定是4的倍数, 你可以把任意连续的一段子串,变成'W'.'A'.'S'.'D'组成的随意状态 ...
- 微服务集成seata完成分布式事务,解决数据不一致问题
细心的盆友可能已经发现了,我们的跨行转账并没有保证数据一致性,比如小明扣除了100,但是因为各种问题小红在添加100金额的时候遇到了异常,这个时候数据就出现不一致性 我们可以选择seata来进行分布式 ...
- 如何利用电商API接口来获取商品数据
要利用电商API接口来获取商品数据,我们可以按照以下步骤实现: 确定电商平台和API接口 不同的电商平台提供不同的API接口,因此我们需要确定我们要获取商品数据的电商平台,并选择相应的API接口进行调 ...
- OA管理系统源码
介绍 oa管理系统,只有基本功能,可进行二次开发 软件架构 技术框架:Spring+SpringMVC+Mybatis+BootStrap 数据库:MySQL 服务器:JDK7+Tomcat7 安装教 ...
- HTML一键打包APK工具最新版1.9.1更新(附下载地址)
HMTL网址打包APK,可以把本地HTML项目, Egret游戏,网页游戏,或者网站打包为一个安卓应用APK文件,无需编写任何代码,也无需配置安卓开发环境,支持在最新的安卓设备上安装运行. HTML一 ...
- BZ全景编辑器(KRPano全景可视化编辑器, 无需编写代码, 图形化制作全景漫游)
软件简介 BZ全景编辑器是一款KRPano全景可视化编辑工具,下载安装即可使用,无需拥有任何KRPano代码基础,便可以制作生成精美的全景漫游作品. BZ全景编辑器群:882083973 最新版软件下 ...
- HTML一键打包IPA(苹果IOS应用)工具 网站打包 APP
工具简介 HTML一键打包IPA(苹果应用)工具可以把本地HTML项目或者网站打包为一个苹果应用IPA文件,无需编写任何代码,支持在苹果设备上安装运行. 该软件已经被GDB苹果网页一键打包工具取代,详 ...
- Vue源码学习(七):合并生命周期(混入Vue.Mixin)
好家伙, 1.使用场景 现在来,来想一下,作为一个使用Vue的开发者,假设现在我们要使用created(),我们会如何使用 1.1. .vue文件中使用 <template> < ...
- 一款广受社区好评的 WAF
大家好,我是 Java陈序员,我们有时会搭建一个属于自己的网站,但是自建网站很容易被收到攻击,今天给大家介绍一款简单免费好用的 WAF 网站防护工具. WAF 是 Web Application Fi ...
- Oracle12C登录PDB容器
Oracle12C登录PDB用户,此为12C的新特性 ①首先管理员身份登录 sqlplus / as sysdba;--管理员身份登录 show con_name;--查看此时连接容器 显示:CDB$ ...