golang数据库模式迁移助手插件库gormigrate的使用
Golang数据库模式迁移助手插件库Gormigrate的使用
Gormigrate简介
Gormigrate是一个用于Gorm的极简迁移助手。Gorm已经有有用的迁移功能,但缺少适当的模式版本控制和迁移回滚支持。
注意:如果你需要使用Gorm v1版本(使用github.com/jinzhu/gorm
作为导入路径),请使用gopkg.in/gormigrate.v1
导入路径。
当前Gorm版本(v2)通过使用github.com/go-gormigrate/gormigrate/v2
导入路径来支持。
支持的数据库
Gormigrate支持Gorm支持的任何数据库:
- MySQL
- MariaDB
- PostgreSQL
- SQLite
- Microsoft SQL Server
- TiDB
- Clickhouse
使用示例
下面是一个完整的使用示例:
package main
import (
"log"
"github.com/go-gormigrate/gormigrate/v2"
"github.com/google/uuid"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func main() {
db, err := gorm.Open(sqlite.Open("./data.db"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
log.Fatal(err)
}
m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{{
// 创建`users`表
ID: "201608301400",
Migrate: func(tx *gorm.DB) error {
// 最好在函数内部复制结构体,以防止原始结构体随时间变化而产生副作用
type user struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey;uniqueIndex"`
Name string
}
return tx.Migrator().CreateTable(&user{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropTable("users")
},
}, {
// 向`users`表添加`age`列
ID: "201608301415",
Migrate: func(tx *gorm.DB) error {
// 当表已存在时,只定义将要更改的列
type user struct {
Age int
}
return tx.Migrator().AddColumn(&user{}, "Age")
},
Rollback: func(tx *gorm.DB) error {
type user struct {
Age int
}
return db.Migrator().DropColumn(&user{}, "Age")
},
}, {
// 创建`organizations`表,用户属于该表
ID: "201608301430",
Migrate: func(tx *gorm.DB) error {
type organization struct {
ID uuid.UUID `gorm:"type:uuid;primaryKey;uniqueIndex"`
Name string
Address string
}
if err := tx.Migrator().CreateTable(&organization{}); err != nil {
return err
}
type user struct {
OrganizationID uuid.UUID `gorm:"type:uuid"`
}
return tx.Migrator().AddColumn(&user{}, "OrganizationID")
},
Rollback: func(tx *gorm.DB) error {
type user struct {
OrganizationID uuid.UUID `gorm:"type:uuid"`
}
if err := db.Migrator().DropColumn(&user{}, "OrganizationID"); err != nil {
return err
}
return tx.Migrator().DropTable("organizations")
},
}})
if err := m.Migrate(); err != nil {
log.Fatalf("Migration failed: %v", err)
}
log.Println("Migration did run successfully")
}
初始化模式
如果你有很多迁移,在干净的数据库中部署新应用实例时运行所有迁移会很痛苦。为了防止这种情况,你可以设置一个函数,如果之前没有运行过任何迁移(在新的干净数据库中),该函数将运行。
type Organization struct {
gorm.Model
Name string
Address string
}
type User struct {
gorm.Model
Name string
Age int
OrganizationID uint
}
m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{
// 你的迁移在这里
})
m.InitSchema(func(tx *gorm.DB) error {
err := tx.AutoMigrate(
&Organization{},
&User{},
// 你应用的所有其他表
)
if err != nil {
return err
}
if err := tx.Exec("ALTER TABLE users ADD CONSTRAINT fk_users_organizations FOREIGN KEY (organization_id) REFERENCES organizations (id)").Error; err != nil {
return err
}
// 所有其他约束、索引等...
return nil
})
选项
这是选项结构体,如果你不想使用默认值:
type Options struct {
// TableName是迁移表
TableName string
// IDColumnName是存储迁移id的列名
IDColumnName string
// IDColumnSize是迁移id列的长度
IDColumnSize int
// UseTransaction使Gormigrate在单个事务中执行迁移
// 请注意并非所有数据库都支持事务中的DDL命令
UseTransaction bool
// ValidateUnknownMigrations如果数据库中有未知的迁移ID,会导致迁移失败
ValidateUnknownMigrations bool
}
Gormigrate适合谁?
Gormigrate是为使用Gorm的小型项目设计的简单和极简的迁移工具。如果你计划扩展,你可能想看看更高级的解决方案,如golang-migrate/migrate。
请注意,Gormigrate没有内置的锁机制,所以如果你自动运行它并且有分布式设置(即多个可执行文件同时运行),你可能想使用分布式锁/互斥机制来防止运行迁移时的竞争条件。
更多关于golang数据库模式迁移助手插件库gormigrate的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang数据库模式迁移助手插件库gormigrate的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Gormigrate - Golang数据库模式迁移助手
Gormigrate是一个用于Golang的数据库迁移库,专门为GORM设计。它可以帮助你管理数据库模式的变更,类似于Ruby on Rails的迁移或Django的migrations。
主要特性
- 基于GORM构建
- 支持事务性迁移
- 可以回滚迁移
- 迁移历史记录
- 支持初始化函数
- 简单的API设计
安装
go get -u github.com/go-gormigrate/gormigrate/v2
基本用法
1. 初始化Gormigrate
package main
import (
"log"
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
func main() {
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
m := gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{
// 在这里添加你的迁移
})
if err = m.Migrate(); err != nil {
log.Fatalf("Could not migrate: %v", err)
}
log.Printf("Migration did run successfully")
}
2. 创建迁移
每个迁移需要定义一个唯一的ID、Migrate函数和Rollback函数:
type User struct {
gorm.Model
Name string
Email string
}
// 创建users表的迁移
createUsersTable := &gormigrate.Migration{
ID: "202108010000", // 使用时间戳确保唯一性
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&User{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropTable("users")
},
}
// 添加age字段到users表
addAgeToUsers := &gormigrate.Migration{
ID: "202108010001",
Migrate: func(tx *gorm.DB) error {
// 检查字段是否已存在
if tx.Migrator().HasColumn(&User{}, "age") {
return nil
}
return tx.Migrator().AddColumn(&User{}, "Age")
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropColumn(&User{}, "Age")
},
}
3. 完整示例
package main
import (
"log"
"github.com/go-gormigrate/gormigrate/v2"
"gorm.io/gorm"
"gorm.io/driver/sqlite"
)
type User struct {
gorm.Model
Name string
Email string `gorm:"unique"`
Age int
}
func main() {
db, err := gorm.Open(sqlite.Open("mydb.db"), &gorm.Config{})
if err != nil {
log.Fatal(err)
}
// 设置迁移选项
options := &gormigrate.Options{
TableName: "migrations",
IDColumnName: "id",
IDColumnSize: 255,
UseTransaction: true,
}
// 初始化迁移
m := gormigrate.New(db, options, []*gormigrate.Migration{
// 初始迁移 - 创建users表
{
ID: "202108010000",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(&User{})
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropTable("users")
},
},
// 第二次迁移 - 添加age字段
{
ID: "202108010001",
Migrate: func(tx *gorm.DB) error {
if tx.Migrator().HasColumn(&User{}, "age") {
return nil
}
return tx.Migrator().AddColumn(&User{}, "Age")
},
Rollback: func(tx *gorm.DB) error {
return tx.Migrator().DropColumn(&User{}, "Age")
},
},
})
// 执行迁移
if err = m.Migrate(); err != nil {
log.Fatalf("Could not migrate: %v", err)
}
log.Println("Migration did run successfully")
}
高级用法
1. 初始化函数
你可以在第一次迁移前执行初始化代码:
m := gormigrate.New(db, options, []*gormigrate.Migration{
// 你的迁移
})
m.InitSchema(func(tx *gorm.DB) error {
// 初始化数据库模式
err := tx.AutoMigrate(&User{}, &Product{})
if err != nil {
return err
}
// 添加外键
if err := tx.Table("products").AddForeignKey("user_id", "users(id)", "RESTRICT", "RESTRICT").Error; err != nil {
return err
}
return nil
})
2. 回滚迁移
可以回滚到特定迁移:
// 回滚到特定迁移ID
err := m.RollbackTo("202108010000")
if err != nil {
log.Fatal(err)
}
// 回滚最后一步迁移
err := m.RollbackLast()
if err != nil {
log.Fatal(err)
}
3. 使用事务
默认情况下,Gormigrate会在事务中执行每个迁移。你可以通过选项控制:
options := &gormigrate.Options{
UseTransaction: true, // 默认为true
}
4. 自定义迁移表
可以自定义存储迁移历史的表名和列名:
options := &gormigrate.Options{
TableName: "custom_migrations",
IDColumnName: "migration_id",
IDColumnSize: 100,
}
最佳实践
- 迁移ID命名:使用时间戳格式(YYYYMMDDhhmmss)确保唯一性和顺序
- 幂等性:确保迁移可以安全地多次运行
- 小步迁移:每个迁移应该只做一件事
- 测试迁移:在生产环境运行前测试迁移和回滚
- 版本控制:将迁移文件纳入版本控制系统
Gormigrate是一个简单但功能强大的迁移工具,特别适合与GORM一起使用。它提供了数据库模式变更所需的基本功能,同时保持了API的简洁性。