Go 每日一库之 goose — 数据库版本管理工具
2023-11-20 08:53:36 Author: Go语言中文网(查看原文) 阅读量:9 收藏

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

什么是数据库版本管理?

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

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

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

alter table `user` add column address varchar(255NOT 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:[email protected]: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子命令都是对升级和回退操作的组合。

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

image.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文件被重复执行。

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文件中的内容的。若想进一步了解,可读读源代码。


推荐阅读

福利
我为大家整理了一份从入门到进阶的Go学习资料礼包,包含学习建议:入门看什么,进阶看什么。关注公众号 「polarisxu」,回复 ebook 获取;还可以回复「进群」,和数万 Gopher 交流学习。


文章来源: http://mp.weixin.qq.com/s?__biz=MzAxMTA4Njc0OQ==&mid=2651454815&idx=1&sn=1b37af5a6d34113c58c1f34ce150eaad&chksm=80bb23adb7ccaabb193a3832febb39f1c983c93419250abc6d7609c0e6d56717b01c50f28609&scene=0&xtrack=1#rd
如有侵权请联系:admin#unsafe.sh