当前位置: 首页 > news >正文

数据库约束 和 Struct Tag 标签到底是干什么的?

🥰个人主页:会编程的土豆(欢迎来访)
💎作者简介:后端学习者
❄️个人专栏:数据结构与算法,数据库,leetcode
那些你一个人走过的夜路,终将化作照亮未来的光

适合对象:刚接触 MySQL + GORM 的新手
结合场景:影院票务(users / seats / orders 等表)
读完你能分清:SQL 里的约束管什么,Go 结构体上的 tag 又管什么


一、先建立整体印象

做 Web 后端时,数据会经过两层“说明书”:

层级写在哪作用
数据库约束CREATE TABLE数据库强制执行的规则,违规会直接报错
Struct TagGo 的struct字段后面`...`给框架看的标注:GORM 怎么映射表、JSON 怎么输出

可以记一句:

  • 约束:数据库的“铁规矩”
  • Tag:Go 代码和框架之间的“说明书便签”

两者经常对应(比如表里username唯一,模型上也写uniqueIndex),但职责不同:
真正拦非法数据的,主要是数据库约束;Tag 更多是让 GORM/JSON 知道怎么读写。


二、数据库约束是什么?

建表时,除了写“有哪些列”,还会写“这些列必须遵守什么规则”。这些规则就叫约束(Constraint)

2.1 为什么需要约束?

假如没有约束:

  • 可以插入两个相同的用户名 → 登录时到底算谁?
  • 订单可以写一个不存在的user_id→ 脏数据
  • 座位状态乱填 999 → 业务判断全乱

约束就是在数据库层把这些问题挡掉。

2.2 票务项目里常见约束(对照理解)

1)主键 PRIMARY KEY
id BIGINT PRIMARY KEY AUTO_INCREMENT
  • 每一行的唯一身份证
  • AUTO_INCREMENT:插入时 id 自动增长
  • 一张表通常一个主键
2)非空 NOT NULL
username VARCHAR(50) NOT NULL

这一列不允许是NULL(“没填”)。
注意:空字符串''NULL不是一回事。

3)唯一 UNIQUE
username VARCHAR(50) NOT NULL UNIQUE

同一张表里,这个值不能重复。
用户名、订单号常用。

4)默认值 DEFAULT
role TINYINT NOT NULL DEFAULT 0

插入时如果不写role,就默认是0(顾客)。

5)外键 FOREIGN KEY
CONSTRAINT fk_sch_movie FOREIGN KEY (movie_id) REFERENCES movies(id)

含义:schedules.movie_id必须能在movies.id里找到。
作用:防止场次挂到一部不存在的电影上。

常见连带策略(了解即可):

  • ON DELETE CASCADE:主表删了,子表相关行也删(如删场次时座位跟着删)
  • ON DELETE SET NULL:主表删了,子表外键置空
6)索引 INDEX / UNIQUE KEY
INDEX idx_order_user (user_id) UNIQUE KEY uk_seat (schedule_id, row_no, col_no)
  • 索引:让按某列查询更快(如查某用户订单)
  • 唯一索引:既加速,又保证组合不重复
    例如同一场次不能有两个“3排5座”
7)引擎 ENGINE=InnoDB

购票要用事务和行锁(FOR UPDATE),一般用 InnoDB。
这不是列约束,但是建表时很重要的选择。


三、结合座位和订单理解约束

座位和订单的关系可以记成:

一笔订单对应多个座位;座位通过order_id挂到订单上。

相关约束帮助保证:

  1. orders.user_id必须是真实用户(外键)
  2. orders.schedule_id必须是真实场次(外键)
  3. 同一场次的(schedule_id, row_no, col_no)唯一(唯一索引)
  4. 订单状态、座位状态用整数表示业务含义(配合代码常量,不一定全靠数据库枚举)

没有这些约束,超卖、脏订单会更容易出现(当然超卖还要靠事务和行锁,约束是基础防线)。


四、Go 里的 Tag 标签是什么?

看模型代码时,常看到:

type User struct { ID int64 `gorm:"primaryKey;autoIncrement" json:"id"` Username string `gorm:"size:50;uniqueIndex;not null" json:"username"` Password string `gorm:"size:32;not null" json:"-"` }

字段后面的反引号字符串,就是struct tag(标签)

特点:

  • 不影响 Go 语法本身能不能编译通过(写错 tag 内容往往仍能编译)
  • 主要给反射 + 框架读取,例如 GORM、encoding/json

一个字段上可以写多个 tag,用空格分隔:

`gorm:"..." json:"..."`

五、json tag:控制接口返回长什么样

写法含义
json:"username"JSON 里字段名用username
json:"-"不要序列化出去(密码、盐常用)
json:"nickname,omitempty"空值时可以省略该字段

示例:

Password string `json:"-"` Salt string `json:"-"`

登录成功返回用户信息时,就不会把密码哈希泄露给前端。这是非常基础的安全习惯。


六、gorm tag:控制怎么和数据库打交道

GORM 通过 tag 知道:

  • 主键是谁
  • 列名是什么
  • 是否唯一
  • 字段长度
  • 是否只读(联表查出来的字段)等

