一个基于差异同步数据库结构的工具 - Skeema

请添加图片描述

本文是 GO 三方库推荐的第 5 篇,继续介绍数据库 schema 同步工具,我前面已经写了两篇这个主题的文章。系列查看:Golang 三方库。

今天,推荐是的一个基于差异实现数据库 schema 迁移的工具库 - skeema,同样由 Go 实现。

背景

我的上家公司时,有名架构师开发了一个类似于 skeema 的工具,也是基于差异同步表结构的,区别在于那个工具使用的 yaml 声明表结构定义的。我当时就想在市面上找一个类似的工具,但没找到。好在通过 ChatGPT,搜索效率提升很多,不过也是一步步的引导才让我找到这个工具。

概述

Skeema 是基于差异同步数据库 schema,这让我们只要表结构的终态就行。 还有,skeema 支持在不同环境间同步数据库 schema。

Skeema 支持 linter 识别 SQL 语句,方便我们将其集成到 CICD 中提升 Schema 质量。还有,它默认是禁用了一些不安全的数据库操作,如删表删字段等操作。

如果要说缺点,它现在只支持 MySQL 和 MariaDB。

安装

Skeema 的安装过程直接了当。如果你使用的是 MacOS,可以通过Homebrew来安装:

brew install skeema/tap/skeema

或是也可通过 go get 安装,但 Go 的版本要求在 v1.21+。

$ go install github.com/skeema/skeema@v1.11.1

对于其他平台,可以从Skeema的GitHub页面下载二进制文件,并按照文档指引进行安装。

使用

Skeema 的使用可概括为 5 个核心步骤:

  • 通过 skeema init 下载初始建表 SQL;
  • 基于初始 SQL 按需求修改文件;
  • 使用 skeema diff 在提交前确认差异;
  • 使用 skeema lint 检查 SQL 是否满足 linter 规则;
  • 使用 skeema push 推送 SQL,变更数据库 schema。

我将按这个步骤展开介绍。

初始化

首先,通过 skeema init 实现基于现有的数据库结构初始我们的目录,生成初始建表语句。

示例如下:

$ skeema init -h 127.0.0.1 -uroot -ppassword --schema blog -d .

--schema 用于指定目标库名称,如果没有指定,会生成实例下所有库的建表 SQL。而 -d/--dir 用于指定目标目录。

现在,回车确认和输入密码执行命令。

由于我这个 blog 数据库没有任何内容,只会在当前目录下生成一个 .skeema 文件,它也就是 skeema 的配置文件。

打开它,查看内容如下:

default-character-set=utf8mb4
default-collation=utf8mb4_0900_ai_ci
generator=skeema:1.11.1-community
schema=blog

[production]
flavor=mysql:8.3
host=127.0.0.1
port=3306
user=root

如果想在接下来执行其他命令时,省略掉 -p 输入密码的步骤,可加上密码配置。

...
port=3306
user=root
password=password

这一步会在指定目录下创建数据库架构的本地表示。

而如果我没有指定 --schema 选项,将会把数据库中所有库表初始化到我的目录下。

$ ls -a
.skeema  article  blog  core

生成差异

现在尝试做一些变更,article 库下的有一个名为 comments 的表,它的建表语句如下所示:

