ToB企服应用市场:ToB评测及商务社交产业平台
标题:
Gorm 数据库表迁移与表模型定义
[打印本页]
作者:
用户云卷云舒
时间:
2024-3-30 17:22
标题:
Gorm 数据库表迁移与表模型定义
目录
一、Docker快速创建MySQL实例
1.1 创建
1.3 创建数据库
二、AutoMigrate介绍与使用
2.1 AutoMigrate介绍
2.2 AutoMigrate 基本使用
三、模型定义
3.1 模型定义
3.2 快速增删改查
3.3 约定
3.4 gorm.Model
四、表模型主键、表名、列名的约定
4.1 主键(Primary Key)
4.1.1 使用 ID 作为主键
4.1.2 复合主键
4.2 表名(Table Name)
4.2.1 TableName
4.2.2 临时指定表名
4.2.3 命名策略
4.3 列名(Column Name)
4.4 时间戳跟踪
4.4.1 CreatedAt
4.4.2 UpdatedAt
4.4.3 DeletedAt
五、模型定义高级选项与标签
5.1 字段级权限控制
5.2 创建/更新时间追踪(纳秒、毫秒、秒、Time)
5.3 嵌入结构体
5.4 结构体标签(tags)
5.5 举个例子
一、Docker快速创建MySQL实例
1.1 创建
因为这里我们是测试学习使用,单独安装MySQL 比较费时费力,所以这里使用Docker方便快速掌握Gorm 相关知识。
如果你没有docker环境,可以参考:
【一文搞定】Linux、Mac、Windows安装Docker与配置教程!
下载镜像:
docker pull mysql
复制代码
运行MySQL容器:
docker run -p 3306:3306 --name mysql -v $PWD/conf/my.cnf:/etc/mysql/my.cnf -v $PWD/logs:/logs -v $PWD/data:/mysql_data -e MYSQL_ROOT_PASSWORD=123456 -d mysql
复制代码
下面是对命令中参数的解释:
-p 3306:3306:将容器的 3306 端口映射到主机的 3306 端口
-v $PWD/conf/my.cnf:/etc/mysql/my.cnf:将主机当前目录下的 conf/my.cnf 挂载到容器的 /etc/mysql/my.cnf
-v $PWD/logs:/logs:将主机当前目录下的 logs 目录挂载到容器的 /logs
-v $PWD/data:/mysql_data:将主机当前目录下的 data 目录挂载到容器的 /mysql_data
-e MYSQL_ROOT_PASSWORD=123456:初始化 root 用户的密码
查看运行中的容器:
docker ps
复制代码
1.3 创建数据库
首先,使用Datagrip 链接数据,接着在使用GORM前手动创建数据库db1,执行如下SQL:
CREATE DATABASE db1;
复制代码
二、AutoMigrate介绍与使用
2.1 AutoMigrate介绍
AutoMigrate 是 Gorm 提供的一个功能强大的数据库迁移工具,它可以自动创建或更新数据库表结构,使数据库的结构与 Golang 模型一致。使用 AutoMigrate 可以方便地进行数据库表的初始化和更新,而无需手动执行 SQL 语句。
2.2 AutoMigrate 基本使用
在 Gorm 中,你可以通过调用 db.AutoMigrate 方法来进行数据库表的自动迁移。以下是一个基本的使用示例:
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
type Product struct {
gorm.Model
Code string
Price uint
}
func main() {
// 日志配置
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别为info
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 彩色打印
},
)
dsn := "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err) // 如果数据库不存在会报错
}
db.AutoMigrate(&Product{}) // 可以加多个
log.Println("Auto Migration Completed")
}
复制代码
三、模型定义
3.1 模型定义
模型是标准的 struct,由 Go 的基本数据类型、实现了
Scanner
和
Valuer
接口的自定义类型及其指针或别名组成
例如:
type User struct {
ID uint
Name string
Email *string
Age uint8
Birthday *time.Time
MemberNumber sql.NullString
ActivatedAt sql.NullTime
CreatedAt time.Time
UpdatedAt time.Time
}
复制代码
3.2 快速增删改查
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
// UserInfo 用户信息
type UserInfo struct {
ID uint
Name string
Gender string
Hobby string
}
func main() {
// 日志配置
newLogger := logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer(日志输出的目标,前缀和日志包含的内容——译者注)
logger.Config{
SlowThreshold: time.Second, // 慢 SQL 阈值
LogLevel: logger.Info, // 日志级别为info
IgnoreRecordNotFoundError: true, // 忽略ErrRecordNotFound(记录未找到)错误
Colorful: true, // 彩色打印
},
)
dsn := "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: newLogger,
})
if err != nil {
panic(err) // 如果数据库不存在会报错
}
// 自动迁移
db.AutoMigrate(&UserInfo{})
u1 := UserInfo{1, "贾维斯", "男", "篮球"}
u2 := UserInfo{2, "荆轲", "女", "足球"}
// 创建记录
db.Create(&u1)
db.Create(&u2)
// 查询
var u = new(UserInfo)
db.First(u)
fmt.Printf("%#v\n", u)
var uu UserInfo
db.Find(&uu, "hobby=?", "足球")
fmt.Printf("%#v\n", uu)
// 更新
db.Model(&u).Update("hobby", "双色球")
// 删除
db.Delete(&u)
}
复制代码
3.3 约定
GORM 倾向于约定优于配置 默认情况下,GORM 使用 ID 作为主键,使用结构体名的 蛇形复数 作为表名,字段名的 蛇形 作为列名,并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间
如果您遵循 GORM 的约定,您就可以少写的配置、代码。 如果约定不符合您的实际要求,
GORM 允许你配置它们
3.4 gorm.Model
GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt
// gorm.Model 的定义
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
复制代码
您可以将它嵌入到您的结构体中,以包含这几个字段,详情请参考
嵌入结构体
四、表模型主键、表名、列名的约定
4.1 主键(Primary Key)
4.1.1 使用 ID 作为主键
默认情况下,GORM 会使用 ID 作为表的主键。
type User struct {
ID string // 默认情况下,名为 `ID` 的字段会作为表的主键
Name string
}
复制代码
你可以通过标签 primaryKey 将其它字段设为主键
// 将 `UUID` 设为主键
type Animal struct {
ID int64
UUID string `gorm:"primaryKey"`
Name string
Age int64
}
复制代码
4.1.2 复合主键
通过将多个字段设为主键,以创建复合主键,例如:
type Product struct {
ID string `gorm:"primaryKey"`
LanguageCode string `gorm:"primaryKey"`
Code string
Name string
}
复制代码
注意:
默认情况下,整型 PrioritizedPrimaryField 启用了 AutoIncrement,要禁用它,您需要为整型字段关闭 autoIncrement:
type Product struct {
CategoryID uint64 `gorm:"primaryKey;autoIncrement:false"`
TypeID uint64 `gorm:"primaryKey;autoIncrement:false"`
}
复制代码
4.2 表名(Table Name)
GORM 使用结构体名的 蛇形命名 作为表名。对于结构体 User,根据约定,其表名为 users
4.2.1 TableName
您可以实现 Tabler 接口来更改默认表名,例如:
type Tabler interface {
TableName() string
}
// TableName 会将 User 的表名重写为 `profiles`
func (User) TableName() string {
return "profiles"
}
复制代码
注意:
TableName 不支持动态变化,它会被缓存下来以便后续使用。想要使用动态表名,你可以使用 Scopes,例如:
func UserTable(user User) func (tx *gorm.DB) *gorm.DB {
return func (tx *gorm.DB) *gorm.DB {
if user.Admin {
return tx.Table("admin_users")
}
return tx.Table("users")
}
}
db.Scopes(UserTable(user)).Create(&user)
复制代码
4.2.2 临时指定表名
您可以使用 Table 方法临时指定表名,例如:
// 根据 User 的字段创建 `deleted_users` 表
db.Table("deleted_users").AutoMigrate(&User{})
// 从另一张表查询数据
var deletedUsers []User
db.Table("deleted_users").Find(&deletedUsers)
// SELECT * FROM deleted_users;
db.Table("deleted_users").Where("name = ?", "jinzhu").Delete(&User{})
// DELETE FROM deleted_users WHERE name = 'jinzhu';
复制代码
查看
from 子查询
了解如何在 FROM 子句中使用子查询
4.2.3 命名策略
GORM 允许用户通过覆盖默认的命名策略更改默认的命名约定,命名策略被用于构建: TableName、ColumnName、JoinTableName、RelationshipFKName、CheckerName、IndexName。查看
GORM 配置
获取详情
4.3 列名(Column Name)
根据约定,数据表的列名使用的是 struct 字段名的 蛇形命名
type User struct {
ID uint // 列名是 `id`
Name string // 列名是 `name`
Birthday time.Time // 列名是 `birthday`
CreatedAt time.Time // 列名是 `created_at`
}
复制代码
您可以使用 column 标签或
命名策略
来覆盖列名
type Animal struct {
AnimalID int64 `gorm:"column:beast_id"` // 将列名设为 `beast_id`
Birthday time.Time `gorm:"column:day_of_the_beast"` // 将列名设为 `day_of_the_beast`
Age int64 `gorm:"column:age_of_the_beast"` // 将列名设为 `age_of_the_beast`
}
复制代码
4.4 时间戳跟踪
4.4.1 CreatedAt
对于有 CreatedAt 字段的模型,创建记录时,如果该字段值为零值,则将该字段的值设为当前时间
db.Create(&user) // 将 `CreatedAt` 设为当前时间
user2 := User{Name: "jinzhu", CreatedAt: time.Now()}
db.Create(&user2) // user2 的 `CreatedAt` 不会被修改
// 想要修改该值,您可以使用 `Update`
db.Model(&user).Update("CreatedAt", time.Now())
复制代码
你可以通过将 autoCreateTime 标签置为 false 来禁用时间戳追踪,例如:
type User struct {
CreatedAt time.Time `gorm:"autoCreateTime:false"`
}
复制代码
4.4.2 UpdatedAt
对于有 UpdatedAt 字段的模型,更新记录时,将该字段的值设为当前时间。创建记录时,如果该字段值为零值,则将该字段的值设为当前时间
db.Save(&user) // 将 `UpdatedAt` 设为当前时间
db.Model(&user).Update("name", "jinzhu") // 会将 `UpdatedAt` 设为当前时间
db.Model(&user).UpdateColumn("name", "jinzhu") // `UpdatedAt` 不会被修改
user2 := User{Name: "jinzhu", UpdatedAt: time.Now()}
db.Create(&user2) // 创建记录时,user2 的 `UpdatedAt` 不会被修改
user3 := User{Name: "jinzhu", UpdatedAt: time.Now()}
db.Save(&user3) // 更新时,user3 的 `UpdatedAt` 会修改为当前时间
复制代码
你可以通过将 autoUpdateTime 标签置为 false 来禁用时间戳追踪,例如:
type User struct {
UpdatedAt time.Time `gorm:"autoUpdateTime:false"`
}
复制代码
4.4.3 DeletedAt
// 只要使用了gorm.Model结构体继承,DeletedAt DeletedAt `gorm:"index"` 字段
// 执行删除是其实是update语句,并没有真正的删除
复制代码
五、模型定义高级选项与标签
5.1 字段级权限控制
可导出的字段在使用 GORM 进行 CRUD 时拥有全部的权限,此外,GORM 允许您用标签控制字段级别的权限。这样您就可以让一个字段的权限是只读、只写、只创建、只更新或者被忽略
注意:
使用 GORM Migrator 创建表时,不会创建被忽略的字段
[code]type User struct { Name string `gorm:"
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4