Go 語言編程 — gorm 數據庫版本遷移
目錄
文章目錄
目錄
前言
AutoMigrate
示例
Migrator 接口(DDL 操作方法)
表操作
列操作
約束操作
索引操作
數據庫版本控制
參考文檔
前言
本文示例為 GORM V2.0 版本。
AutoMigrate
GORM 的 AutoMigrate() 方法用于自動遷移 ORM 的 Schemas。所謂 “遷移” 就是刷新數據庫中的表格定義,使其保持最新(只增不減)。
AutoMigrate 會創建(新的)表、缺少的外鍵、約束、列和索引,并且會更改現有列的類型(如果其大小、精度、是否為空可更改的話)。但不會刪除未使用的列,以保護現存的數據。
// 初始化一張表 db.AutoMigrate(&User{}) // 初始化多張表 db.AutoMigrate(&User{}, &Product{}, &Order{}) // 創建表的同時進行表屬性配置 db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})
1
2
3
4
5
6
7
8
在 2.0 版本中,AutoMigrate 還會自動創建數據庫表的約束,包括:外鍵約束。這在 1.9 版本中,則需要顯示的通過 sql tag 來完成。
2.0 還支持在初始化時禁用此功能:
db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{ DisableForeignKeyConstraintWhenMigrating: true, })
1
2
3
示例
以 SQLite 數據庫存儲為例。
V1 Schema
type Product struct { gorm.Model Code string Price string } // 初始化 V1 db.AutoMigrate(&Product{})
1
2
3
4
5
6
7
8
其在數據庫的存儲格式為:
V2 Schema:新增了一個 Age 字段
type Product struct { gorm.Model Code string Price string Age string } // 更新 V2 db.AutoMigrate(&Product{})
1
2
3
4
5
6
7
8
9
數據庫會自動為 products 表新增 age 列,舊數據記錄的 age 列值為空(NULL),新數據記錄的 age 列值可以不為空:
V3 Schema:刪除了 Price 和 Age 字段
type Product struct { gorm.Model Code string } // 更新 V3 db.AutoMigrate(&Product{})
1
2
3
4
5
6
7
數據庫不會自動為 products 表刪減 price 和 age 列,舊數據記錄依舊存在且可以使用,新數據紀錄的 price 和 age 的列值為空(NULL):
Migrator 接口(DDL 操作方法)
如果 AutoMigrate 還不足以滿足特殊的需求,那么 GORM 還提供了 Migrator 接口,可用來為 ORM Schemas 實現自定義的遷移邏輯。
Migrator 還為不同類型的數據庫提供了統一的 API 抽象,例如:SQLite 不支持 ALTER COLUMN、DROP COLUMN 等 SQL 子句,所以當我們調用 Migrator API 試圖修改表結構時,GORM 會自定為在 SQLite 創建一張新表、并復制所有數據,然后刪除舊表、重命名新表。
再例如:舊版本的 MySQL 不支持 rename 列、索引,GORM 也會基于當前的 MySQL 的版本執行不同 SQL。
type Migrator interface { // AutoMigrate AutoMigrate(dst ...interface{}) error // Database CurrentDatabase() string FullDataTypeOf(*schema.Field) clause.Expr // Tables CreateTable(dst ...interface{}) error DropTable(dst ...interface{}) error HasTable(dst interface{}) bool RenameTable(oldName, newName interface{}) error // Columns AddColumn(dst interface{}, field string) error DropColumn(dst interface{}, field string) error AlterColumn(dst interface{}, field string) error HasColumn(dst interface{}, field string) bool RenameColumn(dst interface{}, oldName, field string) error MigrateColumn(dst interface{}, field *schema.Field, columnType *sql.ColumnType) error ColumnTypes(dst interface{}) ([]*sql.ColumnType, error) // Constraints CreateConstraint(dst interface{}, name string) error DropConstraint(dst interface{}, name string) error HasConstraint(dst interface{}, name string) bool // Indexes CreateIndex(dst interface{}, name string) error DropIndex(dst interface{}, name string) error HasIndex(dst interface{}, name string) bool RenameIndex(dst interface{}, oldName, newName string) error }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
表操作
// 為 `User` 創建表 db.Migrator().CreateTable(&User{}) // 將 "ENGINE=InnoDB" 添加到創建 `User` 的 SQL 里去 db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&User{}) // 檢查 `User` 對應的表是否存在 db.Migrator().HasTable(&User{}) db.Migrator().HasTable("users") // 如果存在表則刪除(刪除時會忽略、刪除外鍵約束) db.Migrator().DropTable(&User{}) db.Migrator().DropTable("users") // 重命名表 db.Migrator().RenameTable(&User{}, &UserInfo{}) db.Migrator().RenameTable("users", "user_infos")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
列操作
type User struct { Name string } // 添加 name 字段 db.Migrator().AddColumn(&User{}, "Name") // 刪除 name 字段 db.Migrator().DropColumn(&User{}, "Name") // 修改 name 字段 db.Migrator().AlterColumn(&User{}, "Name") // 檢查字段是否存在 db.Migrator().HasColumn(&User{}, "Name") type User struct { Name string NewName string } // 重命名字段 db.Migrator().RenameColumn(&User{}, "Name", "NewName") db.Migrator().RenameColumn(&User{}, "name", "new_name") // 獲取字段類型 db.Migrator().ColumnTypes(&User{}) ([]*sql.ColumnType, error)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
約束操作
包括基本的數據完整性約束類型。
type UserIndex struct { Name string `gorm:"check:name_checker,name <> 'jinzhu'"` } // 創建約束 db.Migrator().CreateConstraint(&User{}, "name_checker") // 刪除約束 db.Migrator().DropConstraint(&User{}, "name_checker") // 檢查約束是否存在 db.Migrator().HasConstraint(&User{}, "name_checker")
1
2
3
4
5
6
7
8
9
10
11
12
索引操作
type User struct { gorm.Model Name string `gorm:"size:255;index:idx_name,unique"` } // 為 Name 字段創建索引 db.Migrator().CreateIndex(&User{}, "Name") db.Migrator().CreateIndex(&User{}, "idx_name") // 為 Name 字段刪除索引 db.Migrator().DropIndex(&User{}, "Name") db.Migrator().DropIndex(&User{}, "idx_name") // 檢查索引是否存在 db.Migrator().HasIndex(&User{}, "Name") db.Migrator().HasIndex(&User{}, "idx_name") type User struct { gorm.Model Name string `gorm:"size:255;index:idx_name,unique"` Name2 string `gorm:"size:255;index:idx_name_2,unique"` } // 修改索引名 db.Migrator().RenameIndex(&User{}, "Name", "Name2") db.Migrator().RenameIndex(&User{}, "idx_name", "idx_name_2")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
數據庫版本控制
需要注意的是,GORM 雖然提供了不錯的數據庫遷移功能,但是距離理想的 “版本控制” 仍有距離。不支持,包括:版本記錄、版本回退、版本選擇。這些都需要開發者自行封裝。
參考文檔
https://gorm.io/zh_CN/docs/migration.html
https://davidchan0519.github.io/2019/05/06/gorm-automigrate/
Go 數據庫
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。