Sequelize 日常实践教程
这套教程面向正在使用 Node.js、TypeScript、Sequelize 和 MySQL 开发 Sakila API 的初学者。
它不是 Sequelize API 的逐项翻译,而是围绕日常工作反复出现的问题展开:怎样定义类型可靠的 Model、怎样写 CRUD、什么时候需要事务、怎样处理并发、怎样创建和升级表结构,以及怎样安全地做连表查询。
学习案例
教程贯穿以下案例:
- 项目已有的
admin_user:管理员创建、登录、失败计数、临时锁定和 JWT 版本; - 教程使用的
admin_login_audit:登录审计、外键、索引、一对多关联和连表查询。 - 项目已有的
actor/film/film_actor:多对多关联、关系替换、分页主体和统一锁协议; - 项目已有的
customer/address/city/country,以及rental/payment:嵌套查询、输入验证、DTO、聚合和多步骤创建。
所有数据库对象都遵守项目约定,使用小写 snake_case。示例默认基于 MySQL 8.0.16 或更高版本、InnoDB 和 utf8mb4_0900_ai_ci。之所以明确最低版本,是因为 MySQL 8.0.16 之前虽然能解析 CHECK,却不会真正执行约束。
推荐学习顺序
第一阶段:能够正确写日常代码
- 学习路线与实践环境
- 建立 Sequelize 的正确心智模型
- 连接配置、连接池与环境变量
- 时区与时间字段:避免悄悄偏移 8 小时
- TypeScript 模型定义:从 SQL 到 Model
- Model.init 与表映射配置
- 日常 CRUD 高频接口
- WHERE、排序、分页与字段选择
完成这一阶段后,应该能够回答:
- Model、Model 实例、数据库记录和 API DTO 有什么区别?
findOne()、findAll()、create()和update()分别返回什么?- SQL 类型、Sequelize
DataTypes和 TypeScript 类型是否一致?
第二阶段:管理数据库结构变化
完成这一阶段后,应该停止依赖“只在 DBeaver 中手工执行、仓库里没有记录”的结构变更。每次 DDL 都应成为可评审、可追踪、可重复执行的 Migration。
第三阶段:掌握事务、并发与关联
这一阶段的核心不是记住 transaction 和 include 的写法,而是理解:
- 哪些业务状态必须共同提交或回滚;
- 哪些读取和写入可能被并发请求穿插;
hasMany()与数据库外键分别解决什么问题;include最终对应怎样的JOIN。
第四阶段:形成工程能力
第五阶段:结合 Actor / Customer 深入查询 options
以下新增章节是完成关联练习后的实务补充,不需要从头重读基础篇。示例基于本项目 Sequelize 6.37.8;标注“等价 SQL”的代码用于解释语义,实际 SQL 的别名、主键补列、子查询和查询条数以日志为准。
- 19 从一个客户列表理解查询 options:参数职责、返回类型、日志及常见查询开关。
- 20 WHERE、AND 与 OR:先写括号,再写对象:嵌套逻辑、动态条件、NULL、LIKE 与当前 WhereBuilder 的边界。
- 21 attributes 与结果形状:共享列清单、别名、Model / raw / DTO 与类型限制。
- 22 include 参数实战:JOIN 筛选、国家条件、through、关联排序和 separate。
- 23 排序、分页与计数:稳定排序、distinct、分页子查询、group count 与游标。
- 24 fn、col、literal 与表达式:值与列的区别、嵌套函数、别名、安全边界和 Raw SQL 选择。
- 25 GROUP、HAVING 与聚合:COUNT、金额、ONLY_FULL_GROUP_BY 与 Rental × Payment 放大。
第六阶段:按业务场景选择事务与并发策略
- 26 什么时候需要 transaction?:业务不变量、只读快照、单条原子 SQL、约束、幂等与补偿的取舍。
- 27 悲观锁、乐观锁与 MySQL 锁:统一父行锁协议、MVCC、锁范围、版本号与双会话实验。
第七阶段:复盘这次练习中的问题
- 28 模型类型、关联字段与 DTO 答疑:NonAttribute、CreationOptional、asserts、官方 Mixin 与未建 Model 的查询。
- 29 await、reload 与事务可见性答疑:Promise 判空、连接池、未提交记录、提交时机与重试。
- 30 查询调试与验证答疑:matchedData、白名单、false/null/数组、聚合字符串与分层测试。
针对这次疑问的最短阅读路径:20 → 22 → 24 → 26 → 27;类型与 reload 问题分别查 28、29,金额与 count 查 25、30。
每章怎样学习
不要只复制教程代码。部分片段省略了已有 imports、业务参数或辅助函数,应放回对应 Service 上下文理解;它们不是要求立即替换现有实现。建议对每个示例执行下面的循环:
先预测 SQL 和返回值
→ 编写或运行 Sequelize 代码
→ 查看 Sequelize SQL 日志
→ 在 MySQL CLI/DBeaver 验证数据
→ 制造一个失败或并发场景
→ 解释为什么会得到这个结果
建立四层对照表是最重要的习惯:
MySQL DDL
↕
Sequelize DataTypes 和 Model 配置
↕
TypeScript 属性、创建参数和查询返回类型
↕
API DTO
任何一层改变,都要判断其他层是否需要同步。
SQL 中的 :参数 由 Sequelize 的 replacements 处理,MySQL CLI/DBeaver 手工执行时须改成具体值或 @会话变量;带 ... 的 SQL 是语义示意,先补全再执行。写入与锁实验只在独立练习库进行。
练习环境安全约定
- 使用单独的本地练习数据库,不在生产库实验 DDL、锁或删除操作;
- 不把真实密码、JWT、数据库 Secret 写入源码、SQL 文件或日志;
- 执行
UPDATE、DELETE前先用相同WHERE执行SELECT; - 不在重要数据库运行
sync({ force: true })或未经评审的sync({ alter: true }); - 事务和行锁练习至少开启两个数据库会话,亲自观察等待、提交和回滚;
- 表结构修改先保留成 Migration,再执行,不把 DBeaver 的历史窗口当作变更记录。
学完后的验收目标
完成整套教程后,你应该能够独立完成:
- 从业务规则设计 DDL 和索引;
- 将 DDL 准确映射为 TypeScript Sequelize Model;
- 使用高频 CRUD 和查询接口完成 Service;
- 判断是否需要事务并正确传递
transaction; - 使用行锁或原子更新解决丢失更新;
- 使用 Association 和
include编写并分析连表查询; - 通过版本化 Migration 创建和升级数据库;
- 识别唯一约束、外键、分页、N+1、日志泄露等常见问题;
- 使用真实 MySQL 验证 Migration、事务和并发行为。