惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Proofpoint News Feed
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
博客园_首页
爱范儿
爱范儿
博客园 - 叶小钗
aimingoo的专栏
aimingoo的专栏
S
SegmentFault 最新的问题
MyScale Blog
MyScale Blog
阮一峰的网络日志
阮一峰的网络日志
IT之家
IT之家
Microsoft Security Blog
Microsoft Security Blog
Blog — PlanetScale
Blog — PlanetScale
博客园 - 【当耐特】
Y
Y Combinator Blog
量子位
博客园 - 三生石上(FineUI控件)
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
The Blog of Author Tim Ferriss
月光博客
月光博客
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
A
About on SuperTechFans

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例)
Golang里数据库migration方案
Jiajun Huang · 2020-12-16 · via Jiajun的技术笔记

Python中如果用SQLAlchemy的话,一般会用alembic来做migration。那么,Go呢?我一般用这个:

https://github.com/golang-migrate/migrate

官方的用法是生成migration文件(其实就是sql)时用命令行,升级时也可以用命令行。不过我更喜欢把升级文件和代码一起打包到二进制文件里。

我们依次来看。

创建migration文件

这个很简单,首先你要在自己电脑上装上 migrate 这个二进制:

curl -L https://github.com/golang-migrate/migrate/releases/download/$version/migrate.$platform-amd64.tar.gz | tar xvz

我是放到了 /usr/local/bin 下,其实也可以放到 $PATH 的任一自定义目录里。

生成migration文件,则执行以下命令即可:

$ migrate create -ext sql -dir ./migrations -seq create_user_table

执行之后,就会在 ./migrations 文件夹下,创建两个文件,都会包含 -seq 后的那一段,以 up.sqldown.sql 结尾。分别对应升级和降级操作该要执行的SQL。

migration操作,就写在对应的文件里。

升级

除了继续用 migrate 这个命令来进行升级降级操作,我们还可以把操作结合到程序里,我更喜欢这样做,好处如下:

  • 不用每个地方都打包 migrate 这个命令,或者安装这个二进制文件
  • 不用把migrations文件夹到处同步

咋做呢?这个时候就该祭出 go-bindata 这个包了,它的原理就是读文件,把文件的内容生成到一个 bindata.go 文件里,然后就可以通过内置的api,读取其中的内容。

那怎么结合到我们的应用里呢?直接上代码:

package main

import (
    "flag"
)

var migrateUp = flag.Bool("migrateUp", false, "run migration")

func main() {
    // ...
	if *migrateUp {
		s := bindata.Resource(migrations.AssetNames(),
			func(name string) ([]byte, error) {
				return migrations.Asset(name)
			})

		d, err := bindata.WithInstance(s)
		if err != nil {
			logrus.Panicf("failed to get migrations: %s", err)
		}
		m, err := migrate.NewWithSourceInstance("go-bindata", d, config.MigrateDBURL)
		if err != nil {
			logrus.Panicf("failed to get migrations: %s", err)
		}
		err = m.Up()
		if err != nil {
			logrus.Panicf("failed to migrate: %s", err)
		}
		return
	}
    // ...
}

就是介样,我们就可以愉快的把migration也编译到应用里,然后继续愉快的一个二进制包到处丢了。

当然了,要想使用 go-bindata,也得安装:

$ go get -u github.com/go-bindata/go-bindata/...

然后我在Makefile里加上这么一个动作:

bindata:
	cd migrations && go-bindata -pkg migrations .

duang,大功告成。