MySQl schema 表变更版本管理
https://github.com/nomad-software/snap https://github.com/arstercz/snap
注: 笔者新启 snap 分支项目后, 做了以下改动:
修复 cli 命令行需要返回 error 信息的错误;
增加 clear 选择删除指定库的版本控制信息;
更多信息参见 snap 链接
snap 用途概述 在开发过程中, 我们经常需要对核心的库表结构进行调整, 新建表, 增删字段等都需要记录以便和线上的环境区别开, 亦可以和相关的代码对应起来方便功能的追溯. 在交叉开发的环境中, 多名开发者共同更新一个表的情况很容易引起开发和部署的混乱, 可以通过版本管理的方式避免此类问题.
-
适用范围 仅适用于内网开发环境, 线上环境不做改动, 指定库中的所有表的 DDL 语句都需要使用 snap 工具更新.
-
风险提示 alter 相关的语句不影响测试表中的数据, create 相关的语句在回滚的时候会清理相关的数据.
-
选项说明 snap 以命令行方式运行:
snap command <arguments...> [optional]
更细节的帮助信息可以通过 snap help command 获得, 以下为全局的帮助信息:
# ./snap
___ _ __ __ _ _ __
/ __| '_ \ / _' | '_ \ v0.1a
\__ \ | | | (_| | |_) |
|___/_| |_|\__,_| .__/
|_|
Version control for MySql database schemas
by Gary Willoughby <snap@nomad.so>
USAGE:
snap command <arguments...> [optional]
COMMANDS:
commit, ci <database> <snapfile> <message>
copy, cp <source-database> <destination-database> [revision]
diff <database> <from-revision>[..<to-revision>]
dump <database> [revision]
help [command]
init <database>
list, ls
log <database>
show <database> [revision]
update, up <database> [revision]
clear, cl <database>
version
- 工作流程 snap 使用类似 git 的方式来实现版本的管理, 每次指定库的 DDL(sql包括 SNAP_UP 和 SNAP_DOWN两部分) 语句更新都会将库中所有的当前表结构信息保存一份到 snap 的配置库中, SNAP_UP 和 SNAP_DOWN 相关的 sql 也会保存到 snap 配置库的相关字段中, 在开发者指定回滚或更新到哪个版本的时候, snap 则根据保存在配置库中的信息进行重建(不变的表不做改动).
从上面描述来看 SNAP_UP 和 SNAP_DOWN 相关的 SQL 是版本管理的根本, 开发者每次更新 sql 前都要写好对应的 SNAP_UP 和 SNAP_DOWN 语句, 比如以下 sql:
-- SNAP_UP
create table snapt(
id int(10)
) engine = innodb;
-- SNAP_DOWN
drop table snapt;
SNAP_UP 即为 do, SNAP_DOWN 即为 undo.
- 操作示例 snap 工具默认读取home目录下的 .snap 文件内容当做配置信息, 多个开发者则在各自的 home 目录下创建配置信息. 如下所示:
# cat /home/arstercz/.snap
{
"identity": "zhe.chen <arstercz@gmail.com>",
"database": {
"user": "arstercz",
"password": "xxxxxxxxxxx",
"protocol": "tcp",
"host": "127.0.0.1",
"port": "3306"
}
}
库表版本管理的流程类似 git, 最开始需要初始化, 将最初的库中的表结构信息保存到 snap 配置库中(默认为 snap_config)
# ./snap init cztest
2016/06/03 17:48:42 Initialising 'cztest' database for managment
2016/06/03 17:48:42 Database initialised successfully.
init 即为第一次提交 cztest 库的全量表结构信息, 如果需要创建新表 snapt, 则在 sql 文件中写好 SNAP_UP 和 SNAP_DOWN 相关的 sql, 之后进行 commit 提交, 如下所示, commit 命令最后的参数为当前操作的注释说明.
# cat 1.sql
-- SNAP_UP
create table snapt(
id int(10)
) engine = innodb;
-- SNAP_DOWN
drop table snapt;
# ./snap commit cztest 1.sql "create snapt table"
2016/06/03 17:48:48 File committed successfully.
mysql root@[localhost:s3306 cztest] > show tables;
+------------------+
| Tables_in_cztest |
+------------------+
| snapt |
| test |
+------------------+
2 rows in set (0.00 sec)
可以使用 log 命令查看 cztest 库操作的历史记录概要, show 命令会列出指定库名某一版本下所有的表结构信息. 下面中的 Revision 即为版本号:
# ./snap log cztest
Revision: 2
Author: arstercz <arstercz@gmail.com>
Date: 2016-06-03 17:48:48
create snapt table
Revision: 1
Author: arstercz <arstercz@gmail.com>
Date: 2016-06-03 17:48:42
Database initialised.
回滚到第1版本:
# ./snap update cztest 1
mysql root@[localhost:s3306 cztest] > show tables;
+------------------+
| Tables_in_cztest |
+------------------+
| test |
+------------------+
1 row in set (0.00 sec)
如果需要再次更新表呢? snap 如何保证多个用户之间的操作不会冲突? 当前情况下如果再想 commit DDL 操作, 需要先使用 snap 将 cztest 库更新到最高版本, 之后才能提交 DDL 语句. 通过这个流程可以比较有效的避免开发者之间的冲突.
备注 使用 snap 工具后, 所有的 DDL 语句都需要在一个文件里指定好 SNAP_UP 和 SNAP_DOWN 两部分以便版本的更新和回退, 如果在此期间手工更改了相关的表,理论上都不会影响 SNAP_UP 和 SANP_DOWN 之外的表, 但为了避免不必要的麻烦, 开发者可以使用 clear 选项清除指定库相关的所有版本信息, 再重新 init 该库.
同类工具 https://github.com/winebarrel/ridgepole 开发人员可能不习惯这种创建表的方式.