Skip to content

Node系列 · ORM:Sequelize 简介

ORM(Object-Relational Mapping)把"数据库表行"映射成"JS 对象",让开发者用面向对象的方式操作数据,而不必每次写 SQL。Sequelize 是 Node 生态最成熟的 ORM——本文讲清楚它的核心概念和适用边界。

一、ORM 是什么

ORM(对象关系映射)解决一个根本问题:JS 世界是对象,数据库世界是表和行——怎么让两者无缝对接?

ORM 的核心抽象:

  • 模型(Model) = 表(Table)
  • 实例(Instance) = 行(Row)
  • 属性(Attribute) = 列(Column)

二、ORM 的核心价值

价值说明
屏蔽 SQL不需要拼接 SQL,开发者用 JS 方法操作数据
类型映射DataTypes.STRING / DataTypes.INTEGER 等统一类型定义
模型关联hasMany / belongsTo 一行声明外键关系
数据迁移通过 migrations 管理 schema 变更
数据库无关同一份代码可以切换 MySQL / PostgreSQL / SQLite

三、Node 中的 ORM 选项

ORM风格适用
SequelizePromise / 类模型JS 项目首选
Sequelize(TS)同上 + 类型TS 项目
TypeORM装饰器(TS)TS 项目
PrismaSchema 文件 + 生成TS 项目,现代推荐
KnexQuery Builder(半 ORM)需要手写 SQL 的场景
DrizzleTS 类型安全 + 轻量 ORM新兴

TIP

本指南聚焦 Sequelize——它在 Node 生态中历史最久、社区最成熟、文档最完整。新项目如果想用 TS-first 体验,可以选 Prisma / Drizzle。

四、安装与连接

bash
npm install sequelize mysql2

mysql2 是 Sequelize 操作 MySQL 的底层驱动;不能少。

javascript
const { Sequelize } = require('sequelize');

const sequelize = new Sequelize('myapp', 'root', 'your-password', {
  host: '127.0.0.1',
  port: 3306,
  dialect: 'mysql',                 // 数据库类型
  logging: false,                    // 设为 true 看 SQL 日志
  pool: {
    max: 10,
    min: 0,
    acquire: 30000,
    idle: 10000,
  },
});

// 测试连接
await sequelize.authenticate();
console.log('连接成功');

支持的 dialect:

  • mysql / mariadb
  • postgres
  • sqlite / mssql
  • db2 / oracle

五、核心概念

5.1 DataTypes

Sequelize 用 DataTypes 描述列类型:

javascript
const { DataTypes } = require('sequelize');

const User = sequelize.define('User', {
  id:        { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
  name:      { type: DataTypes.STRING(50), allowNull: false },
  email:     { type: DataTypes.STRING(100), allowNull: false, unique: true },
  age:       { type: DataTypes.INTEGER, defaultValue: 0 },
  isActive:  { type: DataTypes.BOOLEAN, defaultValue: true },
  bio:       { type: DataTypes.TEXT },
  birthDate: { type: DataTypes.DATEONLY },
  metadata:  { type: DataTypes.JSON },
});
DataTypes对应 MySQL
STRINGVARCHAR(255)
TEXTTEXT
INTEGERINT
BIGINTBIGINT
FLOAT / DOUBLEFLOAT / DOUBLE
DECIMAL(p, s)DECIMAL
BOOLEANTINYINT(1)
DATEDATETIME
DATEONLYDATE
JSONJSON
UUIDCHAR(36)

5.2 Model(模型)

模型 = 表的抽象。每个 sequelize.define() 返回一个 Model 类。

javascript
const User = sequelize.define('User', { /* columns */ });

// 默认表名是 model 名复数(User → users)
// 可显式指定:tableName: 'my_users'

5.3 Instance(实例)

实例 = 一行数据。Model.create() 返回 Instance,Model.findOne() 等也返回 Instance:

javascript
const user = await User.create({
  name: 'Alice',
  email: 'alice@example.com',
});

// 实例属性就是行字段
console.log(user.id, user.name, user.email);

// 修改并保存
user.name = 'Alice2';
await user.save();

// 删除
await user.destroy();

5.4 查询接口

javascript
const { Op } = require('sequelize');

// 查询一条
const user = await User.findOne({ where: { id: 1 } });

// 按主键查
const user = await User.findByPk(1);

// 查询多条
const users = await User.findAll({
  where: { isActive: true },
  order: [['id', 'DESC']],
  limit: 10,
});

// 计数
const count = await User.count({ where: { age: { [Op.gt]: 18 } } });

六、ORM 与原始 SQL 的取舍

维度原始 SQL(mysql2)ORM(Sequelize)
性能最优(无中间层)略低(多了对象转换)
可读性复杂 JOIN 易乱模型方法直观
类型安全字符串 SQL,无类型TS 项目类型完整
迁移自己管有 migrations 工具
跨数据库锁死 MySQL 方言一份代码换 PG/SQLite
复杂查询任意 SQL部分场景要 raw SQL
学习成本会 SQL 即可概念多,模型 + 关联 + 迁移

TIP

ORM 不万能。遇到特别复杂的报表查询(多层嵌套、子查询、窗口函数),直接 sequelize.query(sql, { type: SELECT }) 跑 raw SQL 更简单。

七、连接管理

javascript
// 应用退出时关闭连接
process.on('SIGTERM', async () => {
  await sequelize.close();
  process.exit(0);
});

不关连接会让 MySQL 的 Sleep 连接堆积,触发 Too many connections

八、小结

  • ORM 把"表 → 模型 / 行 → 实例 / 列 → 属性",让 JS 开发者用面向对象方式操作数据
  • Sequelize 是 Node 生态最成熟的 ORM;新项目首选,TS 项目可考虑 Prisma
  • 核心概念:DataTypes(类型)、Model(表)、Instance(行)、sequelize.query()(底层 SQL 入口)
  • 永远用占位符或 ORM API,不要拼 SQL
  • 复杂查询可以用 sequelize.query() 跑 raw SQL,不被 ORM 束缚
  • 应用退出时 sequelize.close() 释放连接