跳转到内容

迁移 ​

简介 ​

当多人协作开发应用程序时,如果同步数据库结构没有一个统一的规范,以保证所有人的本地数据都是一致的,那将是灾难。数据库迁移就是为了解决这个问题,将数据库的结构进行版本控制,以保证所有开发人员的数据库结构的一致性。 不这样做,就可能出现混乱,因为每个人的数据都不会匹配。 数据库迁移 将数据库的结构进行版本控制,以保证所有开发人员的数据库结构的一致性。

配置 ​

数据库迁移文件存放在 database/migrations 目录下。 你可以在 config/database.go 文件中配置数据库连接信息。

go
"migrations": map[string]any{
  // You can cumstomize the table name of migrations
  "table":  "migrations",
},

生成迁移 ​

使用 make:migration 命令来创建迁移:

shell
./artisan make:migration
./artisan make:migration create_users_table

该命令会在 database/migrations 目录下生成迁移文件。 所有迁移文件都以一个时间戳为开头,Goravel 将以此作为迁移文件的执行顺序。

你还可以通过使用 -m 或 --model 选项为特定模型创建迁移:

shell
./artisan make:migration create_users_table -m User

该模型应在运行命令之前在 bootstrap/app.go 文件中进行注册。 此命令将根据 User 模型中定义的结构生成一个迁移文件。

go
func Boot() contractsfoundation.Application {
  return foundation.Setup().
    WithConfig(config.Boot).
    WithCallback(func() {
      facades.Schema().Extend(schema.Extension{
        Models: []any{models.User{}},
      })
    }).
    Create()
}

快捷生成 ​

使用 create_users_table 将会自动生成包含 users 基础结构的表,实现原理是根据正则进行匹配:

^create_(\w+)_table$
^create_(\w+)$

使用 add_avatar_to_users_table 将会自动生成向 users 表增加字段的结构,实现原理是根据正则进行匹配:

_(to|from|in)_(\w+)_table$
_(to|from|in)_(\w+)$

未匹配到上述情况时,框架会生成一个空的迁移文件。

迁移结构 ​

Go 语言迁移 ​

迁移类包含两个方法:Up 和 Down。 Up 方法用于向数据库中添加新表、列或索引,而 Down 方法用于撤销 Up 方法执行的操作。 在这两种方法中,可以使用 facades.Schema() 来创建和操作数据库表。 可用方法详见文档。 以下迁移会创建一个 users 表:

go
package migrations

import (
	"github.com/goravel/framework/contracts/database/schema"
	
  "goravel/app/facades"
)

type M20241207095921CreateUsersTable struct {
}

// Signature The unique signature for the migration.
func (r *M20241207095921CreateUsersTable) Signature() string {
	return "20241207095921_create_users_table"
}

// Up Run the migrations.
func (r *M20241207095921CreateUsersTable) Up() error {
	if !facades.Schema().HasTable("users") {
		return facades.Schema().Create("users", func(table schema.Blueprint) {
			table.ID()
			table.String("name").Nullable()
			table.String("email").Nullable()
			table.Timestamps()
		})
	}

	return nil
}

// Down Reverse the migrations.
func (r *M20241207095921CreateUsersTable) Down() error {
	return facades.Schema().DropIfExists("users")
}

设置迁移连接 ​

如果迁移将与应用程序默认数据库连接以外的数据库连接进行交互,你可以使用迁移的 Connection 方法:

go
func (r *M20241207095921CreateUsersTable) Connection() string {
  return "connection-name"
}

注册迁移 ​

通过 make:migration 创建的新迁移将自动注册到 bootstrap/migrations.go::Migrations() 函数中,并且该函数将由 WithMigrations 调用。 如果你自行创建迁移文件,则需要手动注册。

go
func Boot() contractsfoundation.Application {
	return foundation.Setup().
		WithMigrations(Migrations).
		WithConfig(config.Boot).
		Create()
}

执行迁移 ​

执行 Artisan 命令 migrate,来运行所有未执行过的迁移:

shell
./artisan migrate

如果你想查看目前的迁移状态,可以使用 migrate:status Artisan 命令:

shell
./artisan migrate:status

回滚迁移 ​

要回滚最新的迁移批次,请使用 rollback Artisan 命令:

shell
./artisan migrate:rollback

如果要回滚多个迁移批次,可以指定 batch 选项,数字表示要回滚的批次:

shell
./artisan migrate:rollback --batch=2

通过向 rollback 命令加上 step 参数,可以回滚指定数量的迁移。 例如,以下命令将回滚最后五个迁移:

shell
./artisan migrate:rollback --step=5

命令 migrate:reset 会回滚应用已运行过的所有迁移:

shell
./artisan migrate:reset

使用单个命令同时进行回滚和迁移操作 ​

命令 migrate:refresh 首先会回滚已运行过的所有迁移,随后会执行 migrate。 这一命令可以高效地重建你的整个数据库:

shell
./artisan migrate:refresh

通过在命令 refresh 中使用 step 参数,你可以回滚并重新执行指定数量的迁移操作。 例如,下列命令会回滚并重新执行最后五个迁移操作:

shell
./artisan migrate:refresh --step=5

删除所有表然后执行迁移 ​

命令 migrate:fresh 会删去数据库中的所有表,随后执行命令 migrate:

shell
./artisan migrate:fresh

Tables ​

创建表 ​

