Golang Migration

一个项目长期运行,一定设计到数据库表的迭代升级,尤其是在多环境交付的模式下,清晰严格的版本数据库设计升降机管理显得尤为必要。在go语言下有相关工具go migration来完成相关工作。

go migration 可以做什么

  1. 管理版本sql
  2. 将db table升级到指定版本
  3. 将db table降级到指定版本
  4. 支持mysql,postgresql, sqlLite, MariaDB, MongoDB等主流数据库
  5. 支持命令行与SDK两种执行方式

安装

git clone git@github.com:golang-migrate/migrate.git

cd migrate; make build

mv migrate /usr/local/bin

使用介绍

创建版本sql

migrate create -ext sql -dir database/migration/ -seq init_mg

  • -ext 文件格式
  • -dir sql目录
  • -seq 序列号

版本格式如下

  1. 000001_init_mg.up.sql // 1版本的升级sql
  2. 000001_init_mg.down.sql // 1版本的降级sql

执行变更到DB

  1. 升级到最新版migrate -path database/migration/ -database "mysql://{user}:{passwd}@localhost:3306/{dbname}" -verbose up

  2. 升级N个版本migrate -path database/migration/ -database "mysql://{user}:{passwd}@localhost:3306/{dbname}" -verbose up {N}

  3. 降级N个版本migrate -path database/migration/ -database "mysql://{user}:{passwd}@localhost:3306/{dbname}" -verbose down {N}

  4. 直接升降级到指定版本migrate -path database/migration/ -database "mysql://root:123456@tcp(127.0.0.1:3306)/vc" -verbose goto 2

migration的实现逻辑如何

在官方的介绍里,有一张图如下。就是这么简单 image.png 在使用migrate的过程中,用户做的事情是

  1. 创建版本sql文件,文件名格式符合migrate格式
  2. 维护版本之间的升降级sql

migrate做的事情是

  1. 按照文件名识别sql的版本序列
  2. 按照用户预期的目标版本顺序执行升降级sql
  3. 将当前的sql版本记录在服务db的schema_migrations表中

总结

migration的实现思路并不复杂,工具的目标是协助解决版本迭代时sql升降级顺利。

golang migration使用文件名来识别版本,当一个版本sql变更较多时可能导致sql文件臃肿。其他类似服务有些支持以目录为版本粒度,对sql较多的大型项目更加友好。

migration只是一个执行器,软件的sql升降级实际能否顺利最终依赖up.sql和down.sql的维护策略,对于良好的维护策略应该做到以下几点

  1. sql的重入考虑,create table / drop table 时判断table是否存在
  2. 对历史版本 只读特性 的严格支持
  3. 对于多db实例的sql语法兼容
  4. 对于删改操作的谨慎执行,可以考虑软删除策略
  5. migration 需要从sql to db, 要保持to db的链路唯一,不要再使用其他的to db链路,比如model to db