「Go开源」goose:深入学习数据库版本管理工具

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: 「Go开源」goose:深入学习数据库版本管理工具

goose是一个用go语言编写的数据库版本管理的命令行工具。其github地址如下:https://github.com/pressly/goose


什么是数据库版本管理?


数据库版本管理,其实就是对数据表结构的演进的管理。比如,我们有一个用户表user,如下:


create table if not exists `user` (
  id int auto_increcement comment '主键',
  name varchar(255) NOT NULL DEFAULT '' COMMENT '用户姓名',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB charset='utf-8' COMMENT='用户表';


过了一段时间,需要在该表中增加一个字段address:


alter table `user` add column address varchar(255) NOT NULL DEFAULT '' COMMENT '用户地址';


又过了一段时间,又需要创建一个用户好友表user_friends:


CREATE TABLE if not exists `user_friends` (
  id int auto_increcement comment '主键',
  user_id int NOT NULL DEFAULT 0 COMMENT '用户ID',
  friend_id int NOT NULL DEFAULT 0 COMMENT '好友用户ID',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB charset='utf-8' COMMENT='用户好友表'


你看,上面这些就是对数据库结构的演进。但在演化的过程中,就有可能造成许多问题。比如在多种环境下(生产、测试、预发布环境)数据结构没保持一致问题。数据库的变更没有统一的文档管理等一些列问题。


接下来我们来看看goose是如何管理数据库的演进的。


goose工具详解


安装


goose是一个使用golang语言编写的命令行工作。我们可以在go代码中引入,也可以通过安装在电脑上直接使用。

安装在$GOPATH/bin目录下:


$ go install github.com/pressly/goose/v3/cmd/goose@latest


在Mac下使用brew安装:


brew install goose


使用


安装完成后,使用goose命令即可对数据库进行管理了。goose命令的使用格式如下:


goose [OPTIONS] DRIVER DBSTRING COMMAND


  • DRIVER:指的是数据库驱动器类型。比如goose工具支持以下数据库:postgres、mysql、sqlite3、mssql、redshift、tidb、clickhouse、vertica。
  • DBSTRING:指的是具体数据库的配置。当指定了数据库类型后,就需要指定特定的数据库配置。比如数据库的地址、用户名、密码以及使用哪个数据库等。如下是当使用mysql数据库时的配置:


user:password@/dbname?parseTime=true


  • COMMAND:goose支持的子命令。指明具体要对数据库做的具体动作。goose工具支持如下子命令:


up                   Migrate the DB to the most recent version available
    up-by-one            Migrate the DB up by 1
    up-to VERSION        Migrate the DB to a specific VERSION
    down                 Roll back the version by 1
    down-to VERSION      Roll back to a specific VERSION
    redo                 Re-run the latest migration
    reset                Roll back all migrations
    status               Dump the migration status for the current DB
    version              Print the current version of the database
    create NAME [sql|go] Creates new migration file with the current timestamp
    fix                  Apply sequential ordering to migrations
    validate             Check migration files without running them


以下是对不同数据库的示例:


goose sqlite3 ./foo.db status
    goose sqlite3 ./foo.db create init sql
    goose sqlite3 ./foo.db create add_some_column sql
    goose sqlite3 ./foo.db create fetch_user_data go
    goose sqlite3 ./foo.db up
    goose postgres "user=postgres password=postgres dbname=postgres sslmode=disable" status
    goose mysql "user:password@/dbname?parseTime=true" status
    goose redshift "postgres://user:password@qwerty.us-east-1.redshift.amazonaws.com:5439/db" status
    goose tidb "user:password@/dbname?parseTime=true" status
    goose mssql "sqlserver://user:password@dbname:1433?database=master" status
    goose clickhouse "tcp://127.0.0.1:9000" status
    goose vertica "vertica://user:password@localhost:5433/dbname?connection_load_balance=1" status


看到上述示例,我们知道了使用的数据库类型、数据库的连接地址以及对数据库要做的具体动作。但这个动作要执行什么呢,是不是还少了具体的数据库的定义语句呢?


其实,在上面的命令中还隐含着一个选项就是dir:指定数据库的DDL文件的目录。默认是在当前目录下读取sql文件。


所以,goose的作用即使将指定目录下的sql文件 按指定的子命令进行执行


goose的工作原理


goose的工作原理实际上就是维护了一个有规则版本号的sql文件。在sql文件中通过标记sql语句是升级还是回退来来告知goose如何执行。goose本质上就是两个子命令:升级操作(goose Up)和回退操作(goose Down)。其他的reset子命令和redo子命令都是对升级和回退操作的组合。


下面是升级和回退操作的流程图:

a7022cc24d73e2b0bbbd08c2a83e46ec.png



image.png


24cc0a63509160a81ffc1b3d5f0350f6.png

image.png


goose子命令详解


通过goose的子命令就可以对sql文件进行管理。下面我们详细介绍下goose的各个子命令的含义以及执行的动作。


create


该命令是创建一个sql的迁移文件。如下:


goose mysql "user:password@/dbname?parseTime=true" create add_some_column sql


运行该命令后,就会在当前目录下生成一个sql文件:20231011222931_add_some_column.sql


create命令后的add_some_column就是文件名,sql就是要生成的文件类型。在生成的文件中我们看到文件名前缀中还有一个日期的前缀,这个是命令自动生成的,用来标识文件的版本。这个版本号在up和down命令的时候会非常有用,稍后详细介绍。


生成了sql文件后,就可以在该文件中添加数据表的定义内容了。首先我们看下该sql文件的格式:


-- +goose Up
-- +goose StatementBegin
SELECT 'up SQL query';
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
SELECT 'down SQL query';
-- +goose StatementEnd


在该文件中,我们看到有两部分内容:


  • 类似 -- +goose Up这样的指令:这个指令告诉goose工具,接下来的内容是要在up子命令下执行的。同理,-- +goose Down指令告诉goose工具,其接下来的内容是在down命令下执行的。
  • sql语句:类型SELECT或CREATE等这样的sql,是要具体执行的内容。


基于上述sql模版文件,我们就可以编写自己的数据库的DDL语言了。示例如下:


-- +goose Up
CREATE TABLE users (
    id int NOT NULL PRIMARY KEY,
    username text,
    name text,
    surname text
);
INSERT INTO users VALUES
(0, 'root', '', ''),
(1, 'vojtechvitek', 'Vojtech', 'Vitek');
-- +goose Down
DROP TABLE users;

up


up子命令是从--dir指定的目录下(默认是当前目录)读取sql文件,然后执行sql文件中的 -- +goose Up下的具体的sql语句。同时,goose还会在数据库中生成一个goose_db_version表,该表里记录了执行过的sql文件。如下:


CREATE TABLE `goose_db_version` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `version_id` bigint(20) NOT NULL,
  `is_applied` tinyint(1) NOT NULL,
  `tstamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;


该表里的version_id字段,就是在sql文件的日期。is_applied字段是指该文件是否已执行。


当重复运行up命令时,首先会检查goose_db_version表中最近成功运行的版本,然后再从dir目录下找到该版本的下一个版本的sql文件并执行。这样就避免了之前运行过的sql文件被重复执行。


b8f6a38c84ca9e374ae804bc2a5dc093.png


image.png


up-to


up-to子命令后面必须要跟一个VERSION参数,即指定具体的sql的版本。该命令会根据指定的版本号,从--dir指定的目录下查找对应的sql文件来执行。VERSION指定的版本就是sql文件名前面的数字部分。


down命令


down子命令是对up子命令的回退操作。即从--dir指定的目录中读取sql文件,然后读取sql文件中的标识为-- +goose Down指令的内容。


这里需要注意的是,在sql文件中,-- +goose Down的内容必须是和文件中的 -- +goose Up内容配对出现的,即有向前执行的内容,才会有对应的回退的内容。


down-to


down-to子命令后面也必须跟一个VERSION版本号,标识回退到对应的版本。即从--dir指定的目录中读取特定版本的sql文件中的down的部分。


redo


redo子命令是将最近执行的一个版本先回退,再重新执行该版本。即先从goose_db_version表中查找中最近执行过的一个版本的sql文件,然后执行该文件的回退操作,再执行up操作。


例如,我们刚执行过sql文件 00001_create_users_table.sql,其内容:


-- +goose Up
CREATE TABLE users (
    id int NOT NULL PRIMARY KEY,
    username text,
    name text,
    surname text
);
INSERT INTO users VALUES
(0, 'root', '', ''),
(1, 'vojtechvitek', 'Vojtech', 'Vitek');
-- +goose Down
DROP TABLE users;


如果执行redo操作,则是先执行该文件中的goose Down部分,再执行该文件中的 goose Up部分的内容。


reset


reset子命令是重置操作,即将所有sql文件中的goose Down的部分重新执行一遍。


总结


本文介绍了goose工具的工作流程及原理。同时介绍了使用的sql文件模版中的指令。最后还介绍了对应的子命令的作用及如何执行sql文件中的内容的。若想进一步了解,可读读源代码。


特别说明:你的关注,是我写下去的最大动力。点击下方公众号卡片,直接关注。关注送《100个go常见的错误》pdf文档、经典go学习资料

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
人工智能 Kubernetes Java
回归开源,两位 Java 和 Go 程序员分享的开源贡献指引
Higress是一个基于Istio和Envoy的云原生API网关,支持AI功能扩展。它通过Go/Rust/JS编写的Wasm插件提供可扩展架构,并包含Node和Java的console模块。Higress起源于阿里巴巴,解决了Tengine配置重载及gRPC/Dubbo负载均衡问题,现已成为阿里云API网关的基础。本文介绍Higress的基本架构、功能(如AI网关、API管理、Ingress流量网关等)、部署方式以及如何参与开源贡献。此外,还提供了有效的开源贡献指南和社区交流信息。
370 33
|
2月前
|
关系型数据库 MySQL 数据库
MyEMS开源系统安装之数据库
本文详细讲解MyEMS的安装步骤,重点介绍数据库架构与脚本部署。MyEMS支持MySQL 8.0、MariaDB 10.5及SingleStore 7.0等数据库服务器。通过命令行或客户端工具执行SQL脚本完成安装,包括多个数据库(如myems_billing_db、myems_energy_db等)。此外,提供解决常见问题的方法,如“用户拒绝访问”、“COLLATE设置”和“MAX_ALLOWED_PACKET错误”。注意,不建议在生产环境中将数据库安装于Docker容器内。
53 1
|
3月前
|
人工智能 运维 关系型数据库
|
5月前
|
存储 NoSQL 关系型数据库
PolarDB开源数据库进阶课17 集成数据湖功能
本文介绍了如何在PolarDB数据库中接入pg_duckdb、pg_mooncake插件以支持数据湖功能, 可以读写对象存储的远程数据, 支持csv, parquet等格式, 支持delta等框架, 并显著提升OLAP性能。
247 3
|
5月前
|
存储 关系型数据库 分布式数据库
PolarDB开源数据库进阶课15 集成DeepSeek等大模型
本文介绍了如何在PolarDB数据库中接入私有化大模型服务,以实现多种应用场景。实验环境依赖于Docker容器中的loop设备模拟共享存储,具体搭建方法可参考相关系列文章。文中详细描述了部署ollama服务、编译并安装http和openai插件的过程,并通过示例展示了如何使用这些插件调用大模型API进行文本分析和情感分类等任务。此外,还探讨了如何设计表结构及触发器函数自动处理客户反馈数据,以及生成满足需求的SQL查询语句。最后对比了不同模型的回答效果,展示了deepseek-r1模型的优势。
250 3
|
5月前
|
存储 关系型数据库 分布式数据库
PolarDB开源数据库进阶课14 纯享单机版
PolarDB不仅支持基于“共享存储+多计算节点”的集群版,还提供类似开源PostgreSQL的单机版。单机版部署简单,适合大多数应用场景,并可直接使用PostgreSQL生态插件。通过Docker容器、Git克隆代码、编译软件等步骤,即可完成PolarDB单机版的安装与配置。具体操作包括启动容器、进入容器、克隆代码、编译软件、初始化实例、配置参数及启动数据库。此外,还有多个相关教程和视频链接供参考,帮助用户更好地理解和使用PolarDB单机版。
218 1
|
5月前
|
存储 容灾 关系型数据库
PolarDB开源数据库进阶课11 激活容灾(Standby)节点
本文介绍了如何激活PolarDB容灾(Standby)节点,实验环境依赖于Docker容器中用loop设备模拟共享存储。通过`pg_ctl promote`命令可以将Standby节点提升为主节点,使其能够接收读写请求。激活后,原Standby节点不能再成为PolarDB集群的Standby节点。建议删除对应的复制槽位以避免WAL文件堆积。相关操作和配置请参考系列文章及视频教程。
98 1
|
3月前
|
SQL 人工智能 数据可视化
16.1k star! 只需要DDL就能一键生成数据库关系图!开源神器ChartDB让你的数据结构"看得见"
ChartDB是一款开源的数据库可视化神器,通过一句智能查询就能自动生成专业的数据库关系图。无需安装客户端、不用暴露数据库密码,打开网页就能完成从数据建模到迁移的全流程操作,堪称开发者的"数据库透视镜"。
504 67
|
5月前
|
存储 关系型数据库 分布式数据库
PolarDB开源数据库进阶课13 单机版转换为集群版
本文介绍如何将“本地存储实例”转换为“共享存储实例”,依赖于先前搭建的实验环境。主要步骤包括:准备PFS二进制文件、格式化共享盘为pfs文件系统、启动pfsd服务、停库并拷贝数据到pfs内、修改配置文件,最后启动实例。通过这些操作,成功实现了从本地存储到共享存储的转换,并验证了新实例的功能。相关系列文章和视频链接提供了更多背景信息和技术细节。
90 0
|
5月前
|
存储 关系型数据库 分布式数据库
PolarDB开源数据库进阶课7 实时流式归档
本文介绍了如何在PolarDB RAC一写多读集群中实现实时归档,确保WAL日志的及时备份。实验依赖于Docker容器和loop设备模拟的共享存储环境。通过配置主节点的`pg_hba.conf`、创建复制槽以及使用`pg_receivewal`工具,实现实时接收并归档WAL文件。此外,还提供了详细的命令行帮助和相关文档链接,方便读者参考和操作。注意:如果已搭建容灾节点,则无需重复进行实时归档。
93 0