1,倉庫地址:https://github.com/go-admin-team/go-admin.git 我拉取的是master分支,commit:c973d6819ceb008e0dfa97173ca3c69ce1cfd49a
創(chuàng)新互聯(lián)建站-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設、高性價比官渡網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式官渡網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設找我們,業(yè)務覆蓋官渡地區(qū)。費用合理售后完善,10多年實體公司更值得信賴。2,這里只分析migrate,go-admin的啟動命令使用cobra封裝(k8s也在用),那第一步就是定義migrate(遷移)指令并且掛載到根Command
import (
...
"go-admin/cmd/migrate"
...
)
func init() {
rootCmd.AddCommand(migrate.StartCmd)
...
}
3,migrate.StartCmd定義在cmd/migrate/server.go,因為go-admin是后臺腳手架,自帶了權(quán)限,菜單的管理,作者在定義遷移時,劃分兩種,你可以直接修改go-admin自帶的數(shù)據(jù)模型,也可以自定義模型,詳見代碼注釋
// 我只保留核心邏輯的代碼
import (
...
_ "go-admin/cmd/migrate/migration/version" // 系統(tǒng)自帶的遷移目錄
_ "go-admin/cmd/migrate/migration/version-local" // 自定義遷移目錄
...
)
var (
configYml string // 配置文件
// ./go-admin migrate -g=true -a=false
generate bool // 生成自定義遷移文件
goAdmin bool // 生成go-admin初始遷移
host string // 域, 為什么會有一個域?一個域代表的是一個key,作者是希望支持多庫的,目前 我對多庫的處理是在 ApplicationConfig中新增了一個Database2
...
)
...
func run() {
if !generate { // 默認false,先生成后執(zhí)行
fmt.Println(`start init`)
//1. 讀取配置
config.Setup(
file.NewSource(file.WithPath(configYml)),
initDB,
)
} else {
fmt.Println(`generate migration file`)
_ = genFile() // 生成配置文件
}
}
func migrateModel() error {
if host == "" {
host = "*"
}
db := sdk.Runtime.GetDbByKey(host) // 取庫
if config.DatabasesConfig[host].Driver == "mysql" {
//初始化數(shù)據(jù)庫時候用
db.Set("gorm:table_options", "ENGINE=InnoDB CHARSET=utf8mb4")
}
err := db.Debug().AutoMigrate(&models.Migration{}) // 遷移庫,維護了一個遷移庫來記錄遷移,根據(jù)版本信息,來確定是否執(zhí)行這次遷移
if err != nil {
return err
}
migration.Migrate.SetDb(db.Debug()) // 設置 DB
migration.Migrate.Migrate() // 執(zhí)行遷移
return err
}
func initDB() {
//3. 初始化數(shù)據(jù)庫鏈接
database.Setup()
//4. 數(shù)據(jù)庫遷移
fmt.Println("數(shù)據(jù)庫遷移開始")
_ = migrateModel()
fmt.Println(`數(shù)據(jù)庫基礎(chǔ)數(shù)據(jù)初始化成功`)
}
func genFile() error {
t1, err := template.ParseFiles("template/migrate.template") // 解讀模版文件
if err != nil {
return err
}
m := map[string]string{}
m["GenerateTime"] = strconv.FormatInt(time.Now().UnixNano()/1e6, 10)
m["Package"] = "version_local"
// goAdmin 區(qū)分是 系統(tǒng)級遷移還是自定義的遷移
if goAdmin {
m["Package"] = "version"
}
var b1 bytes.Buffer
err = t1.Execute(&b1, m) // map 映射到模版文件并寫入buffer
if goAdmin {
pkg.FileCreate(b1, "./cmd/migrate/migration/version/"+m["GenerateTime"]+"_migrate.go")
} else {
pkg.FileCreate(b1, "./cmd/migrate/migration/version-local/"+m["GenerateTime"]+"_migrate.go")
}
return nil
}
3,再有的核心就是在version和version-local了
...
// version, version-local 是一樣的邏輯,都是用init觸發(fā)的
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), _1599190683659Tables) // SetVersion是將當前版本加入到遷移數(shù)組當中
}
// 遷移函數(shù)
func _1599190683659Tables(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
if config.DatabaseConfig.Driver == "mysql" {
tx = tx.Set("gorm:table_options", "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4")
}
err := tx.Migrator().AutoMigrate(
new(models.SysDept)
...
)
if err != nil {
return err
}
if err := models.InitDb(tx); err != nil {
return err
}
return tx.Create(&common.Migration{
Version: version, // 這里就是要增加當前遷移的版本信息了
}).Error
})
}
4,上面是定義好了遷移的實體方法,我們來看一下調(diào)用方式
package migration
import (
"log"
"path/filepath"
"sort"
"sync"
"gorm.io/gorm"
)
var Migrate = &Migration{
version: make(map[string]func(db *gorm.DB, version string) error),
}
// 遷移的必要元素
type Migration struct {
db *gorm.DB // 指定的庫
version map[string]func(db *gorm.DB, version string) error // 每個版本信息對應的遷移函數(shù),就是上面那串時間戳函數(shù)
mutex sync.Mutex
}
...
// 這就是上面的代碼init中,將version信息和遷移函數(shù)做了綁定
func (e *Migration) SetVersion(k string, f func(db *gorm.DB, version string) error) {
e.mutex.Lock()
defer e.mutex.Unlock()
e.version[k] = f // 給指定版本綁定遷移函數(shù)
}
// 真正執(zhí)行遷移的地方
func (e *Migration) Migrate() {
versions := make([]string, 0)
for k := range e.version {
versions = append(versions, k)
}
if !sort.StringsAreSorted(versions) {
sort.Strings(versions)
}
var err error
var count int64
// versions 是什么意思?只要是包含在version和version-local目錄的init方法內(nèi)的,都會加入到versions
// 然后去庫里匹配version,匹配不到即將遷移的版本信息的,則開始執(zhí)行對應的遷移函數(shù)
for _, v := range versions {
err = e.db.Table("sys_migration").Where("version = ?", v).Count(&count).Error
if err != nil {
log.Fatalln(err)
}
if count >0 { // 有這個版本跳出
log.Println(count)
count = 0
continue
}
err = (e.version[v])(e.db.Debug(), v) // 這是遷移函數(shù)
if err != nil {
log.Fatalln(err)
}
}
}
func GetFilename(s string) string {
s = filepath.Base(s)
return s[:13] // 取名字,這也是setVersion的第一個參數(shù)
}
5,有一張記錄遷移信息的表
只有version和apply_time兩個字段
6,完。
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
當前文章:go-admin數(shù)據(jù)庫遷移代碼分析-創(chuàng)新互聯(lián)
轉(zhuǎn)載來源:http://muchs.cn/article6/cochog.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供企業(yè)建站、網(wǎng)站營銷、軟件開發(fā)、網(wǎng)站內(nèi)鏈、企業(yè)網(wǎng)站制作、定制網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容