7--商品、活动、订单的Model实现

阶段回顾

User (已完成)
    ↓ JWT (已完成)
    ↓
商品/秒杀/订单 ← 当前阶段
    ↓
Redis 库存预热 ← 依赖 Seckill.Stock
    ↓
RabbitMQ 异步下单 ← 依赖 Order 创建
    ↓
秒杀接口 ← 需要 UserId 鉴权

想要完成秒杀,首先要确定哪个用户在抢,我们在先前通过JWT已经完成了用户身份验证逻辑
接下来要解决的就是在哪秒杀秒杀什么,即秒杀活动秒杀商品
订单秒杀的结果,用户抢购成功后生成Order,依赖 UserProductSeckill 三个模型的外键关系

一. 模型设计

1) ER图

erDiagram USER ||--o{ ORDER : "下单" PRODUCT ||--o{ SECKILL : "举办活动" PRODUCT ||--o{ ORDER : "包含" SECKILL ||--o{ ORDER : "生成" USER { uint uid PK string username string email string phone string password datetime created_at } PRODUCT { uint product_id PK string name text description decimal price int stock datetime created_at } SECKILL { uint seckill_id PK uint product_id FK string name decimal price int stock datetime start_time datetime end_time int status datetime created_at } ORDER { uint order_id PK uint user_id FK uint product_id FK uint seckill_id FK decimal amount int status datetime created_at datetime updated_at }

2) 秒杀状态机

graph LR 未开始[未开始<br>status=0] -->|开始| 进行中[进行中<br>status=1] -->|结束| 已结束[已结束<br>status=2]

3) 订单状态机

graph LR 待支付[待支付<br>status=0] -->|支付| 已支付[已支付<br>status=1] 已支付 -->|退款| 已退款[已退款<br>status=3] 待支付 -->|取消| 已取消[已取消<br>status=2]

4) 字段说明

模型 关键字段 作用
Product stock 真实库存,秒杀前预热到 Redis
Seckill stockstart_timeend_timestatus 控制秒杀活动的开始/结束/可用状态
Order user_idseckill_idamountstatus 关联用户、秒杀活动、金额、支付状态

二. 模型创建

三个go文件需要创建在internal/model/文件夹下

internal/model/
    ├── user.go       # 已有
    ├── product.go    # 新增
    ├── seckill.go    # 新增
    └── order.go      # 新增

1) 商品模型

product.go

package model

import "time"

// Product 定义了商品的结构体,包含商品ID、名称、描述、价格、库存数量和创建时间等字段
type Product struct {
	ProductId   uint      `gorm:"primaryKey;column:product_id;autoIncrement" json:"product_id"` // 商品ID,主键,自增
	Name        string    `gorm:"column:name;type:varchar(100);not null" json:"name"`           // 商品名称,字符串类型,最大长度100,不能为空
	Description string    `gorm:"column:description;type:text" json:"description"`              // 商品描述,文本类型
	Price       float64   `gorm:"column:price;type:decimal(10,2);not null" json:"price"`        // 商品价格,十进制类型,精度10位,小数点后2位,不能为空
	Stock       int       `gorm:"column:stock;type:int;not null" json:"stock"`                  // 商品库存数量,整数类型,不能为空
	CreatedAt   time.Time `gorm:"column:created_at;autoCreateTime" json:"created_at"`           // 商品创建时间,自动设置为当前时间
}

func (Product) TableName() string {
	return "product" // 指定数据库表名为 "product"
}

2) 秒杀活动模型

seckill.go

package model

import "time"

// Seckill 定义了秒杀活动的结构体,包含秒杀活动ID、关联的商品ID、秒杀活动名称、库存数量、开始时间、结束时间、状态和创建时间等字段
type Seckill struct {
	SeckillId uint      `gorm:"primaryKey;column:seckill_id;autoIncrement" json:"seckill_id"` // 秒杀活动ID,主键,自增
	ProductId uint      `gorm:"column:product_id;not null" json:"product_id"`                 // 关联的商品ID,不能为空
	Name      string    `gorm:"column:name;type:varchar(200);not null" json:"name"`           // 秒杀活动名称,字符串类型,最大长度200,不能为空
	Price     float64   `gorm:"column:price;type:decimal(10,2);not null" json:"price"`        // 秒杀价格,十进制类型,精度10位,小数点后2位,不能为空
	Stock     int       `gorm:"column:stock;not null" json:"stock"`                           // 秒杀活动库存数量,不能为空
	StartTime time.Time `gorm:"column:start_time;not null" json:"start_time"`                 // 秒杀活动开始时间,不能为空
	EndTime   time.Time `gorm:"column:end_time;not null" json:"end_time"`                     // 秒杀活动结束时间,不能为空
	Status    int       `gorm:"column:status;type:int;default:0" json:"status"`               // 秒杀活动状态,整数类型,不能为空
	// (0:未开始,1:进行中,2:已结束)
	CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"created_at"` // 秒杀活动创建时间,自动设置为当前时间
}

func (Seckill) TableName() string {
	return "seckill" // 指定数据库表名为 "seckill"
}

3) 订单模型

order.go

package model

import "time"

// Order 定义了订单的结构体,包含订单ID、用户ID、商品ID、秒杀活动ID、订单金额、订单状态、创建时间和更新时间等字段
type Order struct {
	OrderId   uint    `gorm:"primaryKey;column:order_id;autoIncrement" json:"order_id"` // 订单ID,主键,自增
	UserId    uint    `gorm:"column:user_id;not null" json:"user_id"`                   // 关联的用户ID,不能为空
	ProductId uint    `gorm:"column:product_id;not null" json:"product_id"`             // 关联的商品ID,不能为空
	SeckillId uint    `gorm:"column:seckill_id;not null" json:"seckill_id"`             // 关联的秒杀活动ID,不能为空
	Amount    float64 `gorm:"column:amount;type:decimal(10,2);not null" json:"amount"`  // 订单金额,十进制类型,精度10位,小数点后2位,不能为空
	Status    int     `gorm:"column:status;type:int;default:0" json:"status"`           // 订单状态,整数类型,不能为空
	// (0:未支付,1:已支付,2:已取消)
	CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"created_at"` // 订单创建时间,自动设置为当前时间
	UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updated_at"` // 订单更新时间,自动设置为当前时间
}

func (Order) TableName() string {
	return "order" // 指定数据库表名为 "order"
}

4) 数据库表关系

源实体 关系 目标实体 说明
product(商品) 一对多 seckill(秒杀活动) 一个商品可对应多个秒杀活动
order(订单) 一对一 seckill(秒杀活动) 一个用户 + 秒杀活动 = 一个订单

三. 更新AutoMigrate以便Gorm创建对应数据表

internal/repository/mysql.go

// InitMySQL 初始化数据库连接
func InitMySQL() {
	// ... 其余代码 ...

	// AutoMigrate 会根据 User 结构体自动创建或更新数据库表结构
	if err := DB.AutoMigrate(&model.User{}, &model.Product{}, &model.Seckill{}, &model.Order{}); err != nil {
		log.Fatalf("Failed to auto migrate tables: %v", err)
	}
}

四. 运行

go run之后会发现数据库里自动创建了三个数据表,加上之前的User表一共是四个

Four_tables

posted @ 2026-04-17 17:36  Chuan81  阅读(23)  评论(0)    收藏  举报