Gorm学习(三)基础:迁移(数据库建表以及字段设置)

简介: 在项目开发中,我们可能会随时调整声明的模型,比如添加字段和索引,使用 GORM 的自动迁移功能,可以始终让我们的数据库表结构保持最新。

前言


感谢开源项目gin-vue-admin,以及1010工作室的视频教程

本人学识尚浅,如有错误,请评论指出,谢谢!

详细可见个人博客:https://linzyblog.netlify.app/


一、迁移概念


在项目开发中,我们可能会随时调整声明的模型,比如添加字段和索引,使用 GORM 的自动迁移功能,可以始终让我们的数据库表结构保持最新。


此外,GORM 还提供了一些迁移接口的方法,可以帮助我们方便操作数据库表、字段和索引。


二、AutoMigrate 自动迁移


AutoMigrate 用于自动迁移你的 schema(模式),保持你的 schema(模式) 是最新的。


注意: AutoMigrate 会创建表、缺失的外键、约束、列和索引。 并且会更改现有列的类型,如果大小、精度、是否为空可以更改。 但不会删除未使用的列,以保护您的数据。(只增不减)


在执行 AutoMigrate时,我们需要先声明模型。


type User struct {
  gorm.Model
  Name string
  Age  uint
}
type Product struct {
  gorm.Model
  Name  string
  Price int
}
type Order struct {
  gorm.Model
  UserID    int
  ProductID int
}


建立数据库连接后,执行 AutoMigrate:


var db *gorm.DB
func init() {
  var err error
  //我这里用到数据库是mysql,需要配置DSN属性[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]
  dsn := "root:123456@tcp(127.0.0.1:3306)/go_test?charset=utf8&parseTime=True"
  db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{})
  if err != nil {
    panic("failed to connect database")
  }
}
func main() {
  db.AutoMigrate(&User{})
  db.AutoMigrate(&User{}, &Product{}, &Order{})
}

50ae867464814d7cbacba46352b2cc30.png


三、Migrator 接口


GORM 提供了 Migrator 接口,该接口为每个数据库提供了统一的 API 接口,可用来为您的数据库构建独立迁移,例如:


SQLite 不支持 ALTER COLUMN、DROP COLUMN,当你试图修改表结构,GORM 将创建一个新表、复制所有数据、删除旧表、重命名新表。


一些版本的 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
  GetTables() (tableList []string, err error)
  // Columns
  AddColumn(dst interface{}, field string) error
  DropColumn(dst interface{}, field string) error
  AlterColumn(dst interface{}, field string) error
  MigrateColumn(dst interface{}, field *schema.Field, columnType ColumnType) error
  HasColumn(dst interface{}, field string) bool
  RenameColumn(dst interface{}, oldName, field string) error
  ColumnTypes(dst interface{}) ([]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、数据库接口


1)CurrentDatabase 返回当前使用的数据库名


db.Migrator().CurrentDatabase()

db80a6791d464b2480162a27952192db.png


2、数据表接口


操作数据库表,必须先声明模型。


1)CreateTable 创建数据表


err := db.Migrator().CreateTable(&User{})
if err != nil {
  fmt.Printf("创建数据库表失败,错误:%s\n", err)
  return
}
fmt.Println("创建数据库表成功")


创建失败:


bacdf3a19cc34cd3a963ea433a3867f5.png


创建成功:


默认情况下,GORM 会约定使用 ID 作为表的主键,可以通过标签 gorm:"primarykey" 将其它字段设为主键。


通过将多个字段设为主键,以达到创建复合主键,整型字段设为主键,默认为启用 AutoIncrement,如果需要禁用,使用标签 autoIncrement:false。


GORM 约定使用结构体名的复数形式作为表名,不过也可以根据需求修改,可以实现Tabler 接口来更改默认表名,不过这种方式不支持动态变化,它会被缓存下来以便后续使用,如果想要使用动态表名,可以使用Scopes.


GORM 约定使用结构体的字段名作为数据表的字段名,默认GORM 对 struct 字段名使用Snake Case命名风格转换成 MySQL 表字段名(需要转换成小写字母),也可以通过标签 column 修改。


2)HasTable 检查对应的数据表是否存在


