MySQL 入门:库、表、行、主键是什么 个人主页会编程的土豆欢迎来访作者简介后端学习者❄️个人专栏数据结构与算法数据库leetcode✨那些你一个人走过的夜路终将化作照亮未来的光系列《影院票务 GO》知识点博客 · 第 6 篇对应文件sql/schema.sql、sql/seed.sql以及config/config.go里的 DSN写在前面票务系统所有「记得住」的东西——用户账号、电影、场次、座位状态、订单——最后都落在MySQL里。Go 程序重启后内存 Session 会丢数据库里的订单还在。学长可能问「库和表啥区别为什么每张表都有 idDECIMAL 和 FLOAT 有啥不一样」本篇用最直白的方式建立数据库世界观并对照本项目的ttms库。不涉及复杂 SQL 语法细节那是第 7 篇先把名词和表结构讲透能和models/models.go对上号。1. 四级概念从服务器到单元格MySQL 服务器进程默认端口 3306 └── 数据库 Database如 ttms └── 表 Table如 users、movies、orders └── 行 Row一条用户、一笔订单 └── 列 Columnusername、amount、status…概念类比项目例子服务器整栋图书馆大楼你电脑上的 MySQL 8 服务数据库一个分馆 / 一个项目专属书架区ttms表一种登记册users、seats、orders行登记册里的一行用户admin那一行列登记项username、password、role脚本开头schema.sqlDROP DATABASE IF EXISTS ttms; CREATE DATABASE ttms DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE ttms;含义若已有ttms库则删掉开发脚本危险操作生产绝不用创建新库指定字符集USE ttms进入该库后面CREATE TABLE都建在这里和 Go 的衔接config.Load()默认 DSN 末尾是/ttms?charsetutf8mb4...——连的就是这个库名。2. 为什么需要数据库不用文件行吗可以把订单写进orders.txt。小 demo 可以票务系统不行因为数据库擅长能力文件方案的痛点结构化查询找「某用户所有待支付订单」要扫全文并发安全两人同时买同一座文件很难原子更新约束用户名重复、外键引用靠自觉持久与恢复文件也能持久但缺少事务、备份生态索引按时间查场次表上有INDEX课程项目必须用 MySQL也是为了练事务、行锁、外键——后面第 16、17 篇的主线。3. 本项目表关系鸟瞰schema.sql建的表简化关系users ─────┬──── orders ──── schedules ──── movies │ │ │ └── halls ├── comments ──── movies ├── ratings ──── movies │ movie_groups ── movies schedules ── seats每场次一批座位表存什么users登录账号、角色movie_groups动作/科幻等分类movies电影元数据、评分汇总halls影厅名、行列数schedules哪部电影、哪个厅、几点、票价seats某场次下每个格子的状态orders订单号、座位摘要、金额、支付截止comments评论与回复parent_idratings用户对电影 1–10 分Go 里models包与这些表一一对应第 5 篇。4. 主键 PRIMARY KEY几乎每张表都有id BIGINT PRIMARY KEY AUTO_INCREMENT概念含义主键唯一标识一行不能重复、不能 NULL惯例AUTO_INCREMENT插入时不写 idMySQL 自动分配 1, 2, 3…BIGINT64 位整数id 空间大为什么几乎都用 surrogate key代理主键id关联方便orders.user_id→users.id业务字段会变昵称可改username 理论上也可改id 稳定Join 性能整数比长字符串做主键更常见拓展自然键用username或order_no当主键理论上可以但order_no在本项目仍是UNIQUE 业务键主键仍是id——两套并存见思考题。5. 常见列类型对照 schema5.1 字符串username VARCHAR(50) NOT NULL UNIQUE password CHAR(32) NOT NULL description TEXT seat_info VARCHAR(255)类型特点项目用途VARCHAR(n)可变长最多 n 字符用户名、标题CHAR(n)定长不足补空格存比较时MD5 十六进制固定 32 位TEXT长文本电影简介5.2 数值role TINYINT NOT NULL DEFAULT 0 duration INT NOT NULL DEFAULT 120 amount DECIMAL(10,2) NOT NULL DEFAULT 0 rating_avg DECIMAL(3,1) NOT NULL DEFAULT 0.0类型用途TINYINT小整数、枚举状态0/1/2INT时长分钟、计数DECIMAL(p,s)精确小数金额、评分钱为什么用 DECIMAL 不用 FLOATFLOAT/DOUBLE 是二进制浮点0.1 0.2在计算机里不精确票价 45.00、订单 90.00 必须精确到分GoScan进float64对课程够用金融系统常用整数「分」或 decimal 库rating_avg DECIMAL(3,1)最多 3 位数字、1 位小数如 9.3、10.0思考题最大值5.3 时间created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP start_time DATETIME NOT NULL pay_deadline DATETIME NOT NULL paid_at DATETIME NULLGo DSN 里parseTimetruelocLocal才能把 DATETIME 扫进time.Time。6. 约束数据库帮你守门username VARCHAR(50) NOT NULL UNIQUE约束含义NOT NULL不能空UNIQUE不能重复DEFAULT缺省值PRIMARY KEY主键唯一FOREIGN KEY引用父表必须存在例订单表CONSTRAINT fk_order_user FOREIGN KEY (user_id) REFERENCES users(id), CONSTRAINT fk_order_sch FOREIGN KEY (schedule_id) REFERENCES schedules(id),插入user_id99999若 users 里没有 →拒绝防止孤儿订单。座位表UNIQUE KEY uk_seat (schedule_id, row_no, col_no),同一场次同一排座不能重复两行——防数据脏。应用层也要校验但约束是最后一道防线。7. 索引 INDEX入门INDEX idx_sch_start (start_time), INDEX idx_order_user (user_id), INDEX idx_seat_lock (status, lock_until),索引像「书的目录」按用户查订单、按时间查场次、清理任务扫超时锁座不必全表扫描。代价插入/update 要维护索引小项目数据量小感觉不明显大数据量关键。8. 引擎 InnoDB) ENGINEInnoDB;每张表末尾都有。引擎特点InnoDB事务、行级锁、外键——购票必备MyISAM老无事务不适合订单锁座本项目全部 InnoDB。CreateOrderWithSeats里BEGINFOR UPDATE依赖 InnoDB 行锁第 17 篇。9. 字符集 utf8mb4DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci名称说明utf8mb4完整 UTF-8含中文、emoji4 字节utf8MySQL 旧名最多 3 字节不完整电影名、评论、昵称可能有 emojiDSN 也要charsetutf8mb4。乱码排查客户端编码、表字符集、连接 charset 三者一致。10. schema vs seed文件作用本项目特点schema.sql建库建表结构开头DROP DATABASE会清空整个库seed.sql插入演示数据内容默认账号、电影、场次典型开发流程1. 改表结构 → 编辑 schema.sql → 在 MySQL 里执行 2. 需要演示数据 → 执行 seed.sql依赖 schema 已建好 3. 启动 Go → db.Init Ping ttms 成功db.Init失败时的提示连接 MySQL 失败: ...请先执行 sql/schema.sql 和 sql/seed.sql说明库不存在、表不存在、MySQL 没启动都会 Ping 失败。10.1 seed 里有什么管理员admin/admin123、顾客user/user123密码 MD5盐第 13 篇讲5 部电影、3 个影厅、若干未来场次执行 seed 后才有首页列表可点11. 单表精读usersCREATE TABLE IF NOT EXISTS users ( id BIGINT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password CHAR(32) NOT NULL COMMENT MD5(passwordsalt), salt VARCHAR(16) NOT NULL, nickname VARCHAR(50) NOT NULL DEFAULT , phone VARCHAR(20) NOT NULL DEFAULT , role TINYINT NOT NULL DEFAULT 0, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB;列对应 models.UseridID int64usernameUsernamepasswordPasswordjson:“-”role 0/1RoleCustomer / RoleAdmin12. 单表精读seats 与 ordersseats——购票并发核心status TINYINT NOT NULL DEFAULT 0, -- 0空闲 1锁定 2已售 lock_user_id BIGINT NULL, lock_until DATETIME NULL, order_id BIGINT NULL,和models.Seat、SeatFree/Locked/Sold常量一致。ordersorder_no VARCHAR(32) NOT NULL UNIQUE, seat_info VARCHAR(255) NOT NULL DEFAULT , amount DECIMAL(10,2) NOT NULL DEFAULT 0, status TINYINT NOT NULL DEFAULT 0, pay_deadline DATETIME NOT NULL,order_no业务可见id内部关联 seats.order_id。13. 和 Go 的三层连接预告后续篇Go 应用 database/sql标准库接口 go-sql-driver/mysql驱动db 包 _ 导入 MySQL 服务器 :3306 数据库 ttms组件文件DSN 字符串config/config.gosql.OpenPingdb/db.go执行 SQLdao/*.go行 → structScan进models.*本篇不讲SELECT/INSERT语法细节——那是07 · SQL 增删改查。本篇不讲连接池参数——那是08 · database/sql。14. 拓展客户端怎么执行脚本方式任选mysql -u root -p sql/schema.sql mysql -u root -p sql/seed.sql或在 Navicat / DBeaver / MySQL Workbench 里打开文件执行。执行前确认连的是开发机不是生产。15. 常见误区「数据库 MySQL 软件」常混MySQL 是服务器软件ttms是它里面的一个 database。「没有 schema 也能 go run」db.InitPing 会失败main Fatal 退出。「FLOAT 存票价省空间」省那点空间不值得丢精度。「DROP DATABASE 和 DELETE 一样」DROP 整个库没了DELETE 删行。schema 开头 DROP 是重置开发环境。「3306 和 8080 是一个服务」MySQL 3306Go HTTP 8080。浏览器访问 3306 不对第 1 篇思考题。16. 项目代码对照概念位置建库建表sql/schema.sql演示数据sql/seed.sql连接串config/config.go→TTMS_DSN环境变量连接池db/db.go→Init表 → structmodels/models.go读写行dao/user.go,dao/order.go, …启动检查清单□ MySQL 服务已启动 □ 已执行 schema.sql有 ttms 库和表 □ 已执行 seed.sql有 admin/user 和电影 □ config DSN 用户名密码与本地 MySQL 一致 □ go run . 看到「MySQL 连接成功」和 8080 启动日志17. 小结口述稿MySQL 用库、表、行、列组织数据我们项目库名是 ttms。主键 id 自增用来稳定关联业务号 order_no 另设 UNIQUE。金额用 DECIMAL状态用 TINYINT和 Go 常量数值对应。InnoDB 支持事务和行锁utf8mb4 支持中文和 emoji。schema 管结构会 DROP 重建seed 管演示数据Go 通过 DSN 连 ttms。18. 思考题为什么orders.order_no也 UNIQUE同时还要有id主键rating_avg DECIMAL(3,1)最大能表示多少最小呢若把座位status存成字符串locked而不是 0/1/2在 SQL 和 Go 里各有什么优缺点DROP DATABASE IF EXISTS ttms的危险是什么生产环境能随便跑 schema 吗DSN 里parseTimetrue若去掉Go 里 Scan 到time.Time会怎样19. 下一篇预告《07 · SQL 增删改查与 dao 对应》——SELECT/INSERT/UPDATE/DELETE 在本项目里的真实写法以及QueryRow、Query、Exec和Scan怎么配合

本月热点