GORM是什么?
- GORM 是一个Go 语言 ORM(对象关系映射)库,它让我们可以使用结构体来操作数据库,而无需编写SQL 语句
GORM 模型与字段标签详解
在 GORM 中,模型是数据库表的抽象表示,字段标签(Tag)则用于指定模型字段与数据库字段之间的映射规则及行为。
1. 模型定义
模型是由 Go 的结构体定义的,它表示数据库中的一张表。GORM 默认遵循约定优于配置的原则,提供了很多自动化功能。
基本模型示例
type User struct {
ID uint `gorm:"primaryKey"` // 主键
Name string `gorm:"size:100"` // 字符串最大长度为 100
Email string `gorm:"unique"` // 唯一字段
Age uint8 `gorm:"check:age >= 0"` // 年龄必须非负
CreatedAt time.Time // 创建时间
UpdatedAt time.Time // 更新时间
}
GORM 的默认约定
- 使用结构体名的复数形式(蛇形命名)作为表名。
- 例如:
User
-> 表名为users
。
- 例如:
- 字段名会转换为蛇形命名作为列名。
- 例如:
CreatedAt
-> 列名为created_at
。
- 例如:
- 自动管理
CreatedAt
和UpdatedAt
字段。
2. 字段标签详解
GORM 提供了丰富的字段标签,帮助我们定制模型字段的行为。以下是常用标签的分类及示例。
2.1 主键和自增
primaryKey
:设置主键。autoIncrement
:设置字段为自增。
type Product struct {
ID uint `gorm:"primaryKey;autoIncrement"`
Name string
Price float64
}
效果:ID
字段为自增主键。
2.2 字段属性
size
:设置字符串类型字段的最大长度。not null
:设置字段不能为空。default
:设置字段的默认值。unique
:设置字段为唯一约束。
type Customer struct {
ID uint
Name string `gorm:"size:50;not null"` // 最长 50 字符,不能为空
Email string `gorm:"unique;not null"` // 唯一且不能为空
Status string `gorm:"default:'active'"` // 默认值为 'active'
}
效果:
Name
和Email
字段必须有值。- 插入记录时,未显式设置
Status
的值时,将使用默认值。
2.3 外键与关联
foreignKey
:定义外键字段。references
:指定外键引用的字段。constraint
:设置外键的约束行为。
type Order struct {
ID uint
CustomerID uint `gorm:"not null"`
Customer Customer `gorm:"foreignKey:CustomerID;references:ID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"`
}
效果:
Order.CustomerID
是Customer.ID
的外键。- 更新
Customer.ID
时级联更新,删除Customer
时将CustomerID
设为 NULL。
2.4 时间字段
autoCreateTime
:自动设置为记录创建时间。autoUpdateTime
:自动设置为记录更新时间。
type Post struct {
ID uint
Title string
CreatedAt int64 `gorm:"autoCreateTime"` // 使用 Unix 时间戳
UpdatedAt int64 `gorm:"autoUpdateTime:nano"` // 使用纳秒时间戳
}
2.5 嵌套结构体
GORM 支持将结构体嵌套到模型中,通过标签自定义嵌套字段的列名前缀。
type Author struct {
Name string
Email string
}
type Blog struct {
ID uint
Author Author `gorm:"embedded;embeddedPrefix:author_"`
Content string
}
效果:
Author
的字段会被展开,数据库表的列名为author_name
和author_email
。
3. 实际案例:用户与订单系统
以下是一个用户和订单的实际案例,展示如何使用模型和字段标签。
模型定义
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:100;not null"`
Email string `gorm:"uniqueIndex;not null"`
Orders []Order `gorm:"foreignKey:UserID"`
CreatedAt time.Time
UpdatedAt time.Time
}
type Order struct {
ID uint `gorm:"primaryKey"`
UserID uint `gorm:"not null"`
Amount float64 `gorm:"not null"`
Status string `gorm:"default:'pending'"`
CreatedAt time.Time
}
数据库迁移
使用 AutoMigrate
自动生成表结构:
db.AutoMigrate(&User{}, &Order{})
数据操作
- 插入数据
user := User{Name: "Alice", Email: "[email protected]"}
db.Create(&user)
order := Order{UserID: user.ID, Amount: 99.99}
db.Create(&order)
- 查询数据
var user User
db.Preload("Orders").First(&user)
fmt.Printf("用户信息: %+v\\n", user)
4. 总结
标签 | 描述 | 示例 |
---|
| primaryKey | 设置字段为主键 | gorm:\"primaryKey\"
|
| size | 设置字符串字段长度 | gorm:\"size:255\"
|
| not null | 设置字段不能为空 | gorm:\"not null\"
|
| unique | 设置字段唯一性约束 | gorm:\"unique\"
|
| autoCreateTime| 自动记录创建时间 | gorm:\"autoCreateTime\"
|
| foreignKey | 定义外键字段 | gorm:\"foreignKey:UserID\"
|
| embedded | 嵌套结构体字段 | gorm:\"embedded\"
|
go案例展示
conn.go
package _case
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"log"
"os"
"time"
)
var DB *gorm.DB
/*
用户名和密码:root:123456
root 是数据库用户名。
123456 是数据库密码。
网络协议和地址:@tcp(192.168.88.131:3306)
@tcp 表示使用 TCP 协议进行连接。
192.168.88.131 是数据库服务器的 IP 地址。
3306 是 MySQL 默认端口号。
数据库名称:/mydb
mydb 是要连接的数据库名称。
查询参数:
charset=utf8mb4:指定字符集为 utf8mb4,支持完整的 Unicode 编码,包括表情符号等。
parseTime=True:将时间字段解析为 Go 的 time.Time 类型。
loc=Local:设置时区为本地时区。// 保存与数据库的连接实例
*/
var dsn = "root:123456@tcp(192.168.88.131:3306)/mydb?charset=utf8mb4&parseTime=True&loc=Local" // 数据源名称(DSN)
// 为了提高安全性,避免硬编码敏感信息(如用户名和密码),可以使用环境变量来存储这些信息。
func getDSN() string {
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local",
os.Getenv("DB_USER"),
os.Getenv("DB_PASSWORD"),
os.Getenv("DB_HOST"),
os.Getenv("DB_PORT"),
os.Getenv("DB_NAME"))
}
// 使用 GORM 库连接 MySQL 数据库,并配置数据库连接池。
func init() {
var err error
DB, err = gorm.Open(mysql.New(mysql.Config{ // gorm.Open 打开数据库连接 ,第一个参数mysql.Config是mysql配置对象
DSN: dsn,
DefaultStringSize: 256,
}), &gorm.Config{ // 第二个参数gorm.Config gorm配置
Logger: logger.Default.LogMode(logger.Info), // 设置日志级别为Info
// 开启预编译,提高后续调用速度
// 开启预编译情况,不支持嵌套事务
// PrepareStmt: true
})
if err != nil {
log.Println(err)
return
}
setPool(DB)
}
// 设置数据库连接池
func setPool(db *gorm.DB) {
sqlDB, err := db.DB() // 获取底层的*sql.DB
if err != nil {
log.Println(err)
return
}
sqlDB.SetMaxOpenConns(100) // 设置最大打开连接数
sqlDB.SetMaxIdleConns(10) // 设置最大空闲连接数
sqlDB.SetConnMaxLifetime(time.Hour) // 设置连接最大生命周期
}
models.go
package _case
import "gorm.io/gorm"
// init函数在程序启动时初始化数据库迁移
// 使用了AutoMigrate方法来自动迁移Teacher和Course模型
// 确保了表结构与 Go 结构体定义保持同步
func init() {
DB.Migrator().AutoMigrate(Teacher{}, Course{}) // migrator 迁移器 autoMigrate 自动迁移
}
type Roles []string // 存储教师的角色信息
// Teacher 结构体代表了一个教师实体,用于在数据库中存储教师的相关信息。
// 通过 GORM 标签,定义了各个字段在数据库中的行为和约束。
type Teacher struct {
gorm.Model // 继承自 GORM 的默认模型,包含 ID, CreatedAt, UpdatedAt, DeletedAt 字段
Name string `gorm:"size:256"` // 教师的姓名,最多256个字符
Email string `gorm:"size:256"` // 教师的电子邮件地址,最多256个字符
Salary float64 `gorm:"scale:2;precision:7"` // 教师的工资,使用7位精度和2位小数表示
Age uint8 `gorm:"check:age>30"` // 教师的年龄,数据库中有一个检查约束确保年龄大于30
Birthday int64 `gorm:"serializer:unixtime;type:time"` // 教师的生日,以Unix时间戳的形式存储
Roles Roles `gorm:"serializer:json"` // 教师的角色,以JSON格式序列化存储
JobInfo Job `gorm:"embedded;embeddedPrefix:job_"` // 嵌入的Job结构体,表示教师的职业信息,字段名前缀为job_
JobInfo2 Job `gorm:"type:bytes;serializer:gob"` // 另一种形式的教师职业信息存储,使用GOB序列化方式存储为字节类型
}
type Job struct {
Title string
Location string
}
// Course 结构体代表了一个课程实体,包括课程的基本信息及其与用户的关系。
// 该结构体使用了gorm.Model,这意味着它包含了通用的字段如ID、创建时间、更新时间和删除时间,用于ORM操作。
type Course struct {
// gorm.Model 嵌入式通用模型,提供基础的ORM功能。
gorm.Model
// Name 字段表示课程的名称,使用gorm注释指定最大长度为256字符。
Name string `gorm:"size:256"`
// Price 字段表示课程的价格,其中scale:2表示小数点后保留两位,precision:7表示总共可以存储7位数字(包括小数点后的数字)。
Price float64 `gorm:"scale:2;precision:7"`
// UserID 字段表示创建或关联该课程的用户ID,使用gorm注释指定其数据库中的类型为int。
UserID uint `gorm:"type:int"`
}
main.go
package main
import (
_ "golang15-gorm/case"
)
func main() {
}