6.1 常用 gorm tag(入门够用)

tag含义
primaryKey主键
autoIncrement自增
not null非空(模型层提示/迁移时有用)
size:50字符串长度
uniqueIndex唯一索引
index普通索引
column:rows_num数据库列名和 Go 字段名不一致时指定列名
type:decimal(10,2)指定数据库类型
default:0默认值
->只读:查可以填充,一般不用于写入该表
-忽略该字段(完全不映射)

6.2 TableName:指定表名

func (User) TableName() string { return "users" }

告诉 GORM:User对应表名users
否则 GORM 可能按默认规则猜表名(有时是users,有时你想精确控制)。

6.3 为什么有的字段是指针?

GroupID *int64 LockUserID *int64 PaidAt *time.Time

因为数据库里这些列可能是NULL

  • 用指针:可以区分“没值(nil)”和“有值 0”
  • 用普通int64:很难表达 SQL 的NULL

七、约束 vs Tag:别混在一起

对比数据库约束Struct Tag
写在哪SQL / 数据库Go 结构体
谁强制执行MySQL框架约定(GORM/JSON)
作用保证数据合法性指导映射与序列化
失败时插入/更新直接报错可能映射错、字段丢失、或迁移不一致

注意:

  • 只在 Go 的 gorm tag 写了uniqueIndex,但数据库里没建唯一约束,不一定能防重复(尤其你是用schema.sql建表、而不是全靠 AutoMigrate 时)。
  • 本票务项目是SQL 建表为主,models 上的 gorm tag 更多是让 GORM 读写时行为正确、字段对应正确。
  • 真正的底线仍是数据库约束 + 业务代码(事务/行锁)

八、一张对照表(users)

SQLGo
id BIGINT PRIMARY KEY AUTO_INCREMENTID int64 \gorm:“primaryKey;autoIncrement” json:“id”``
username VARCHAR(50) NOT NULL UNIQUEUsername string \gorm:“size:50;uniqueIndex;not null” json:“username”``
password CHAR(32) NOT NULLPassword string \gorm:“size:32;not null” json:“-”``
role TINYINT DEFAULT 0Role int \gorm:“not null;default:0” json:“role”``

看到没有:左边是库的规矩,右边是 Go 的说明书。两边对齐,项目才稳

http://www.jsqmd.com/news/1333424/

相关文章:

  • YOLOv8从理论到实战:核心架构解析、训练调优与多平台部署指南
  • 上海刑事申诉律师事务所推荐:生效裁判纠错路径与新证据认定 - 律师律所推荐
  • 怎样高效捕获网页媒体:智能资源提取的完整指南
  • GoldHEN金手指管理器:重新定义你的PS4游戏体验
  • C++实现远程控制木马:从Socket通信到进程隐藏的攻防技术剖析
  • 量化策略开发02:海龟三重EMA趋势策略 - 从设计思路到回测验证
  • 2026年跨境魔方领衔:AI外贸客户开发平台综合测评 适配工厂与外贸公司需求的智能拓客工具选型参考
  • WeatherNext 2 :DeepMind发布全球15天天气预报数据集
  • Java开发中Duplicate key异常深度解析与实战解决方案
  • 如何用Pixelle-Video实现零门槛AI短视频创作:新手到专家的完整指南
  • 终极VSCode美化指南:三步打造个性化编程背景环境
  • Unity Remote 5真机调试指南:告别模拟器,实现移动端触摸交互高效开发
  • 如何用PoeCharm打造流放之路完美BD:中文版角色构建终极指南
  • 【CarbonData】CarbonData 的序列化和反序列化框架是如何设计的?
  • 冷启动阶段主播找公会专属流量加热门推荐位扶持 - 产品评测官
  • B站视频下载终极指南:BiliTools让你轻松保存任何B站内容
  • 嵌入式AI情感交互系统:让硬件拥有表情灵魂的架构设计
  • G-Helper终极指南:如何用免费轻量级工具彻底解放华硕笔记本性能
  • AI工具降重降AIGC率效果实测
  • 终极PoeCharm中文版使用指南:3步打造《流放之路》完美角色构建
  • 5个专业技巧:如何快速上手猫抓浏览器资源嗅探扩展
  • 微博图片批量下载:无需登录的自动化采集神器
  • Windows 10 PL-2303老芯片驱动终极解决方案:让废弃设备重获新生
  • 如何用神奇弹幕打造高效智能的B站直播场控系统:7大核心功能与3分钟快速上手指南
  • HBM技术解析:从3D堆叠到SoC集成的工程实践指南
  • Excel逻辑函数IF与IFERROR深度解析:从基础语法到复杂业务场景实战
  • 2026年十大窗帘品牌深度评测:从行业科普到落地避坑,一篇说透高定软装选型逻辑 - 品牌报告
  • 用WorkBuddy+Python+Streamlit构建家电选购数据决策工具
  • 3分钟掌握Obsidian加密技巧:保护你的数字隐私笔记终极指南
  • 程序员求职利器:LaTeX与Overleaf打造专业简历全攻略