isExist := db.Migrator().HasTable(&User{})
//isExist := db.Migrator().HasTable("users")
if !isExist {
  fmt.Printf("users 表不存在\n")
  return
}
fmt.Printf("users 表存在\n")

7e7f2c0e315c4d2badee87a8448b6476.png


3)DropTable 如果存在表则删除(删除时会忽略、删除外键约束)


db.Migrator().DropTable(&User{})
// err := db.Migrator().DropTable("users")
fmt.Printf("users 表删除成功\n")

1e6e76ae0e6345399d68620bcb803c14.png


4)RenameTable 重命名表


// db.Migrator().RenameTable("users", "user_infos")
//若是users表存在则改名为user_infos表,反之亦然
if b := db.Migrator().HasTable(&User{}); b {
  db.Migrator().RenameTable(&User{}, &UserInfo{})
  fmt.Printf("users 表名修改成功\n")
} else {
  db.Migrator().RenameTable(&UserInfo{}, &User{})
  fmt.Printf("user_infos 表名修改成功\n")
}


8376fb46be234d2ea375b473b3f768ff.png


个人推荐用结构体模型来进行以上操作,数据库的结构可以统一固定,这也是迁移的目的。


3、数据表字段接口


操作数据库表字段,必须先声明模型。


1)AddColumn 添加字段


注意:


  • 必须先声明模型。
  • 数据表不存在的字段名,且结构体字段存在。


现在的表结构:


b3f421275d3c4a309551e70611c9969c.png


type User struct {
  Sex bool
}
err := db.Migrator().AddColumn(&User{}, "Sex")
if err != nil {
  fmt.Printf("添加字段错误,err:%s\n", err)
  return
}


6e64c88513f847d78f02965e0a5962b1.png


2)DropColumn 删除字段


err := db.Migrator().DropColumn(&User{}, "Age")
if err != nil {
  fmt.Printf("删除字段错误,err:%s\n", err)
  return
}


78b311c35301473ca7d7cb42d7b86227.png


3)RenameColumn 修改字段名


注意:


  • 必须先声明模型。
  • 修改的字段名在对应的数据表必须存在,修改的字段名和修改后的字段名必须定义在结构体内。


type User struct {
  Name     string
  UserName string
}
err := db.Migrator().RenameColumn(&User{}, "name", "user_name")
if err != nil {
  fmt.Printf("修改字段名错误,err:%s\n", err)
  return
}

0fcdaa96e17f4f3289abd4fa446f1477.png


4)HasColumn 查询字段是否存在


isExistField := db.Migrator().HasColumn(&User{}, "name")
fmt.Printf("name字段是否存在:%t\n", isExistField)
isExistField = db.Migrator().HasColumn(&User{}, "user_name")
fmt.Printf("user_name:%t\n", isExistField)

ef708625dba247d691105c65a626d0ba.png


4、 数据库表的索引接口


1)CreateIndex 为字段创建索引


注意:


  • 必须先声明模型。
  • 必须先在声明模型中使用标签gorm:index定义索引。


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")

f846e698c8f14cecb46655128eee67b1.png


2)DropIndex 为字段删除索引


db.Migrator().DropIndex(&User{}, "Name")
db.Migrator().DropIndex(&User{}, "idx_name")

b7a5871425e643a1906c6c6ffaa506d0.png


3)HasIndex 检查索引是否存在


isExists := db.Migrator().HasIndex(&User{}, "idx_name")
fmt.Printf("idex_name是否存在:%t\n", isExists)
db.Migrator().CreateIndex(&User{}, "idx_name")
isExists = db.Migrator().HasIndex(&User{}, "idx_name")
fmt.Printf("idex_name是否存在:%t\n", isExists)

468623eb6c6341ac8647ccd712235180.png


4)RenameIndex 修改索引名


注意:


  • 必须先声明模型。
  • 必须先在声明模型中使用标签gorm:index定义索引。


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{}, "idx_name", "idx_name_2")

cea6547308934fa2b8790d985376da24.png


四、小结


Gorm的迁移接口功能很丰富,AutoMigrate 就适用于大多数的迁移,如果需要更加个性化的迁移工具 ,GORM 提供的一个通用数据库接口。


