golang MySQL数据库迁移与架构管理插件库migrator的使用
Golang MySQL数据库迁移与架构管理插件库migrator的使用
简介
MySQL数据库迁移工具migrator是一个用于运行数据库迁移和管理数据库架构更新的Go库,兼容最新的MySQL v8。
安装
要安装migrator
包,您需要先安装Go并设置Go工作区。
- 首先需要安装Go(需要1.13+版本),然后可以使用以下Go命令安装
migrator
:
$ go get -u github.com/larapulse/migrator
- 在代码中导入:
import "github.com/larapulse/migrator"
快速开始
初始化带有迁移条目的migrator:
var migrations = []migrator.Migration{
{
Name: "19700101_0001_create_posts_table",
Up: func() migrator.Schema {
var s migrator.Schema
posts := migrator.Table{Name: "posts"}
posts.UniqueID("id")
posts.Varchar("title", 64)
posts.Text("content", false)
posts.Timestamps()
s.CreateTable(posts)
return s
},
Down: func() migrator.Schema {
var s migrator.Schema
s.DropTableIfExists("posts")
return s
},
},
{
Name: "19700101_0002_create_comments_table",
Up: func() migrator.Schema {
var s migrator.Schema
comments := migrator.Table{Name: "comments"}
comments.UniqueID("id")
comments.UUID("post_id", "", false)
comments.Varchar("name", 64)
comments.Column("email", migrator.String{Default: "<nil>"})
comments.Text("content", false)
comments.Timestamps()
comments.Foreign("post_id", "id", "posts", "RESTRICT", "RESTRICT")
s.CreateTable(comments)
return s
},
Down: func() migrator.Schema {
var s migrator.Schema
s.DropTableIfExists("comments")
return s
},
},
{
Name: "19700101_0003_rename_foreign_key",
Up: func() migrator.Schema {
var s migrator.Schema
keyName := migrator.BuildForeignNameOnTable("comments", "post_id")
newKeyName := migrator.BuildForeignNameOnTable("comments", "article_id")
s.AlterTable("comments", migrator.TableCommands{
migrator.DropForeignCommand(keyName),
migrator.DropIndexCommand(keyName),
migrator.RenameColumnCommand{"post_id", "article_id"},
migrator.AddIndexCommand{newKeyName, []string{"article_id"}},
migrator.AddForeignCommand{migrator.Foreign{
Key: newKeyName,
Column: "article_id",
Reference: "id",
On: "posts",
}},
})
return s
},
Down: func() migrator.Schema {
var s migrator.Schema
keyName := migrator.BuildForeignNameOnTable("comments", "article_id")
newKeyName := migrator.BuildForeignNameOnTable("comments", "post_id")
s.AlterTable("comments", migrator.TableCommands{
migrator.DropForeignCommand(keyName),
migrator.DropIndexCommand(keyName),
migrator.RenameColumnCommand{"article_id", "post_id"},
migrator.AddIndexCommand{newKeyName, []string{"post_id"}},
migrator.AddForeignCommand{migrator.Foreign{
Key: newKeyName,
Column: "post_id",
Reference: "id",
On: "posts",
}},
})
return s
},
}
m := migrator.Migrator{Pool: migrations}
migrated, err = m.Migrate(db)
if err != nil {
log.Errorf("Could not migrate: %v", err)
os.Exit(1)
}
if len(migrated) == 0 {
log.Print("Nothing were migrated.")
}
for _, m := range migrated {
log.Printf("Migration: %s was migrated ✅", m)
}
log.Print("Migration did run successfully")
第一次迁移运行后,将创建migrations
表:
+----+-------------------------------------+-------+----------------------------+
| id | name | batch | applied_at |
+----+-------------------------------------+-------+----------------------------+
| 1 | 19700101_0001_create_posts_table | 1 | 2020-06-27 00:00:00.000000 |
| 2 | 19700101_0002_create_comments_table | 1 | 2020-06-27 00:00:00.000000 |
| 3 | 19700101_0003_rename_foreign_key | 1 | 2020-06-27 00:00:00.000000 |
+----+-------------------------------------+-------+----------------------------+
如果想使用其他名称作为迁移表,可以在运行迁移前更改Migrator
:
m := migrator.Migrator{TableName: "_my_app_migrations"}
事务性迁移
如果在一个迁移中有多个命令,并且您希望确保它被正确迁移,可以启用每个迁移的事务执行:
var migration = migrator.Migration{
Name: "19700101_0001_create_posts_and_users_tables",
Up: func() migrator.Schema {
var s migrator.Schema
posts := migrator.Table{Name: "posts"}
posts.UniqueID("id")
posts.Timestamps()
users := migrator.Table{Name: "users"}
users.UniqueID("id")
users.Timestamps()
s.CreateTable(posts)
s.CreateTable(users)
return s
},
Down: func() migrator.Schema {
var s migrator.Schema
s.DropTableIfExists("users")
s.DropTableIfExists("posts")
return s
},
Transaction: true,
}
回滚和恢复
如果需要回滚部署和数据库,可以回滚最后迁移的批次:
m := migrator.Migrator{Pool: migrations}
reverted, err := m.Rollback(db)
if err != nil {
log.Errorf("Could not roll back migrations: %v", err)
os.Exit(1)
}
if len(reverted) == 0 {
log.Print("Nothing were rolled back.")
}
for _, m := range reverted {
log.Printf("Migration: %s was rolled back ✅", m)
}
要恢复所有迁移的项目,您需要在migrator
上调用Revert()
:
m := migrator.Migrator{Pool: migrations}
reverted, err := m.Revert(db)
自定义查询
您可以向数据库添加任何列定义,只需确保实现columnType
接口:
type customType string
func (ct customType) buildRow() string {
return string(ct)
}
posts := migrator.Table{Name: "posts"}
posts.UniqueID("id")
posts.Column("data", customType("json not null"))
posts.Timestamps()
同样的逻辑适用于向Schema添加自定义命令以进行迁移或恢复,只需确保实现command
接口:
type customCommand string
func (cc customCommand) toSQL() string {
return string(cc)
}
var s migrator.Schema
c := customCommand("DROP PROCEDURE abc")
s.CustomCommand(c)
更多关于golang MySQL数据库迁移与架构管理插件库migrator的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang MySQL数据库迁移与架构管理插件库migrator的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang MySQL数据库迁移与架构管理插件库migrator使用指南
什么是migrator
migrator是一个流行的Golang数据库迁移工具,它提供了简单易用的API来管理数据库架构变更。它支持MySQL、PostgreSQL、SQLite等数据库,并具有以下特点:
- 支持版本化迁移
- 提供up和down操作
- 记录迁移历史
- 支持事务
- 可嵌入到Go应用程序中
安装migrator
go get -u github.com/golang-migrate/migrate/v4
go get -u github.com/golang-migrate/migrate/v4/database/mysql
基本使用示例
1. 初始化迁移
package main
import (
"database/sql"
"log"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/mysql"
_ "github.com/golang-migrate/migrate/v4/source/file"
)
func main() {
db, err := sql.Open("mysql", "user:password@tcp(localhost:3306)/dbname?multiStatements=true")
if err != nil {
log.Fatal(err)
}
defer db.Close()
driver, err := mysql.WithInstance(db, &mysql.Config{})
if err != nil {
log.Fatal(err)
}
m, err := migrate.NewWithDatabaseInstance(
"file:///path/to/migrations",
"mysql",
driver,
)
if err != nil {
log.Fatal(err)
}
// 执行迁移
err = m.Up()
if err != nil && err != migrate.ErrNoChange {
log.Fatal(err)
}
log.Println("Migration done")
}
2. 创建迁移文件
迁移文件通常存储在项目目录下的migrations
文件夹中,命名格式为:
[version]_[description].up.sql
[version]_[description].down.sql
例如:
0001_create_users_table.up.sql
0001_create_users_table.down.sql
3. 编写迁移SQL
0001_create_users_table.up.sql
:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
0001_create_users_table.down.sql
:
DROP TABLE IF EXISTS users;
高级功能
1. 特定版本迁移
// 迁移到特定版本
err = m.Migrate(2)
if err != nil {
log.Fatal(err)
}
// 回滚一步
err = m.Steps(-1)
if err != nil {
log.Fatal(err)
}
2. 强制版本
// 当数据库处于脏状态时,可以强制设置版本
err = m.Force(2)
if err != nil {
log.Fatal(err)
}
3. 获取当前版本
version, dirty, err := m.Version()
if err != nil {
log.Fatal(err)
}
log.Printf("Current version: %d, dirty: %v", version, dirty)
最佳实践
- 版本控制:将迁移文件纳入版本控制系统
- 原子性:每个迁移应该是独立的,可以单独应用或回滚
- 测试:在生产环境应用前测试所有迁移
- 备份:执行重大变更前备份数据库
- 命名规范:使用一致的命名约定
与Go集成
可以将迁移作为应用程序启动的一部分:
func runMigrations(db *sql.DB) error {
driver, err := mysql.WithInstance(db, &mysql.Config{})
if err != nil {
return err
}
m, err := migrate.NewWithDatabaseInstance(
"file://migrations",
"mysql",
driver,
)
if err != nil {
return err
}
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
return err
}
return nil
}
替代方案
除了migrator,还有其他Golang迁移工具:
- gormigrate - 基于GORM的迁移工具
- sql-migrate - 另一个流行的迁移工具
- goose - 功能丰富的迁移工具
migrator因其简单性和灵活性成为许多项目的首选。它不依赖于特定的ORM,可以与任何数据库驱动配合使用。