Bootstrap

【GORM】初探gorm模型,字段标签与go案例

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 的默认约定

  1. 使用结构体名的复数形式(蛇形命名)作为表名。
    • 例如:User -> 表名为 users
  2. 字段名会转换为蛇形命名作为列名。
    • 例如:CreatedAt -> 列名为 created_at
  3. 自动管理 CreatedAtUpdatedAt 字段。

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'
}

效果

  • NameEmail 字段必须有值。
  • 插入记录时,未显式设置 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.CustomerIDCustomer.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_nameauthor_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{})

数据操作

  1. 插入数据
user := User{Name: "Alice", Email: "[email protected]"}
db.Create(&user)

order := Order{UserID: user.ID, Amount: 99.99}
db.Create(&order)
  1. 查询数据
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() {

}

在这里插入图片描述


https://github.com/0voice

;