go-admin migrate 数据表迁移
nav:
title: 指令
order: 3
title: migrate
order: 10
toc: content
视频教程
【go-admin-pro】如何优雅的数据迁移?migrate 指令
【go-admin-pro】数据迁移 migrate 指令常见的问题说明
应用场景
- 迁移新表
- 变更表字段,表字段的新增、删除、修改
- 预置表数据
目录说明
注意:
迁移关联数据时,如果有外键约定,需要先执行写入表数据,再执行写入关系数据,不然会报错,注意迁移时插入数据的顺序
├── migration
│ ├── init.go # 迁移类
│ ├── models #迁移模型 (go-admin系统已开发过的功能)
│ ├── version-local # 新开发迁移文件 大家在这里开发
│ └── version #go-admin系统系统迁移文件 (已开发过的功能 不要动这里的文件,以免影响后面升级)
│ ├── 1599190683659_tables_tables.go # 迁移表
│ ├── 1653638869132_migrate.go # 迁移预置数据
│ └── doc.go # 预置数据
└── server.go # cobra.Command 命令行文件
数据迁移
在开发过程中经常会遇到数据库字段的变更和基础数据的变更,go-admin
提供了对应的迁移工具;
首先需要将在项目根目录下执行go build
将程序编译:
go build
执行go-admin migrate
指令,可以进行数据迁移;
首次使用时可以使用-h
查看帮助信息;
$ ./go-admin migrate -h
Initialize the database
Usage:
go-admin migrate [flags]
Examples:
go-admin migrate -c config/settings.yml
Flags:
-c, --config string Start server with provided configuration file (default "config/settings.yml")
-d, --domain string select tenant host (default "*")
-g, --generate generate migration file
-a, --goAdmin generate go-admin migration file
-h, --help help for migrate
迁移步骤
- 配置数据库配置
- 生成迁移文件
- 修改迁移文件
- 创建迁移模型
- 执行迁移命令
配置数据库
修改配置文件里数据库链接信息(database
)
config/settings.dev.yml
常用命令示例
go run main.go migrate -h # 帮助
go run main.go migrate -g true -a true -c config/settings.dev.yml # 生成 go-admin系统预置 迁移文件
go run main.go migrate -g true -c config/settings.dev.yml # 生成 自定义功能 迁移文件 自己开发新功能用这个功能
go run main.go migrate -c config/settings.dev.yml # 执行迁移命令 迁移 未迁移过的 文件
参数说明:
-h # 帮助
-c # 指定配置文件 默认使用 -c config/settings.yml 配置文件
-a # 生成 系统预置 迁移文 生成到` cmd/migrate/migration/version ` go-admin系统迁移文件在这目录里操作,最好不要动,方便同步升级
-g # 生成迁移文 生成到` cmd/migrate/migration/version-local ` 自己开发新功能的迁移文件在这目录里操作
新建模型实例
- 生成迁移文件
首先执行,
$ go run main.go migrate -a true -g true
generate migration file
完成后,我们打开cmd/migrate/migration/version
目录,这时里边已经为您新添加了一个迁移文件1654233005297_migrate.go
(一般会在最下边):
提示:
迁移文件名版本号不要修改,后面的名称可以随便修改为有语意的名称,方便后续维护迁移文件。
例 1654233005297_migrate.go
修改为 1654233005297_CreateTable_TbDemoTest.go
,见名知意,创建tb_demo_test
表
打开文件,我们打开看一下
package version
import (
"gorm.io/gorm"
"runtime"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), _1654233005297Test)
}
func _1654233005297Test(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
// TODO: 这里开始写入要变更的内容
// TODO: 例如 修改表字段 使用过程中请删除此段代码
//err := tx.Migrator().RenameColumn(&models.SysConfig{}, "config_id", "id")
//if err != nil {
// return err
//}
// TODO: 例如 新增表结构 使用过程中请删除此段代码
//err = tx.Migrator().AutoMigrate(
// new(models.CasbinRule),
// )
//if err != nil {
// return err
//}
return tx.Create(&common.Migration{
Version: version,
}).Error
})
}
- 接下来只要按照文件里边的代码提示编写即可。
package version
import (
"go-admin/cmd/migrate/migration/models"
"gorm.io/gorm"
"runtime"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), _1654233005297Test)
}
func _1654233005297Test(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
// TODO: 这里开始写入要迁移的表构型
err := tx.Debug().Migrator().AutoMigrate(
new(models.TbDemoTest1654233005297),
)
if err != nil {
//如果错误就报错,停止迁移
return err
}
return tx.Create(&common.Migration{
Version: version,
}).Error
})
}
// TbDemoTest表模型 建议带上版本号和生成文件名前缀一致
type TbDemoTest1654233005297 struct {
models.Model
Name string `json:"name" gorm:"type:varchar(128);comment:名称"`
models.ModelTime
models.ControlBy
}
func (TbDemoTest1654233005297) TableName() string {
return "tb_demo_test" # 指定表名
}
上边我们给出了一个简单的struct
,包含的有Model
、ModelTime
、ControlBy
和Name
属性;
其中Model
、ModelTime
、ControlBy
是 go-admin
默认需要添加的基本属性,Name
是业务属性;
另外还需要定义一个TableName()
的func
用来设置我们的表名称;
- 执行迁移。
:::warning
温馨提醒,请认真阅读
数据库操作建议做好检查确认脚本,另外确认完成 cmd/migrate/migration/version
目录中只有新建的文件没有被执行过(已迁移过的文件,不会再次迁移),
因为执行迁移指令的过程中,系统会检查没有执行过的迁移脚本(sys_migration 表中 version 字段里值和 cmd/migrate/migration/version
目录中的文件对比),
将未执行的脚本全部执行;迁移前做好数据备份
当然,相反如果迁移过的文件,想要再次迁移,也可删除 sys_migration 表中对应版本信息的那条记录,即可以再次执行迁移文件(调适时可以试试,呵呵)。
:::
3.1 方式一:不编译运行(推荐)
注意:
不带 -c config/settings.dev.yml
默认使用 -c config/settings.yml
配置文件
# 执行迁移
$ go run main.go migrate -c config/settings.dev.yml
3.2 方式二:编译并运行迁移
# 不推荐,每次修改迁移文件后,都需要 go build 重新编译,容易忘记编译,掉进坑里,嘿嘿。。。
$ go build
$ ./go-admin migrate -c config/settings.dev.yml # mac /linux执行命令
$ ./go-admin.exe migrate -c config/settings.dev.yml # windows执行命令
# 注意:sqlite 需要加 -tags=sqlite3.json1参数
$ go run -tags=sqlite3,json1 main.go migrate
3.3 方式三:golangIDE
运行
golangIDE
还要可以进行 debug 断点调适迁移文件,(推荐)
migrate -c config/settings.dev.93.yml -g true -g true
执行成功后检查数据库的对应信息,和预期一样就迁移成功,会生成tb_demo_test
表。
更新模型实例
我们以修改字段名称为例:
- 生成迁移文件
首先执行,
$ go run main.go migrate -c config/settings.dev.yml
注意:sqlite 需要加 -tags=sqlite3.json1参数
$ go run -tags=sqlite3,json1 main.go migrate -c config/settings.dev.yml
完成后,我们打开cmd/migrate/migration/version
目录,这时里边已经为您新添加了一个迁移文件1660151543503_migrate
(一般会在最下边),我们打开看一下:
例 1660151543503_migrate.go
修改为 1660151543503_editeColumns_TbDemoTest.go
,见名知意,修改表tb_demo_test
字段
package version
import (
"gorm.io/gorm"
"runtime"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), _1660151543503Test)
}
func _1660151543503Test(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
// TODO: 这里开始写入要变更的内容
// TODO: 例如 修改表字段 使用过程中请删除此段代码
//err := tx.Migrator().RenameColumn(&models.SysConfig{}, "config_id", "id")
//if err != nil {
// return err
//}
// TODO: 例如 新增表结构 使用过程中请删除此段代码
//err = tx.Migrator().AutoMigrate(
// new(models.CasbinRule),
// )
//if err != nil {
// return err
//}
return tx.Create(&common.Migration{
Version: version,
}).Error
})
}
- 修改迁移脚本
接下来只要按照文件里边的提示修改代码即可。
修改表字段更多操作参考gorm
官网
https://gorm.io/zh_CN/docs/models.html
package version
import (
"gorm.io/gorm"
"runtime"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), _1660151543503Test)
}
func _1660151543503Test(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
// 修改表字段 第二个参数标明需要修改的字段名 desc和mysql表里的字段名称一致
err := tx.Migrator().AlterColumn(&TbDemoTest1660151543503{}, "name")
if err != nil {
return err
}
// 添加表字段 第二个参数标明需要修改的字段名 desc和mysql表里的字段名称一致
err = tx.Migrator().AddColumn(&TbDemoTest1660151543503{}, "desc")
if err != nil {
return err
}
// 删除表字段 第二个参数标明需要修改的字段名 desc和mysql表里的字段名称一致
err = tx.Migrator().DropColumn(&TbDemoTest1660151543503{}, "desc")
if err != nil {
return err
}
return tx.Create(&common.Migration{
Version: version,
}).Error
})
}
// TbDemoTest表模型 这里建议带上版本号和生成文件名前缀一致
type TbDemoTest1660151543503 struct {
models.Model
Name string `json:"name" gorm:"type:varchar(128);comment:名称"`
Desc string `json:"desc" gorm:"type:varchar(255);comment:描述"` //需要添加的字段
models.ModelTime
models.ControlBy
}
func (TbDemoTest1660151543503) TableName() string {
return "tb_demo_test" # 指定表名
}
- 执行迁移
$ go run main.go migrate -c config/settings.dev.yml
注意:sqlite 需要加 -tags=sqlite3.json1参数
$ go run -tags=sqlite3,json1 main.go migrate -c config/settings.dev.yml
执行成功后检查数据库的对应信息,查看tb_demo_test
表,验证字段变化,和预期一样就迁移成功了。
预置表数据
思路:
按行读取sql
语句,写入mysql
表
sql
语句可以先导入 mysql 表,再使用navicat
导出插入语句
Q:为什么表里已经数据了,还要做迁移文件,写入数据?
上正式环境时,运维人员需要迁移数据。
- 生成迁移文件
首先执行,
$ go run main.go migrate -a true -g true
generate migration file
完成后,我们打开cmd/migrate/migration/version
目录,这时里边已经为您新添加了一个迁移文件1668407576412_migrate.go
(一般会在最下边):
提示:
迁移文件名版本号不要修改,后面的名称可以随便修改为有语意的名称,方便后续维护迁移文件。
例 1668407576412_migrate.go
修改为 1668407576412_insertSql_TbDemoTest.go
,见名知意,tb_demo_test
表插入数据
- 修改迁移文件
package version
import (
"bufio"
"errors"
"fmt"
"gorm.io/gorm"
"io"
"log"
"os"
"path"
"runtime"
"strings"
"go-admin/cmd/migrate/migration"
common "go-admin/common/models"
)
func init() {
_, fileName, _, _ := runtime.Caller(0)
migration.Migrate.SetVersion(migration.GetFilename(fileName), _1668407576412Test)
}
// 写入数据的sql文件所在路径
const db1668407576412Path = "cmd/migrate/migration/version/1668407576412_insertSqlTbDemoTest.sql"
func _1668407576412Test(db *gorm.DB, version string) error {
return db.Transaction(func(tx *gorm.DB) error {
filePath := db1668407576412Path
ext := path.Ext(filePath)
if ext != ".sql" {
errMsg := fmt.Sprintf("file ext is not sql. filePath:%s", filePath)
return errors.New(errMsg)
}
fileContentSlice, err := ReadFileContentWithLine(filePath)
if err != nil {
errMsg := fmt.Sprintf("read sql file error:%s ,filePath:%s", err.Error(), filePath)
log.Println(errMsg)
return errors.New(errMsg)
}
if len(fileContentSlice) < 0 {
errMsg := fmt.Sprintf("read sql content[%s] content is empty", filePath)
log.Println(errMsg)
return errors.New(errMsg)
}
for _, sqlStr := range fileContentSlice {
if len(strings.TrimSpace(sqlStr)) < 1 {
continue
}
res := tx.Exec(sqlStr)
if res.Error != nil {
fmt.Printf("insert failed, errorSql:%v\n", sqlStr)
}
}
return tx.Create(&common.Migration{
Version: version,
}).Error
})
}
func ReadFileContentWithLine(filePath string) (data []string, err error) {
file, err := os.Open(filePath)
if err != nil {
return
}
defer file.Close()
scanner := bufio.NewReader(file)
for {
line, _, err := scanner.ReadLine()
if err != nil {
if err == io.EOF {
break
}
}
if len(line) > 0 {
data = append(data, string(line))
}
}
return
}
- 准备
sql
文件
使用navicat
等工具从表中导出需要预置的数据
导出表里所有数据
想导出哪张表,就勾选哪张表,选择文件保存位置 , 下一步
开始导出
放在 cmd/migrate/migration/version/1668407576412_insertSqlTbDemoTest.sql
目标下, 文件名改为和迁移文件名一致,方便管理
以供上面迁移文件读取
INSERT INTO tb_demo (`id`, `name`, `created_at`, `updated_at`, `deleted_at`, `create_by`, `update_by`) VALUES (1, '张三', '2022-11-20 16:59:41.000', '2022-11-26 16:59:47.000', '2022-11-25 16:59:50.000', 1, 1);
INSERT INTO tb_demo (`id`, `name`, `created_at`, `updated_at`, `deleted_at`, `create_by`, `update_by`) VALUES (2, '李四', '2022-11-20 16:59:41.000', '2022-11-26 16:59:47.000', '2022-11-25 16:59:50.000', 1, 1);
- 执行迁移
$ go run main.go migrate -c config/settings.dev.yml
注意:sqlite 需要加 -tags=sqlite3.json1参数
$ go run -tags=sqlite3,json1 main.go migrate -c config/settings.dev.yml
扩展:
如果有多个 sql 文件,可以修改上面的文件,把文件路径改为数组,循环读取文件,执行数据写入。到此结束。
感谢大家对 go-admin 的支持,希望大家多多点 star,多多推荐本项目。
go-admin migrate 数据表迁移的更多相关文章
- Flyway数据表迁移框架的使用
目录 1. 概述 2. Maven配置 3. SQL文件规范 4. 命令 5. 总结 1. 概述 Flyway是一个根据表结构快速生成数据表的工具,类似于Hibernate的自动生成表的特性. 官网: ...
- 使用navicat进行数据表迁移
使用navicat进行数据和表迁移只需要复制,粘贴就可以实现.
- 针对数据量较大的表,需要进行跨库复制,采用navcat 实现sqlite数据库跨数据库的数据表迁移 [转载]
2014年12月13日 14:36 新浪博客 (转自http://www.cnblogs.com/nmj1986/archive/2012/09/17/2688827.html) 需求: 有两个不同的 ...
- Laravel学习笔记(五)数据库 数据库迁移案例2——创建数据结构,数据表,修改数据结构
默认假设 所有的列在定义的时候都有默认的假设,你可以根据需要重写. Laravel假定每个表都有一个数值型的主键(通常命名为”id”),确保新加入的每一行都是唯一的.Laravel只有在每个表都有数值 ...
- Django学习手册 - admin后台 切换成中文显示/添加数据表
Django admin后台管理 切换成中文界面: 站点显示为中文: 在setting 里面修改 LANGUAGE_CORE = 'zh-Hans' 字段名显示中文 class Test(models ...
- SqlServer:SqlServer(数据库备份,数据文件迁移,增加数据库文件组,递归查询一周报送情况,查询近X天未报送单位,截断数据库日志,复制单个或多个数据库表到另一个数据库 )
1.数据备份 ) ) ) )),'-','') ) SET @savePath = 'f:/DatabaseBackup/' DECLARE My_Cursor CURSOR FOR ( select ...
- django学习-23.admin管理后台的数据表数据的自定义展示
目录结构 1.前言 2.自定义设置一张指定的数据表的列表展示内容 2.1.第一步:如果我们想让数据表[hello_person]里面的表字段值全部展示出来,需在应用[hello]里的[admin.py ...
- python Django教程 之 模型(数据库)、自定义Field、数据表更改、QuerySet API
python Django教程 之 模型(数据库).自定义Field.数据表更改.QuerySet API 一.Django 模型(数据库) Django 模型是与数据库相关的,与数据库相关的代码 ...
- Django之路:模型(数据库)和自定义Field以及数据表的更改
一.Django 模型(数据库) Django模型是与数据库相关的,与数据库相关的代码一般写在models.py中,Django支持sqlite3,MySQL,PostgreSQL等数据库,只需要在s ...
- Django 数据表更改
Django 数据表更改 « Django 开发内容管理系统(第四天) Django 后台 » 我们设计数据库的时候,早期设计完后,后期会发现不完善,要对数据表进行更改,这时候就要用到本节的知识. D ...
随机推荐
- KingbaseES生成动态SQL
1. 动态SQL 动态SQL在程序启动时会根据输入参数替换相应变量.使用动态SQL可以创建更强大和灵活的应用程序,但在编译时SQL语句的全文不确定,因此运行时编译会牺牲一些性能.动态SQL可以是代码或 ...
- 使用fiddler抓取HTTPS的数据包(抓取App端的数据包)
众所周知,我们在做接口测试的时候有两种情况: 第一种是先拿到接口测试规范文档,再去做接口测试. 第二种是没有接口文档,只有通过自己抓包. 那么说到抓包,就不得不说抓包工具,对于浏览器web端,我们只需 ...
- 【已解决】mysql8.0安装报错 error: Found option without preceding group in config file:
D:\Program Files (x86)\mysql-8.0.13-winx64\mysql-8.0.13-winx64 在此路径下找到my.ini(在个人安装的路径下) 另存为ANSI编码:
- 11.硬核的volatile考点分析
大家好,我是王有志.关注王有志,一起聊技术,聊游戏,聊在外漂泊的生活. 今天我们学习并发编程中另一个重要的关键字volatile,虽然面试中它的占比低于synchronized,但依旧是不可忽略的内容 ...
- #交互,栈#LOJ 3005 「JOISC 2015 Day 4」Limited Memory
题目 分析 一开始想的是栈的匹配,但是位数不够,而且还忘记写memory.h, 考虑它询问次数不超过一万五千次,\(O(n^2)\)的询问是绰绰有余的, 如果每一个符号都能被匹配那整个串也能被匹配,而 ...
- #Tarjan#洛谷 4819 [中山市选]杀人游戏
题目 分析 缩点后显然只考虑入度为0的点的个数, 但是问题是如果有一个入度为0的点缩点前只有1个点 且它的出边上的所有点都可以被其它入度为0的点遍历, 那么可以将其它点全部排除后剩下的这个点就是凶手, ...
- Qt调用摄像头一,基础版
本示例,为纯Qt调用摄像头,功能比较简单,打开摄像头,设置参数,拍照 涉及到的功能有: 获取摄像头列表 获取摄像头分辨率 获取摄像头帧率 获取摄像头支持的视频模式 设置摄像头参数 拍照 此版本的缺点是 ...
- Grafana 系列-统一展示-5-AWS Cloudwatch 仪表板
系列文章 Grafana 系列文章 ️强烈推荐 强烈推荐使用 GitHub 上的 monitoringartist/grafana-aws-cloudwatch-dashboards 仪表板.该 re ...
- 第一篇:Python入门基础
主要内容 1.Python简介 2.变量 3.字符编码 4.用户交互 5.if 流程判断 6.while循环 7.for循环 一.Python简介 1.python的创始人为吉多·范罗苏姆(Guido ...
- 华为云CodeArts IDE For Python 快速使用指南
本文分享自华为云社区<华为云CodeArts IDE For Python 快速使用指南>,作者:为云PaaS服务小智. CodeArts IDE 带有 Python 扩展,为 Pytho ...