1 項(xiàng)目地址
https://github.com/golang-migrate/migrate
2 使用情景
一些項(xiàng)目功能會(huì)涉及到數(shù)據(jù)庫和代碼邏輯的修改,對(duì)于數(shù)據(jù)庫的修改,雖然 gorm 之類的工具能夠在代碼里面適配大部分情況,但是不能覆蓋所有數(shù)據(jù)庫變更情況,而且也不夠清晰。為清楚表示某次代碼提交設(shè)計(jì)的數(shù)據(jù)庫的修改并且方便 devops 部署服務(wù),可以使用 golang-migrate 這樣的工具明確的標(biāo)識(shí)對(duì)于數(shù)據(jù)的某次修改,可以對(duì)這些修改做部署和回滾。
使用 golang-migrate 有兩種方式,一種是使用 migrate 提供的 CLI,一種是使用 golang library。本次測試使用 migrate CLI。
2.1 支持?jǐn)?shù)據(jù)庫類型
Source drivers: github-ee, godoc-vfs, s3, bitbucket, go-bindata, gcs, file, github, gitlab
Database drivers: cockroachdb, firebird, postgresql, redshift, clickhouse, postgres, cockroach, firebirdsql, mysql, crdb-postgres, mongodb, mongodb+srv, neo4j, pgx, spanner, sqlserver, stub, cassandra
3 使用方法
一開始使用 mysql 做測試,結(jié)果一直提示錯(cuò)誤,就先用 github 上的教程用 postgres 測試了一遍。之后再解決 mysql 測試的問題。
3.1 安裝 migrate CLI
3.1.1 參考
https://github.com/golang-migrate/migrate/tree/master/cmd/migrate
3.1.2 安裝
直接 Release Downloads 下載對(duì)應(yīng)版本即可。官網(wǎng)上的說明會(huì)讓人誤以為用 migrate CLI 的版本只支持某種數(shù)據(jù)庫,但是實(shí)際測試發(fā)現(xiàn)下載的 migrate CLI 可以支持各種 Database drivers。
3.2 postgres 測試
3.2.1 參考
https://github.com/golang-migrate/migrate/blob/master/database/postgres/TUTORIAL.md
3.2.2 啟動(dòng) postgres 數(shù)據(jù)庫
在 192.168.10.212 這臺(tái)測試服務(wù)器上用 docker 啟動(dòng) postgres 數(shù)據(jù)庫
dockerrun--namepostgres-ePOSTGRES_PASSWORD=mysecretpassword-dpostgres:14.0
進(jìn)入 postgres 容器運(yùn)行 psql -h localhost -U postgres -w -c "create database example;"來創(chuàng)建 example 數(shù)據(jù)庫。
3.2.3 創(chuàng)建某次數(shù)據(jù)庫變更的 sql 文件
mkdir migrations #首次執(zhí)行,用于存放變更的 sql 文件
比如說這次修改我們需要新增一個(gè) users 的表,
migrate create -ext sql -dir ./migrations -seq create_users_table
這個(gè)命令會(huì)在 migrations 目錄下生成兩個(gè)文件000001_create_users_table.up.sql 和000001_create_users_table.down.sql , 000001 是某次修改的版本號(hào),000001_create_users_table.up.sql 用來存放創(chuàng)建 users 表的 sql 腳本,000001_create_users_table.down.sql 用來存放回滾這次操作的 sql 腳本。migrate create 命令只負(fù)責(zé)創(chuàng)建文件,sql 文件的內(nèi)容需要我們手動(dòng)編輯。
migrations├── 000001_create_users_table.down.sql├── 000001_create_users_table.up.sql
編輯000001_create_users_table.up.sql
CREATE TABLE IF NOT EXISTS users( user_id serial PRIMARY KEY, username VARCHAR (50) UNIQUE NOT NULL, password VARCHAR (50) NOT NULL, email VARCHAR (300) UNIQUE NOT NULL);
編輯000001_create_users_table.down.sql
DROP TABLE IF EXISTS users;
3.2.4 應(yīng)用某次數(shù)據(jù)庫修改
migrate 的 up 子命令用來應(yīng)用某一次數(shù)據(jù)庫變更, down 子命令用來回滾數(shù)據(jù)庫變更操作。
比如 up [N], N 表示執(zhí)行多少個(gè)數(shù)據(jù)庫變更任務(wù),那具體是執(zhí)行 ./migrations 下面的哪些 sql 腳本呢?
up [N] Apply all or N up migrations down [N] [-all] Apply all or N down migrations Use -all to apply all down migrations
首次執(zhí)行 migrate up 命令后,會(huì)在數(shù)據(jù)庫中添加 schema_migrations 表,這個(gè)表有兩個(gè)字段:version 和 dirty,version 用來表示當(dāng)前數(shù)據(jù)庫對(duì)應(yīng) ./migrations 下面的那個(gè)版本,比如第一次執(zhí)行 migrate up 1 后,如果執(zhí)行成功了, schema_migrations 表中的 version=1,說明當(dāng)前數(shù)據(jù)庫對(duì)應(yīng)的是000001_create_users_table.up.sql 這個(gè)版本 dirty=f(false),執(zhí)行到 version=1 這次的變更沒有出錯(cuò)。如果 dirty=t(true) 會(huì)涉及要怎么修復(fù)這個(gè)錯(cuò)誤的問題。
3.2.4.1 首次執(zhí)行 migrate up
migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 11/u create_users_table (47.755135ms)
執(zhí)行 migrate up 后,數(shù)據(jù)庫中增加了 users 表和 schema_migrations 表
example=# d List of relations Schema | Name | Type | Owner--------+-------------------+----------+---------- public | schema_migrations | table | postgres public | users | table | postgres public | users_user_id_seq | sequence | postgres(3 rows) example=# d users; Table "public.users" Column | Type | Collation | Nullable | Default----------+------------------------+-----------+----------+---------------------------------------- user_id | integer | | not null | nextval('users_user_id_seq'::regclass) username | character varying(50) | | not null | password | character varying(50) | | not null | email | character varying(300) | | not null |Indexes: "users_pkey" PRIMARY KEY, btree (user_id) "users_email_key" UNIQUE CONSTRAINT, btree (email) "users_username_key" UNIQUE CONSTRAINT, btree (username)
example=# select * from schema_migrations; version | dirty---------+------- 1 | f(1 row)
3.2.4.2 回滾操作
migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations downAre you sure you want to apply all down migrations? [y/N]yApplying all down migrations1/d create_users_table (31.550358ms)
migrations down 后,數(shù)據(jù)庫恢復(fù)到應(yīng)用 create_users 之前的狀態(tài),users 表被刪除,schema_migrations 表記錄被刪除
example=# select * from schema_migrations ; version | dirty---------+-------(0 rows)
3.2.5 應(yīng)用多次修改
為了測試 migrations up [N] 執(zhí)行多次修改的情形,第二次修改我們使用事務(wù)為 users 表增加 COLUMN,
migrate create -ext sql -dir ./migrations -seq add_mood_to_users , migrations 目錄下會(huì)增加000002_add_mood_to_users.up.sql 和000002_add_mood_to_users.down.sql 兩個(gè)文件。
000002_add_mood_to_users.up.sql :
BEGIN;CREATE TYPE enum_mood AS ENUM ( 'happy', 'sad', 'neutral');ALTER TABLE users ADD COLUMN IF NOT EXISTS mood enum_mood;COMMIT;
000002_add_mood_to_users.down.sql :
BEGIN; ALTER TABLE users DROP COLUMN IF EXISTS mood;DROP TYPE enum_mood; COMMIT;
第三次修改為 users 表增加 role_id 這個(gè) COLUMN
migrate create -ext sql -dir ./migrations -seq add_roleid_to_users , migrations 目錄下會(huì)增加000003_add_roleid_to_users.up.sql 和000003_add_roleid_to_users.down.sql 兩個(gè)文件。
000003_add_roleid_to_users.up.sql
ALTER TABLE users ADD COLUMN IF NOT EXISTS role_id INTEGER;
000003_add_roleid_to_users.down.sql
ALTER TABLE users DROP COLUMN IF EXISTS role_id;
這樣 migrations 目錄下有如下6個(gè) sql 文件:
.└── migrations ├── 000001_create_users_table.down.sql ├── 000001_create_users_table.up.sql ├── 000002_add_mood_to_users.down.sql ├── 000002_add_mood_to_users.up.sql ├── 000003_add_roleid_to_users.down.sql └── 000003_add_roleid_to_users.up.sql
3.2.5.1 應(yīng)用多次修改
執(zhí)行 migrate down 回滾 migrations 目錄中所有修改。migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations down
migrate up 表示執(zhí)行 migrations 目錄中所有 up.sql 腳本。migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up
migrate up [N], 表示從 schema_migrations 表的 version 的值后再執(zhí)行 N 個(gè)部署。假設(shè) schema_migration 中 version=1,migrate up [2] 就會(huì)執(zhí)行 migrations 目錄中 000001* 之后的000002_add_mood_to_users.up.sql 和000003_add_roleid_to_users.up.sql 兩個(gè)操作。
3.2.6 測試執(zhí)行失敗的情況
首先執(zhí)行 migrate down 回滾所有操作,然后執(zhí)行 migrate up 2 應(yīng)用000001_create_users_table.up.sql 和000002_add_mood_to_users.up.sql 。接下來我們修改000003_add_roleid_to_users.up.sql ,使得000003_add_roleid_to_users.up.sql 語法錯(cuò)誤
? postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations down # 回滾所有操作Are you sure you want to apply all down migrations? [y/N]yApplying all down migrationsno change? postgres? postgres? postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 2 # 應(yīng)用 `000001_create_users_table.up.sql` 和 `000002_add_mood_to_users.up.sql`1/u create_users_table (47.883494ms)2/u add_mood_to_users (82.025579ms)? postgres? postgres cat migrations/000003_add_roleid_to_users.up.sqlALTER TABLE users ADD COLUMN role_id INTEGER errtest;%# 修改 000003_add_roleid_to_users.up.sql 增加 errtest 到語句末尾,使得 sql 語法錯(cuò)誤 ? postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 1 # 執(zhí)行錯(cuò)誤error:migrationfailed:syntaxerroratornear"errtest"(column46)inline1:ALTERTABLEusersADDCOLUMNrole_idINTEGERerrtest;(details:pq:syntaxerroratornear"errtest")
這個(gè)時(shí)候查詢 postgres 數(shù)據(jù)庫的 schema_migrations 表,version=3,說明當(dāng)前執(zhí)行到 000003, 但是 dirty=t 說明執(zhí)行有錯(cuò)誤。
example=# select * from schema_migrations ; version | dirty---------+------- 3 | t(1 row)
然后修正000003_add_roleid_to_users.up.sql 的語法錯(cuò)誤(去掉多余的 “errtest”),再次執(zhí)行 migrate up 1,這個(gè)時(shí)候還是提示錯(cuò)誤,因?yàn)?version=3 的 dirty=t,這個(gè)時(shí)候需要使用 migrate force 3 來確認(rèn)說 version=3 的錯(cuò)誤問題已修復(fù),而且需要執(zhí)行 migrate down 1 將 version 回退到 version=2 ,才能繼續(xù)執(zhí)行。
postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 1error: migration failed: syntax error at or near "errtest" (column 60) in line 1: ALTER TABLE users ADD COLUMN IF NOT EXISTS role_id INTEGER errtest; (details: pq: syntax error at or near "errtest")? postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations force 3? postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations down 13/d add_roleid_to_users (34.332954ms)? postgres migrate -database 'postgres://postgres:mysecretpassword@192.168.10.212:5432/example?sslmode=disable' -path ./migrations up 13/u add_roleid_to_users (36.832839ms)
3.3 mysql 測試
說回前面說的測試 mysql 出現(xiàn)錯(cuò)誤的問題,錯(cuò)誤提示如下:
migrate -database mysql://root:x*xxx@192.168.10.212:3306/temp -path ./migrations upzsh: no matches found: mysql://root:x*xxx@192.168.10.212:3306/temp
查了一下這個(gè)錯(cuò)誤是因?yàn)槲沂褂玫?shell 是 zsh, zsh 會(huì)自動(dòng)解釋 * ?等字符,而不是把 * ?留給命令 migrate 來解析,導(dǎo)致了錯(cuò)誤,解決方案是在 ~/.zshrc 中加入:setopt no_nomatch 。另外一個(gè)解決方法是把 -database 參數(shù)的值加上引號(hào) migrate -database 'mysql://root:x*xxx@192.168.10.212:3306/temp' -path ./migrations up
修正了 zsh 的問題后,再次執(zhí)行 migrate up,還是提示錯(cuò)誤:
migrate -database mysql://root:x*xxx@192.168.10.212:3306/temp -path ./migrations uperror: default addr for network '192.168.10.212:3306' unknown
這次的錯(cuò)誤是因?yàn)?mysql 的 url 書寫格式問題,mysql 的 url 需要寫成 mysql://root:passwd@tcp(192.168.10.212:3306)/database 這樣的格式。
-
服務(wù)器
+關(guān)注
關(guān)注
13文章
9723瀏覽量
87422 -
數(shù)據(jù)庫
+關(guān)注
關(guān)注
7文章
3905瀏覽量
65853 -
Docker
+關(guān)注
關(guān)注
0文章
513瀏覽量
12770
原文標(biāo)題:Go 語言數(shù)據(jù)庫遷移工具 golang-migrate
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
【Nanopi2試用體驗(yàn)】高級(jí)(九):Nanopi2上配置PostgreSQL數(shù)據(jù)庫
用Delphi做數(shù)據(jù)庫開發(fā)
用PowerBuilder做數(shù)據(jù)庫開發(fā)
什么是Postgres?Postgres是什么意思
用Visual C++做數(shù)據(jù)庫開發(fā)
MySQL與Postgres兩大免費(fèi)數(shù)據(jù)庫大不同
Uber為什么從Postgres遷移到MySQL

數(shù)據(jù)庫課件教程之數(shù)據(jù)庫的啟動(dòng)與關(guān)閉講解資料說明

數(shù)據(jù)庫到底要不要上Docker
數(shù)據(jù)庫數(shù)據(jù)恢復(fù)-Syabse數(shù)據(jù)庫數(shù)據(jù)恢復(fù)案例

python讀取數(shù)據(jù)庫數(shù)據(jù) python查詢數(shù)據(jù)庫 python數(shù)據(jù)庫連接
sql怎么用代碼創(chuàng)建數(shù)據(jù)庫
數(shù)據(jù)庫數(shù)據(jù)恢復(fù)-ORACLE數(shù)據(jù)庫常見故障有哪些?能恢復(fù)嗎?
數(shù)據(jù)庫數(shù)據(jù)恢復(fù)——MongoDB數(shù)據(jù)庫文件拷貝后服務(wù)無法啟動(dòng)的數(shù)據(jù)恢復(fù)

評(píng)論