SQL版本管理工具技术选型

需求点分析

  1. 是否支持多类数据库以及脚本区分?
  2. 如何撤销变更?
  3. 版本是如何管理的?
  4. 费用问题?是否开源?开源协议是什么?

flyway VS liquibase VS bytebase

其中bytebase我很早就放弃了,所以对比结果不全,重点还是放在了flyway和liquibase中

flyway liquibase bytebase
版本&价格 - 🆓 Community 社区版
- 💰 Teams 团队版 $597/每人每年
- 💰💰 Enterprise企业版 价格未知❓

https://www.red-gate.com/products/flyway/
- 🆓 Open Source 开源版
- 💰 Liquebase Pro 专业版 价格未知❓


https://www.liquibase.com/pricing
- 🆓 ommunity 社区版
- 💰 Pro 专业版 $100/每数据库实例每月
- 💰💰 enterprise 企业版本 价格未知❓

https://www.bytebase.com/pricing/
功能清单 - 🆓 Flyway API/CLI 核心功能
- 🆓 Flyway Desktop GUI Flyway桌面图形用户界面
- 🆓 6 basic commands: Migrate, Clean, Info, Validate, Baseline and Repair 6 个基本命令:迁移、清理、信息、验证、基线和修复
- 🆓 Support for current DB versions 支持当前数据库版本
- 🆓 Community support 社区支持
- 💰 Dry run 试运行
- 💰 Undo migration scripts 撤消迁移脚本
- 💰 Cherry pick
- 💰 Object-level versioning 对象级版本控制(仅限SQL Server、Oracle、PostgreSQL和MySQL)
- 💰 Built-in Git client 内置 Git 客户端
- 💰 Support for older DB versions 支持旧数据库版本
- 💰 Access to technical support 获得技术支持
- 💰💰 Change reports 变更报告(仅限SQL Server、Oracle、PostgreSQL和MySQL)
- 💰💰 Drift detection 漂移检测(仅限SQL Server、Oracle、PostgreSQL和MySQL)
- 💰💰 Create custom code analysis rules 创建自定义代码分析规则
- 💰💰 Create regular expression rules 创建正则表达式规则
- 💰💰 Migration script auto-generation 迁移脚本自动生成(仅限SQL Server、Oracle、PostgreSQL和MySQL)
- 💰💰 Schema comparison 架构比较(仅限SQL Server、Oracle、PostgreSQL和MySQL)
- 💰💰 Static data versioning 静态数据版本控制(仅限SQL Server、Oracle)
- 💰💰 Data comparison 数据对比(仅限SQL Server、Oracle)
- 💰💰 Support for extended set of DB versions 支持扩展的数据库版本集
- 🆓 Native SQL Dialect
- 🆓 Change format:SQL, XML, YAML, JSON
- 🆓 Change creation & management:CLI or 3rd party automation tools
- 🆓 Smart database updates 自动确定并部署所有尚未部署的变更
- 🆓 Preconditions 前提条件
- 🆓 Set labels and contexts 设置标签和上下文
- 🆓 Change preview / dry run 更改预览/试运行
- 🆓 Rollback 回滚
- 🆓 Change generation:根据数据库生成更改集
- 🆓 Snapshot 快照:生成架构快照
- 🆓 Diff 差异:生成两个数据库之间的比较(或差异)以检测意外错误
- 🆓 Installation 安装:通过 CLI、API、Spring、Docker、Maven、Gradle、Ant、Debian/Ubuntu 和 Red Hat/CentOS 下载并安装 Liquibase
- 🆓 Deployment 部署:手动或通过自动化流程部署更改
- 🆓 Standard JDBC 标准 JDBC:通过 CLI 或属性文件传递凭据和连接属性
- 🆓 Command line & properties file 命令行和属性文件:使用单个文件、CLI 或 Java 系统属性配置和指定详细信息,例如数据库连接和类路径信息
- 🆓 社区支持
- 💰 Targeted database updates 对数据库执行特定更改
- 💰 Advanced rollback
- 💰 Native executors 原生执行器:使用本机执行器 SQLPlus、PSQL、SQLCMD 和 MongoSH 运行高级更改
- 💰 Stored logic 存储过程:在选定平台(包括 Oracle SQL
Plus)上使用存储过程代码
- 💰 Advanced change generation:高级变更生成:根据数据库生成更改集(包括存储过程)
- 💰 Advanced snapshot 高级快照:生成架构快照,包括具有高级功能的存储过程
- 💰 Remote files 远程文件:运行在 Amazon S3 上远程托管的 Liquibase 文件
- 💰 Advanced diff & drift detection 先进的差异和漂移检测:
- 💰 Policy Checks 政策检查:在部署之前根据一组规则按需或自动检查数据库代码的质量和安全性
- 💰 Flows 流程:编排数据库更改工作流程和最佳实践,以实现即时和一致的部署
- 💰 Structured Logging 结构化日志记录:结构化和可定制的日志记录可增强 BI 工具和仪表板的可观察性和安全性
- 💰 Operations reports 运营报告:用于运营洞察和错误检测的便携式报告
- 💰 Secrets management 保密管理:与 AWS Secrets Manager 和 HashiCorp Vault 的内置集成
- 💰 高级支持
- 💰 入门培训
- 💰 技术客服经理:由技术客服经理协调的个性化服务和帐户审查
- 🆓 社区支持
- 🆓 最多20个团队成员
- 🆓 最多10个数据库实例
- 🆓 SQL lint, GitOps
- 💰 电子邮件支持
- 💰 无限用户
- 💰 最多 20 个数据库实例
- 💰 人工审核、计划上线
- 💰💰 SLA 支持
- 💰💰 无限数据库实例
- 💰💰 SSO、SCIM、2FA、审核日志
- 💰💰 自定义审批、动态数据脱敏
- 💰💰 通过SSH隧道连接数据库
文件类型 - SQL - SQL
- JSON/YML/XML
- SQL
版本控制 通过文件名控制排序,V/U/R0001__ADD_NEW_COLUMN.sql
其中:
- V表示正常版本迭代
- U表示撤销(社区版不支持撤销
- R表示可重复

双下划线__后面的描述内容则属于用于说明,便于理解。
Flyway: Naming Patterns Matter
通过维护统一的changset文件来管理,详见版本控制之liquibase 高级版支持审批流
历史记录 建表:flyway_schema_history 建表:
- DATABASECHANGELOG
- DATABASECHANGELOGLOCK
执行顺序 文件名,V开头的序号 通过changelog和changeset来管理,如果有小数点需要使用双引号引用,详见官方博客中Attributes模块中对于id的描述
回滚 - U开头的SQL文件
- 社区版不支持撤销
针对SQL文件,是通过制定rollback语句;
针对JSON/YML/XML文件,对部分类型,比如createTable会有默认实现,部分需要自己定义,类似于使用SQL文件维护
不同环境部署不同的脚本 有两个参数用于解决这个问题,分别是contextlabels
简单来说context主要是为了区分研发环境/测试环境/生产环境,
labels则是用于区分不同的业务。详见liquibase补充说明之context vs labels
数据库快照 通过CLI完成:liquibase snapshot --snapshot-format=json --output-file=Vx.x.x.json,会得到一个json格式的快照文件,是针对整个数据库的结构、索引等信息的快照,不包含数据

版本控制

flyway

通过文件名控制排序,V/U/R0001__ADD_NEW_COLUMN.sql
其中:

  • V表示正常版本迭代
  • U表示撤销(社区版不支持撤销
  • R表示可重复

双下划线__后面的描述内容则属于用于说明,便于理解。
Flyway: Naming Patterns Matter

liquibase

官方博客:https://docs.liquibase.com/concepts/changelogs/changeset.html

liquibase是通过维护changelog和changeset来统一管理版本的。格式可以是SQL、JSON、YAML、XML。详见liquibase补充说明之changelog与changeset

从我自己的理解来看选择SQL会更合适一些。理由如下:

  1. SQL中不需要再多去了解liquibase自己定义的建表,加字段的语法,学习成本低
  2. SQL中也有完整的功能,而且针对不同的数据库写不同的脚本也更简单

liquibase补充说明

changelog与changeset

changelog是changeset的集合。

changeset是一个维护性的配置文件,支持用SQL、JSON、YAML、XML等格式维护。通过一些固定的标签或者语法去维护变更。
推荐使用SQL作为维护格式。因为JSON、YAML、XML等格式有学习成本,需要按liquibase自己定义的标签去操作数据库。
可以看看示例,会更容易理解

SQL

1
2
--changeset nvoxland:1 
create table company ( id int primary key, address varchar(255) );

JSON

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"changeSet": {
"id": "1",
"author": "nvoxland",
"changes": [
{
"createTable": {
"tableName": "company",
"columns": [
{
"column": {
"name": "address"
}
}
]
}
}
]
}
}

YAML

1
2
3
4
5
6
7
8
9
10
databaseChangeLog:
- changeSet:
id: 1
author: nvoxland
changes:
- createTable:
tableName: company
columns:
- column:
name: address

XML

1
2
3
4
5
<changeSet  id="1"  author="nvoxland">
<createTable tableName="company">
<column name="address" type="varchar(255)"/>
</createTable>
</changeSet>

context vs labels

在维护changset时,有两个关键字,分别是contextlabels。简单来说context主要是为了区分研发环境/测试环境/生产环境,而labels则是用于区分不同的业务。

在官方博客中明确提到你可以按自己的理解去使用,但使用之后需要注意你的changeset对于单个环境来说可能是复杂,冗余的,可能会带来维护上的成本。

同时博客中也提到你可以定义不同的changset文件来解决,不一定非要使用contextlabels

官方博客:https://www.liquibase.com/blog/contexts-vs-labels

Whether you should use contexts or labels comes down to whether the changeset author/developer or the Liquibase executor (deployment manager) best understands and/or needs the most control over which changesets to execute.
是否应该使用上下文或标签取决于变更集作者/开发人员或 Liquibase 执行者(部署经理)是否最好地理解和/或需要对要执行的变更集进行最大程度的控制。

  • If you want to describe/tag the environment and have the changeset authors decide which environments they should run in, use contexts.
    如果您想描述/标记环境并让变更集作者决定他们应该在哪些环境中运行,请使用上下文。
  • If you want to describe/tag the changesets and have the deployment manager decide which changesets to run? If so, use labels.
    如果您想描述/标记变更集并让部署管理器决定运行哪些变更集?如果是这样,请使用标签。
    Remember: you can use both.
    请记住:您可以同时使用两者。
    While there are many use cases for contexts and labels, they should be used judiciously. The reason you use Liquibase in the first place is to ensure consistent deployment logic from development through production; Contexts and labels are inherently breaking that consistency, allowing some statements to run on some environments and not in others.
    虽然上下文和标签有很多用例,但应谨慎使用它们。使用 Liquibase 的首要原因是确保从开发到生产的部署逻辑一致;上下文和标签本质上破坏了这种一致性,允许某些语句在某些环境中运行,而不能在其他环境中运行。
    When you do find yourself looking to use labels or contexts first ask “is there a better way to do this?”
    当您确实发现自己想要使用标签或上下文时,首先问“有更好的方法吗?”
  • If you are using contexts for feature selection, perhaps independent changelogs per feature would work better?
    如果您使用上下文进行功能选择,也许每个功能独立的变更日志会更好?
  • If you are using labels for managing changes by version, perhaps a different version control or artifact management would work better?
    如果您使用标签来按版本管理更改,也许不同的版本控制或工件管理会更好?
    The answer will often be “labels or contexts work best”, but always be aware of any conditional logic you are adding to your changelogs.
    答案通常是“标签或上下文效果最好”,但请始终注意您添加到变更日志中的任何条件逻辑。

为什么要使用context来区别研发/测试/生产环境?

我们可能会有一些数据需要做调整,但每个环境中的数据值有差异,这种情况下使用context就满不错的。

举个例子,在研发环境中,我们需要初始化一些测试数据,比如配置是否校验短信验证,研发环境中为了节约短信资源肯定是不会真的验证的,但是生产环境是一定要验证的,那么这里研发环境和生产环境就明显区分了,那么这里使用context就能很好的解决这个问题。

为什么要使用labels区分业务?

其实我觉得我自己的这个描述不是特别合理,更多的是官方博客中提到的管理器问题。对应我们常说的CI/CD中的CD流程。我们可能线上有多套环境,每套环境针对的业务有所差异,对于环境A中的功能和脚本,环境B中其实并不需要,那么B中就可以不去执行。这时候用labels就比较合理。

当然如果只是不需要这种简单场景,我还是建议都执行比较好,过于碎片化很难在测试阶段中复现问题。但如果是一些数据矫正的SQL,那么可能就不得不使用labels拆分了

总结

flyway、liquibase、bytebase三者在目前免费提供的功能中都是不完美的状态,都属于是加钱才能变强,但总体来说liquibase是三者中功能最全的。

优缺点总结(仅针对各自免费版):

  1. flyway不支持撤销变更;liquibase支持,但需要研发单独维护rollback语句,测试同学也会增加工作量,同时如果研发没有及时维护和验证rollback语句,且此时已被执行后也需要手动处理;
  2. liquibase不支持多文件管理,include/includeAll被定义为专业版功能;flyway本身就是通过多文件管理;
  3. bytebase单纯就是一个SQL执行器

无论使用哪款工具,都需要注意:

  1. 不建议管理索引创建等较为耗时的操作,可能会导致应用无法启动;
  2. 不建议修改已发布的语句,会发生冲突;

需求点分析

问题1:是否支持多类数据库以及脚本区分?

可以肯定的是flyway和liquibase都具备,可以指定不同的数据库执行不同的SQL。
对于bytebase来说,由于免费版没有审批流程,更像是一个sql执行器,所以这里我就没有深度研究对比了。

问题2:如何撤销变更?

  • liquibase通过定义为changeset文件中维护--rollback标签以实现
  • flyway免费版则不支持。

我之前有深度使用过flyway,flyway在执行比较多的历史变更时可能会出现栈溢出,且由于flyway免费版没有undo机制,一旦测试过程进行中,因为一些bug不得不需要重新调整SQL时,就会带来灾难级的问题和繁琐的解决过程。

liquibase在undo上是免费提供的,但也需要研发投入精力单独维护,同时对于测试来说新增了一个脚本undo的测试用例,工作量会有所增加。

问题3:版本是如何管理的?

  • flyway是通过文件名以V开头后接序号;
  • liquibase是通过维护changelog中的changeset实现;

问题4:费用问题?是否开源?开源协议是什么?

详见表格

参考资料

对比类

  1. baeldung Liquibase vs Flyway
  2. oschina 数据库/SQL版本管理工具选型指北
  3. liquibase liquibase-vs-flyway
  4. csdn liquibase介绍,liquibase这一篇就够了

Liquibase

  1. liquibase 最佳实践
  2. cnblogs Spring Boot使用Liquibase最佳实践
  3. Spring Docs Use a higher-level database migration tool
  4. Liquibase 配置文件说明
  5. Liquibase SQL formate配置文件说明

Flyway

  1. Spring Docs Use a higher-level database migration tool