go
facades.Schema().Create("users", func(table schema.Blueprint) {
  table.ID()
  table.String("name").Nullable()
  table.String("email").Nullable()
  table.Timestamps()
})

检查表 / 列是否存在 ​

go
if facades.Schema().HasTable("users") {}
if facades.Schema().HasColumn("users", "email") {}
if facades.Schema().HasColumns("users", []string{"name", "email"}) {}
if facades.Schema().HasIndex("users", "email_unique") {}

数据库连接 ​

go
facades.Schema().Connection("sqlite").Create("users", func(table schema.Blueprint) {
  table.ID()
})

更新表 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.String("name").Nullable()
})

重命名字段 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.RenameColumn("old_name", "new_name")
})

添加表注释 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.Comment("user table")
})

重命名 / 删除表 ​

go
facades.Schema().Rename("users", "new_users")
facades.Schema().Drop("users")
facades.Schema().DropIfExists("users")

字段 ​

可用的字段类型 ​

布尔类型 ​

Boolean

字符串 & 文本类型 ​

Char, Json, LongText, MediumText, String, Text, LongText, TinyText, Uuid, Ulid

数字类型 ​

BigIncrements, BigInteger, Decimal, Double, Float, ID, Increments, Integer, IntegerIncrements, MediumIncrements, MediumInteger, SmallIncrements, SmallInteger, TinyIncrements, TinyInteger, UnsignedBigInteger, UnsignedInteger, UnsignedMediumInteger, UnsignedSmallInteger, UnsignedTinyInteger

日期 & 时间类型 ​

Date, DateTime, DateTimeTz, SoftDeletes, SoftDeletesTz, Time, TimeTz, Timestamp, TimestampTz, Timestamps, TimestampsTz

其他类型 ​

Enum, Morphs, NullableMorphs, NumericMorphs, UuidMorphs, UlidMorphs

Enum ​

创建一个 Enum 字段,该字段在 Mysql 中可以根据 []any 中的类型进行储存,但在 Postgres, Sqlite 和 Sqlserver 数据库中都是 String 类型。

go
table.Enum("difficulty", []any{"easy", "hard"})
table.Enum("num", []any{1, 2})

ID ​

ID 方法是 BigIncrements 方法的别名。 默认情况下,该方法将创建一个 id 列;但是,如果你想要为该列分配一个不同的名称,可以传递一个列名称:

go
table.ID()
table.ID("user_id")

SoftDeletes ​

SoftDeletes 方法添加了一个可以为空的 deleted_at TIMESTAMP 列。 SoftDeletes 方法添加了一个可以为空的 deleted_at TIMESTAMP 列。此列旨在存储 Orm 「软删除」功能所需的 deleted_at 时间戳:

go
table.SoftDeletes()

自定义字段 ​

如果你正在使用框架尚不支持的字段类型,可以通过 Column 方法自定义字段类型:

go
table.Column("geometry", "geometry")

列修饰符 ​

除了上面列出的列类型之外,当给数据库表添加一个列时,你还可以给列添加「修饰符」。 除了上面列出的列类型之外,当给数据库表添加一个列时,你还可以给列添加「修饰符」。例如,要使列可以「为空」,你可以使用 Nullable 方法:

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.String("name").Nullable()
})

以下表格包含所有可用的列修饰符:

修饰符描述
.Always()该列的值始终由数据库系统自动生成,用户不能直接插入或修改(仅限 PostgreSQL)
.AutoIncrement()设置整数列为自动增长的(主键)
.After("column")将列设置为指定列之后(适用于 MySQL)
.Comment("my comment")向列添加注释(MySQL / PostgreSQL)
.Change()修改列(MySQL / PostgreSQL / Sqlserver)
.Default(value)为列指定「默认」值
.First()将列设置为表的第一个字段(适用于 MySQL)
.GeneratedAs()设置列的值由数据库系统自动生成(仅限 PostgreSQL)
.Nullable()允许插入 NULL 值到列中
.Unsigned()设置整数列为 UNSIGNED(仅限 MySQL)
.UseCurrent()设置时间戳列使用 CURRENT_TIMESTAMP 作为默认值
.UseCurrentOnUpdate()设置记录更新时,时间戳列使用 CURRENT_TIMESTAMP(仅限 MySQL)

删除列 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.DropColumn("name")
  table.DropColumn("name", "age")
})

索引 ​

创建索引 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  // 添加主键
  table.Primary("id")
  // 添加复合主键
  table.Primary("id", "name")

  // 添加唯一索引
  table.Unique("name")
  table.Unique("name", "age")

  // 添加普通索引
  table.Index("name")
  table.Index("name", "age")

  // 添加全文索引
  table.FullText("name")
  table.FullText("name", "age")
})

重命名索引 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.RenameIndex("users_name_index", "users_name")
})

删除索引 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.DropPrimary("id")
  table.DropUnique("name")
  table.DropUniqueByName("name_unique")
  table.DropIndex("name")
  table.DropIndexByName("name_index")
  table.DropFullText("name")
  table.DropFullTextByName("name_fulltext")
})

外键约束 ​

go
facades.Schema().Table("posts", func(table schema.Blueprint) {
  table.UnsignedBigInteger("user_id")
  table.Foreign("user_id").References("id").On("users")
})

删除外键 ​

go
facades.Schema().Table("users", func(table schema.Blueprint) {
  table.DropForeign("user_id")
  table.DropForeignByName("user_id_foreign")
})

基于 MIT 许可发布