最近项目要用Go
写。受Laravel
的启发,想找一个Go
语言的数据库版本迁移工具,然后就找到了一个大家用的比较多的工具:migrate。因为官方文档以及网上资源太少,所以这里写一篇文章记录下。
(安装这个工具的方法省略)
我们创建一个目录migrations
,里面存放我们需要迁移的对象。
然后,创建迁移文件:
1 | migrate create -ext sql -dir migrations create_users_table |
执行这条命令会创建两个文件,分别是:
1 | ~/codeDir/golangCode/echo-demo # ls migrations/ |
20190617061102
是和时间有关的一个标识,用来区分我们的migration
的版本。
这两个文件都是空的,需要我们自己去填充。很明显,这是两个相反的sql
操作。
我们在20190617061102_create_users_table.up.sql
中写入创建users
表的操作:
1 | CREATE TABLE IF NOT EXISTS users( |
对应的我们就需要在20190617061102_create_users_table.down.sql
中删除这张表:
1 | DROP table IF EXISTS users; |
然后,我们在终端执行命令:
1 | migrate -verbose -source file://migrations -database postgres://postgres:postgres用户的密码@host.docker.internal:5432/postgres?sslmode=disable up 1 |
结果如下:
1 | ~/codeDir/golangCode/echo-demo # migrate -verbose -source file://migrations -database postgres://postgres:postgres用户的密码@host.docker.internal:5432/postgres?sslmode=disable up 1 |
此时,我们看看数据库的表:
1 | postgres=# \dt |
发现,此时有两张表,分别是schema_migrations
以及我们创建的users
。其中,schema_migrations
里面存放的是当前migration
的版本以及状态。
我们来看看:
1 | postgres=# select * from schema_migrations; |
此时,migration
的版本是20190617061102
,这个就是我们文件的前缀。dirty
代表当前版本是干净的还是脏的。f
表示干净(即没有出问题)。
然后,我来演示一下migrate
失败的操作。
我们再创建一个migration
文件:
1 | migrate create -ext sql -dir migrations create_emails_table |
1 | ~/codeDir/golangCode/echo-demo # ls migrations/ |
然后,在up
的那个文件里面写下:
1 | CREATE TABLE IF NOT EXISTS emails( |
(我们在id
的那一行故意写错了,加了一个会导致报错的字符串error
)
在down
的那个文件里面写下:
1 | DROP table IF EXISTS emails; |
然后,执行迁移操作:
1 | ~/codeDir/golangCode/echo-demo # migrate -verbose -source file://migrations -database postgres://postgres:postgres用户的密码@host.docker.internal:5432/postgres?sslmode=disable up 1 |
完美报错。
此时,我们把error
这个字符串删除:
1 | CREATE TABLE IF NOT EXISTS emails( |
然后再执行迁移操作:
1 | ~/codeDir/golangCode/echo-demo # migrate -verbose -source file://migrations -database postgres://postgres:postgres用户的密码@host.docker.internal:5432/postgres?sslmode=disable up 1 |
(开始的时候,我是吃惊的,因为我按照Laravel migrate
的思路,不应该会报错)
报错提示说database version
是脏的。所以,我们看看schema_migrations
表的内容:
1 | postgres=# select * from schema_migrations; |
我们发现,尽管migrate up
失败了,但是这里还是会up
这个version
。这是我用不习惯的一个地方。
此时,我们需要按照报错的提示:
1 | Fix and force version. |
我们已经把error
字符串删除了,所以此时我们只需要force version
一下:
1 | ~/codeDir/golangCode/echo-demo # migrate -verbose -source file://migrations -database postgres://postgres:postgres用户的密码@host.docker.internal:5432/postgres?sslmode=disable force 20190617062220 |
force
后面带上dirty
的那个版本。
此时,我们再看看schema_migrations
表的内容:
1 | postgres=# select * from schema_migrations; |
dirty
已经是f
了,代表这是干净的了。
然后,我们再回退到上一个版本:
1 | ~/codeDir/golangCode/echo-demo # migrate -verbose -source file://migrations -database postgres://postgres:postgres用户的密码@host.docker.internal:5432/postgres?sslmode=disable down 1 |
回退成功:
1 | postgres=# select * from schema_migrations; |
然后,我们现在可以正常的执行up
操作了:
1 | ~/codeDir/golangCode/echo-demo # migrate -verbose -source file://migrations -database postgres://postgres:postgres用户的密码@host.docker.internal:5432/postgres?sslmode=disable up 1 |
1 | postgres=# \dt |
emails
表创建完成。
(感觉还是不如Laravel
的migrate
好用)