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

news2025/1/27 12:40:20

请添加图片描述

本文是 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,或许你会喜欢这种方式。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker-compose Install Dockge

Dockge Dockge 是一个精美的、易于使用的、反应式的自托管 docker compose.yaml 面向堆栈的管理器。 主要特性: 通过Web页面管理compose.yaml文件。 创建/编辑/启动/停止/重新启动/删除容器。更新Docker镜像。交互式Web终端。响应式设计,实时更新进度(Pull/Up/Down)和Web…

#include<ros/ros.h>头文件报错

快捷键 ctrl shift B 调用编译,选择:catkin_make:build)(要先在vscode上添加扩展:ros) 可以点击配置设置为默认,修改.vscode/tasks.json 文件 修改.vscode/tasks.json 文件,否则ros.h头文件会报错 内容修改为以下内…

代码学习记录13

随想录日记part13 t i m e : time: time: 2024.03.06 主要内容:今天的主要内容是二叉树的第二部分哦,主要有层序遍历;翻转二叉树;对称二叉树。 102.二叉树的层序遍历226.翻转二叉树101. 对称二叉…

Java精品项目--第6期基于SpringBoot的茶叶商城的设计分析与实现

项目技术栈 SpringBootMavenMySQLJAVAMybatis-PLusVue.js(非前后端分离)Element-UI(非前后端分离)… 表截图 项目截图

分布式事务(SeataClient)

问题场景 元数据 库存 100订单记录为空下单操作 @AutowiredRestTemplate restTemplate;/*** 下单** @return*/@Transactional // 开启事务 异常后触发数据库回滚操作@Overridepublic Order create(Order order) {// 插入订单orderMapper.insert(order);// 扣减库存 MultiValu…

Python调用edge-tts实现在线文字转语音

edge-tts是一个 Python 模块,允许通过Python代码或命令的方式使用 Microsoft Edge 的在线文本转语音服务。 项目源码 GitHub - rany2/edge-tts: Use Microsoft Edges online text-to-speech service from Python WITHOUT needing Microsoft Edge or Windows or an…

Intel RealSense D435环境搭建之安装pyrealsense2

ERROR: Could not find a version that satisfies the requirement pyrealsense2 (from versions: none) pip install pyrealsense2 -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com 方法一:升级pip python -m pip install --upgrade pip 方…

Scrapy与分布式开发(3):Scrapy核心组件与运行机制

Scrapy核心组件与运行机制 引言 这一章开始讲解Scrapy核心组件的功能与作用,通过流程图了解整体的运行机制,然后了解它的安装与项目创建,为后续实战做好准备。 Scrapy定义 Scrapy是一个为了爬取网站数据、提取结构性数据而编写的应用框架…

java-新手笔记(类篇)-暂时总结

类定义 用于存储的方法的结构体容器,可以封装多个方法 当在ideal编程器中的工程中创建类文件的同时,就会创建一个公共类, 当我们在新建一个公共类的时候,会出现报错,其要求公共类必须同类文件名一致 同一文件编写新类的时候,不要加public修饰词 调用类…

基于串流技术的p2p共享桌面共享方案

研究远控有一定时间了,但真正落地运用的不多,所以也不太上心,平时也只是自己diy玩玩,远程共享看看电视剧。 最近生成式ai大火,直接带动了gpu应用的相关场景,相关场景,但gpu卡又贵,对…

EXCEL计算时间差(单位毫秒)

公式 VALUE(MID(TEXT(C4,"h:mm:ss.000"),10,7))VALUE(MID(TEXT(C4,"h:mm:ss.000"),6,4))*1000

八、西瓜书——特征选择与稀疏学习

1.子集搜索与评价 对于1个学习任务来说,给定属性集,其中有些属性可能很关键、很有用,另一些属性则可能没什么用,我们将属性称为“特征”(feature),对当前学习任务有用的属性称为“相关特征”(relevant feature)、没什么用的属性称为“无关特征”(irrelev…

Xilinx 7系列FPGA配置(ug470)

Xilinx 7系列FPGA配置(ug470) 配置模式串行配置模式接口从-连接方式主-连接方式串行菊花链(非同时配置)串行配置(同时配置)时序 主SPI配置模式SPIx1/x2 连接图SPIx1模式时序SPIx4 连接图SPI操作指令操作fla…

【工作记录】Threejs学习笔记-引入OrbitControls

前言 前一篇文章我们介绍了three.js中的基础概念,并给出了展示整体流程的一个简单示例, 本文我们继续研究。 问题 我们在很多3d效果图上都能看到鼠标移动或者缩进实现旋转或者放大缩小的效果,这个在three.js中是通过OrbitControls这个组件…

计网面试题整理上

1. 计算机网络的各层协议及作用? 计算机网络体系可以大致分为一下三种,OSI七层模型、TCP/IP四层模型和五层模型。 OSI七层模型:大而全,但是比较复杂、而且是先有了理论模型,没有实际应用。TCP/IP四层模型&#xff1a…

应急响应实战笔记03权限维持篇(6)

第6篇:三大渗透测试框架权限维持技术 0x00 前言 在渗透测试中,有三个非常经典的渗透测试框架----Metasploit、Empire、Cobalt Strike。 那么,通过漏洞获取到目标主机权限后,如何利用框架获得持久性权限呢? 0x01 MS…

【递归搜索回溯专栏】专题一递归:快速幂

本专栏内容为:递归,搜索与回溯算法专栏。 通过本专栏的深入学习,你可以了解并掌握算法。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:递归搜索回溯专栏 🚚代码仓库:小小unicorn的代…

折线图 温度变化曲线图

代码详情介绍 导入必要的库: matplotlib.pyplot:用于绘图。 matplotlib.font_manager:用于设置中文字体。 datetime:用于处理日期和时间。 random:用于生成随机数。 numpy:用于生成arange函数的刻度。 设置…

递推与递归DFS

;例题引入: 在跳楼梯问题中,我们假设每次可以跳1级或2级。如果我们想跳到第N级台阶,那么我们的最后一次跳跃只能是1级或2级。 如果我们最后一次跳1级,那么我们必须先跳到第N-1级台阶。由于跳到第N-1级台阶有f(N-1)种方…

【web安全】实战 批量横扫springboot命令执行漏洞

天命:这次目标批量横扫,但是没完全成功,也没完全失败 步骤1:磨刀准备 这次先针对漏洞来寻找目标,所以寻找这种 springboot 的目标 利用CVE漏洞,进行命令执行攻击 先找靶场训练一波,叠加反弹sh…