// returns `*sql.DB`
db.DB()


迁移接口的方法,确实给开发工作带来了方便,但是个人建议除非特殊原因,否则尽量通过在声明模型中修改数据库表的字段和索引。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
目录
相关文章
|
关系型数据库 MySQL 数据库
自建数据库如何迁移至RDS MySQL实例
数据库迁移是一项复杂且耗时的工程,需考虑数据安全、完整性及业务中断影响。使用阿里云数据传输服务DTS,可快速、平滑完成迁移任务,将应用停机时间降至分钟级。您还可通过全量备份自建数据库并恢复至RDS MySQL实例,实现间接迁移上云。
|
人工智能 运维 关系型数据库
数据库运维:mysql 数据库迁移方法-mysqldump
本文介绍了MySQL数据库迁移的方法与技巧,重点探讨了数据量大小对迁移方式的影响。对于10GB以下的小型数据库,推荐使用mysqldump进行逻辑导出和source导入;10GB以上可考虑mydumper与myloader工具;100GB以上则建议物理迁移。文中还提供了统计数据库及表空间大小的SQL语句,并讲解了如何使用mysqldump导出存储过程、函数和数据结构。通过结合实际应用场景选择合适的工具与方法,可实现高效的数据迁移。
1908 1
|
存储 运维 关系型数据库
从MySQL到云数据库,数据库迁移真的有必要吗?
本文探讨了企业在业务增长背景下,是否应从 MySQL 迁移至云数据库的决策问题。分析了 MySQL 的优势与瓶颈,对比了云数据库在存储计算分离、自动化运维、多负载支持等方面的优势,并提出判断迁移必要性的五个关键问题及实施路径,帮助企业理性决策并落地迁移方案。
|
存储 关系型数据库 数据挖掘
【瑶池数据库动手活动及话题本周精选(体验ADB、 SelectDB,参与 RDS 迁移训练营)】(4.21-4.27)
本文为 “瑶池数据库动手活动及话题精选” 系列第一期,聚焦 SelectDB 日志分析、AnalyticDB Zero-ETL 集成、RDS 迁移训练营三大实战,设积分、实物等多重奖励,同步开启话题互动。点击链接参与,每周解锁数据库实战新场景。
|
SQL Oracle 关系型数据库
用 YashanDB Migration Platform,数据库迁移不再是“高风险动作”
数据库迁移一直是企业信息化中的难题,耗时长、风险高。YashanDB Migration Platform(YMP)提供一站式解决方案,涵盖评估、改写、迁移与校验全流程。其核心能力包括SQL自动适配、智能对象迁移、高性能数据通道及数据对比校验,显著降低人力成本与业务风险。适合从Oracle、MySQL等迁移到YashanDB的企业,以及需异构整合或国产化替代的集团、政府和国企项目。YMP不仅是工具,更是推动数据库国产化的关键平台。
|
SQL Java 关系型数据库
Java连接MySQL数据库环境设置指南
请注意,在实际部署时应该避免将敏感信息(如用户名和密码)硬编码在源码文件里面;应该使用配置文件或者环境变量等更为安全可靠地方式管理这些信息。此外,在处理大量数据时考虑使用PreparedStatement而不是Statement可以提高性能并防止SQL注入攻击;同时也要注意正确处理异常情况,并且确保所有打开过得资源都被正确关闭释放掉以防止内存泄漏等问题发生。
547 13
|
关系型数据库 MySQL 数据库
MySQL数据库上云迁移
本文介绍了将数据库迁移到RDS for Mysql的两种主要方法:停服迁移和不停服迁移。停服迁移适合可短暂中断服务的场景,通过mysqldump或DTS完成;不停服迁移适用于需保持业务连续性的场景,推荐使用DTS实现结构、全量及增量数据迁移。文中详细列出了每种方法的具体操作步骤,帮助企业根据需求选择合适的迁移方案。
496 1
MySQL数据库上云迁移
|
数据库 Python
【YashanDB知识库】python驱动查询gbk字符集崖山数据库CLOB字段,数据被驱动截断
【YashanDB知识库】python驱动查询gbk字符集崖山数据库CLOB字段,数据被驱动截断

热门文章

最新文章