CREATE TABLE `comments` (
  `id` int NOT NULL,
  `post_id` int NOT NULL,
  `author_name` int NOT NULL,
  `comment` text NOT NULL,
  `update_at` timestamp NULL DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

我将在其中添加一个 author_id 字段,修改的建表语句如下所示。

CREATE TABLE `comments` (
   ...
  `author_id` varchar(255) NOT NULL,
   ...
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

现在,让我们使用 skeema diff 查看差异。

$ skeema diff
2024-02-22 18:53:09 [INFO]  Generating diff of 127.0.0.1:3306 article vs
                            /Users/jian.xue/demo/databasemigration/skeema2-demo/article/*.sql
-- instance: 127.0.0.1:3306
USE `article`;
ALTER TABLE `comments` ADD COLUMN `author_id` int NOT NULL AFTER `post_id`;
2024-02-22 18:53:09 [INFO]  127.0.0.1:3306 article: diff complete
...

从上得到在 comments 新增 author_id,要执行的 SQL 是:

ALTER TABLE `comments` ADD COLUMN `author_id` int NOT NULL AFTER `post_id`;

这个命令成功输出了当前目录下建表语句的结构与数据库中表结构的差异。通过查看这个差异,即可确认是否是我们预期的 SQL。

但问题是,和代码审阅一样,如果所有问题都是依靠人来检查,则很难最大限度降低问题发生的可能性。在代码审阅的流程中,通过会加入 linter 工具,SQL 同样也可以有这流程。好在,skeema 也提供了类似这样 lint 能力。

Linter

Skeema 内置了一个linter 工具,检查表结构定义语句,防止一些常规的问题。

运行命令:

skeema lint

Skeema 提供有大量规则选项,有兴趣去看下它的官方文档:Option Reference。

如下是我列举一些常见的大家感兴趣的规则:

# 设置默认的字符集,推荐使用 utf8mb4 以支持全字符集
default-character-set=utf8mb4

# 确保所有表和列使用推荐的字符集
lint-charset=error
allow-charset=utf8mb4

# 确保所有表使用推荐的存储引擎,如 InnoDB
lint-engine=error
allow-engine=innodb

# 推荐使用合适的数据类型作为主键,通常是整数类型
lint-pk-type=error
allow-pk-type=int,bigint

# 根据团队策略对外键使用进行限制,如果避免使用外键以提升性能
lint-has-fk=warning

# 确保自增列使用合适的数据类型,避免未来可能的整数溢出
lint-auto-inc=error

# 避免重复或冗余的索引
lint-dupe-index=error

# 如果应用策略限制了存储过程和函数的使用
lint-has-routine=warning

# 确保表使用一致的命名规则,如全部小写
lint-name-case=error

现在尝试对 comments 做一些变更,测试能检查出主键类型错误和索引问题。

CREATE TABLE `comments` (
  `id` CHAR(32) NOT NULL,
  `post_id` int NOT NULL,
  `author_name` int NOT NULL,
  `comment` text NOT NULL,
  `update_at` timestamp NULL DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_post_id` (`post_id`),
  KEY `idx_post_id_duplicate` (`post_id`), -- 重复的索引,与 idx_post_id 完全相同
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

执行如下命令:

$ skeema lint
2024-02-23 15:55:55 [INFO]  Linting /xxxx/skeema-demo
2024-02-23 15:55:55 [INFO]  Linting /xxxx/skeema-demo/article
2024-02-23 15:55:55 [INFO]  Wrote
                            /xxxx/skeema-demo/article/comments.sql
                            (500 bytes)
2024-02-23 15:55:55 [ERROR] /xxxx/skeema-demo/article/comments.sql:2:
                            Column id of table `comments` is using data type char(32), which
                            is not configured to be permitted in a primary key. The following
                            data types are listed in option allow-pk-type: int.
2024-02-23 15:55:55 [ERROR] /xxxx/skeema-demo/article/comments.sql:10:
                            Indexes idx_post_id_duplicate and idx_post_id of table `comments`
                            are functionally identical.
                            One of them should be dropped. Redundant indexes waste disk space,
                            and harm write performance.
2024-02-23 15:55:55 [ERROR] Found 2 errors

提示索引类型错误:

Column id of table `comments` is using data type char(32), which
is not configured to be permitted in a primary key. The following
data types are listed in option allow-pk-type: int.

提示重复索引错误:

Indexes idx_post_id_duplicate and idx_post_id of table `comments`
are functionally identical.
One of them should be dropped. Redundant indexes waste disk space,
and harm write performance.

skeema 有社区版和商业版,有一些能力检查规则要商业版支持。

应用变更

skeema 使用的最后一步是应用这些变更,使用 skeema push 命令即可将更新应用到数据库。这个没啥可介绍的了。

多环境配置

skeema 支持多环境的不同配置,上面的配置实例中其实已经能看出了。其中有一个 production 段。

default-character-set=utf8mb4
default-collation=utf8mb4_0900_ai_ci
generator=skeema:1.11.1-community
schema=blog

[production]
flavor=mysql:8.3
host=127.0.0.1
port=3306
user=root

如我增加一个 dev 环境,命令如下:

$ skeema add-environment dev --host 127.0.0.1 -uroot -ppassword

配置如下:

[dev]
flavor=mysql:8.3
host=127.0.0.1
port=3306
user=root
password=password

使用时,只要在命令后加上环境名称即可,如:

$ skeema push dev

还有,在不同环境下使用不同 lint 规则,这也是可以的。

安全操作

还有一定要说明,记住 skeema 默认是不允许一些非安全的操作,如删表、列其它如修改导致数据截断啥的等等操作。这也是很符合实际场景的。不然,因为某操作,导致删掉一些数据就完犊子了。

如果有非安全操作的需求,如在开发环境,不喜欢保留一些开发期间临时创建的表,配置 allow-unsafe=true 即可。

[dev]
...
allow-unsafe=true

总结

Skeema 作为一个基于差异同步数据库 schema 的工具,简单强大。它简化了数据库 schema 的管理。使得我们无论是开发新功能时管理架构变更,还是在多环境中同步数据库架构,Skeema都能提供有效的支持,都不再复杂。

最后,如果你和我曾经一样,为不同环境间的数据库表结构管理同步感到头痛,试试 Skeema,或许你会喜欢这种方式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/434124.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS-卡片事件能力说明

卡片事件能力说明 ArkTS卡片中提供了postCardAction()接口用于卡片内部和提供方应用间的交互,当前支持router、message和call三种类型的事件,仅在卡片中可以调用。 接口定义:postCardAction(component: Object, action: Object): void 接口…

CleanMyMac X软件2024全面的测评,包括其功能、性能、易用性和安全性

作为软件评价专家,我对CleanMyMac X进行了全面的评估,包括其功能、性能、易用性和安全性等方面。以下是我的评价和建议: 首先,从功能方面来看,CleanMyMac X提供了丰富多样的清理和优化功能。它不仅能够智能扫描和清理…

网工内推 | 华为成都研究所,24届应届生人才储备计划

华为成都研究所 招聘岗位 网络工程师(2024应届) 岗位要求 24届的学员 本科公办院校 英语4/6级 有HCIP优先 工作地点 成都 私信小编,回复【内推】,获取内推名额申请资格~ 想获取更多『 思科 | 华为 | 红帽 认证真题 』、『 网…

RISC-V架构的不可屏蔽中断(NMI:Non-Maskable Interrupt)介绍

1、RISC-V特权架构官方文档描述 NMI是处理器核心的一种特殊输入信号,经常用于表示系统级别的紧急错误(比如:外部硬件错误等)。在遇到NMI后,处理器应该立即中止当前程序的执行,并处理NMI错误在RISC-V架构中&…

Python自动化测试利器selenium详解

Selenium是一种常用的Web自动化测试工具,支持多种编程语言和多种浏览器,可以模拟用户的交互行为,自动化地执行测试用例和生成测试报告。Selenium基于浏览器驱动实现,结合多种定位元素的方法,可以实现各种复杂的Web应用…

Android开发者值得深入思考的几个问题,看完必懂

程序员的劫 最近,又被程序员年龄的事情刷屏了。37岁被公司优化,找工作几个月都没有很好的归属,所谓的小公司还看不上。等等类似的话题变成了程序员的吐槽固定标题,无论是程序员,还是其他行业人员,都可以就…

HTML入门

1. HTML基础 1.1 什么是HTML HTML是超文本标记语言。 超文本:比文本更强大,可以包含图片,链接等。 标记语言:由标签构成的语言。所以我们学习HTML就是在学习标签。 1.2 认识HTML标签 HTML代码都是由标签组成的,例…

2024希亦、追觅、石头、添可洗地机哪款最好用?一文教会你快速挑选洗地机

对许多人来说,全屋清洁可能是件让人望而却步的任务,因为它需要花费大量的体力和时间。但是,随着科技的发展,我们可以找到一些能够简化这个过程的神器,比如洗地机。有了洗地机,我们可以轻松地完成扫地、拖地…

Linux学习-函数指针和指针函数

目录 字符串是char *型,代表的是字符串的第一个元素的地址 指针函数: 函数指针: 字符串是char *型,代表的是字符串的第一个元素的地址 指针函数: int *Fun(int a, int b); 是函数,函数的返回值类型是…

FlyClient SPV client轻量化

这篇文章主要是为了构建一种轻客户端的算法。 如果使用SPV 的方式验证交易,每个client上面需要存储非常多的header。使用 proofs of proof-of-work 的方式,使得请客户端仅仅下载少量的区块头就能验证这一条链的安全性,然后再对包含交易的区块…

【刷题】双指针入门

双指针入门 双指针283.移动零1089. 复写零202. 快乐数11. 盛最多水的容器Thanks♪(・ω・)ノ谢谢阅读!!!下一篇文章见!!! 双指针 双指针是非常经典的算法,包括但…

【python】对角线遍历

python系列文章目录 【python】基于cv2提取图片上的文本内容 【python】简单作图 【python】数组字符串等实用 【python】sort与sorted排序使用 【python】对角线遍历 python系列文章目录说明1.分析2.注意事项2.1 遍历2.2 区间2.3 顺序 3.代码实现 说明 给你一个大小为 m x n…

kerberos学习系列一:原理

1、简介 Kerberos 一词来源于古希腊神话中的 Cerberus —— 守护地狱之门的三头犬。 Kerberos 是一种基于加密 Ticket 的身份认证协议。Kerberos 主要由三个部分组成:Key Distribution Center (即KDC)、Client 和 Service。 优势: 密码无需进行网络传…

网站建设:承诺网站打开速度,这个要求合理吗?

很多甲方都要求网站的打开速度,这个要求合理吗?其实说合理也合理,说不合理也不合理。 承诺打开速度的合理性的一面 要求网站打开速度是一个合理的要求。网站的打开速度对于用户体验和网站的成功至关重要。以下是一些原因说明为什么网站打开速…

Python实现选择排序算法

Python实现选择排序算法 以下是使用Python实现选择排序算法的示例代码&#xff1a; def selection_sort(arr):n len(arr)for i in range(n):min_index i# 找到未排序部分的最小元素的索引for j in range(i 1, n):if arr[j] < arr[min_index]:min_index j# 将最小元素与…

【Python】新手入门(7):变量的数据类型转换

【Python】新手入门&#xff08;7&#xff09;&#xff1a;变量的数据类型转换 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1…

Locust中wait_time中匿名函数使用方法浅析

前言 翻出之前做个压测项&#xff0c;看到locust中对等待时间的实现方式感到好奇&#xff0c;于是总结下来。 源代码实现 def between(min_wait, max_wait):"""Returns a function that will return a random number between min_wait and max_wait.Example:…

【Linux网络】再谈 “协议“

目录 再谈 "协议" 结构化数据的传输 序列化和反序列化 网络版计算器 封装套接字操作 服务端代码 服务进程执行例程 启动网络版服务端 协议定制 客户端代码 代码测试 使用JSON进行序列化与反序列化 我们程序员写的一个个解决我们实际问题&#xff0c;满…

最强照片AI无损放大工具

使用人工智能的能力来放大图像&#xff0c;同时为惊人的结果添加自然的细节。 使用深度学习技术&#xff0c;A.I.GigaPixEL可以放大图像并填满其他调整大小的产品所遗漏的细节。 下载地址&#xff1a;最强照片AI无损放大工具.zip

LeetCode-第201题-数字范围按位与

1.题目描述 给你两个整数 left 和 right &#xff0c;表示区间 [left, right] &#xff0c;返回此区间内所有数字 按位与 的结果&#xff08;包含 left 、right 端点&#xff09;。 2.样例描述 3.思路描述 方法一&#xff1a;按位与&#xff0c;求两端数字二进制的公共前缀&…