跳到主要内容

Sequelize使用手册

什么是Sequelize?

Sequelize是一个基于Promise的Node.js ORM工具,支持PostgreSQL、MySQL、MariaDB、SQLite和Microsoft SQL Server等多种关系型数据库。它提供了强大的模型定义、关联关系处理、查询构建、迁移工具和事务支持,使Node.js应用程序与关系型数据库的交互变得简单而高效。

安装与配置

安装Sequelize和数据库驱动

# 安装Sequelize核心包
npm install sequelize

# 根据您使用的数据库安装对应的驱动
npm install pg pg-hstore # PostgreSQL
npm install mysql2 # MySQL
npm install mariadb # MariaDB
npm install sqlite3 # SQLite
npm install tedious # Microsoft SQL Server

基本配置

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

// 方法1: 传递连接URI
const sequelize = new Sequelize('postgres://username:password@localhost:5432/mydatabase');

// 方法2: 传递参数
const sequelize = new Sequelize('mydatabase', 'username', 'password', {
host: 'localhost',
dialect: 'postgres',
logging: console.log, // 启用查询日志
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
});

// 测试连接
try {
await sequelize.authenticate();
console.log('数据库连接成功');
} catch (error) {
console.error('数据库连接失败:', error);
}

模型定义

定义基本模型

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

const User = sequelize.define('User', {
// 模型属性
firstName: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
lastName: {
type: DataTypes.STRING,
allowNull: false
},
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
age: {
type: DataTypes.INTEGER,
validate: {
min: 18,
max: 120
}
}
}, {
// 模型选项
tableName: 'users', // 自定义表名
timestamps: true, // 自动添加createdAt和updatedAt字段
paranoid: true, // 启用软删除
underscored: true, // 使用蛇形命名法
indexes: [
{
fields: ['email']
}
]
});

// 同步模型到数据库
await User.sync({ alter: true }); // 自动修改表结构

数据类型

Sequelize支持多种数据类型:

  • STRING:字符串
  • TEXT:长文本
  • INTEGER:整数
  • BIGINT:大整数
  • FLOATDOUBLE:浮点数
  • DECIMAL:高精度小数
  • BOOLEAN:布尔值
  • DATE:日期时间
  • DATEONLY:日期
  • UUID:UUID
  • JSONJSONB:JSON数据
  • ENUM:枚举类型

查询操作

基本查询

// 查找所有记录
const users = await User.findAll();

// 查找单个记录
const user = await User.findByPk(1); // 按主键查找
const userByEmail = await User.findOne({ where: { email: 'example@mail.com' } });

// 条件查询
const adults = await User.findAll({
where: {
age: { [Op.gte]: 18 }
}
});

// 分页和排序
const paginatedUsers = await User.findAll({
order: [['createdAt', 'DESC']],
limit: 10,
offset: 20
});

// 选择特定字段
const userNames = await User.findAll({
attributes: ['firstName', 'lastName']
});

// 聚合函数
const result = await User.findAll({
attributes: [
'department',
[Sequelize.fn('COUNT', Sequelize.col('id')), 'userCount']
],
group: 'department'
});

操作符

Sequelize提供了丰富的操作符用于条件查询:

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

const users = await User.findAll({
where: {
[Op.and]: [
{ age: { [Op.gt]: 18 } },
{ lastName: { [Op.like]: '张%' } }
]
}
});

// 常用操作符:
// Op.eq: 等于
// Op.ne: 不等于
// Op.gt: 大于
// Op.gte: 大于等于
// Op.lt: 小于
// Op.lte: 小于等于
// Op.like: 模糊匹配
// Op.in: 在数组中
// Op.notIn: 不在数组中
// Op.between: 在范围内
// Op.notBetween: 不在范围内
// Op.and: 逻辑与
// Op.or: 逻辑或
// Op.not: 逻辑非

关联关系

Sequelize支持多种关联关系:一对一、一对多和多对多。

定义关联

// 一对多关联
const Post = sequelize.define('Post', {
title: DataTypes.STRING,
content: DataTypes.TEXT
});

// 用户与帖子:一对多
User.hasMany(Post, {
foreignKey: 'userId',
as: 'posts'
});
Post.belongsTo(User, {
foreignKey: 'userId',
as: 'author'
});

// 多对多关联
const Tag = sequelize.define('Tag', {
name: DataTypes.STRING
});

// 帖子与标签:多对多
const PostTag = sequelize.define('PostTag', {});

Post.belongsToMany(Tag, {
through: PostTag,
as: 'tags',
foreignKey: 'postId'
});
Tag.belongsToMany(Post, {
through: PostTag,
as: 'posts',
foreignKey: 'tagId'
});

查询关联数据

// 包含关联数据
const usersWithPosts = await User.findAll({
include: [{ model: Post, as: 'posts' }]
});

// 嵌套包含
const postsWithAuthorAndTags = await Post.findAll({
include: [
{ model: User, as: 'author' },
{ model: Tag, as: 'tags' }
]
});

// 条件包含
const usersWithActivePosts = await User.findAll({
include: [{
model: Post,
as: 'posts',
where: { active: true }
}]
});

创建、更新和删除

创建记录

// 创建单个记录
const newUser = await User.create({
firstName: '张',
lastName: '三',
email: 'zhangsan@example.com',
age: 30
});

// 批量创建
const users = await User.bulkCreate([
{ firstName: '李', lastName: '四', email: 'lisi@example.com' },
{ firstName: '王', lastName: '五', email: 'wangwu@example.com' }
]);

// 创建带有关联的数据
const userWithPost = await User.create({
firstName: '赵',
lastName: '六',
email: 'zhaoliu@example.com',
posts: [
{ title: 'Hello World', content: '我的第一篇帖子' },
{ title: 'Node.js开发', content: 'Node.js入门指南' }
]
}, {
include: [{ model: Post, as: 'posts' }]
});

更新记录

// 更新单个记录
const [updatedCount, updatedUsers] = await User.update(
{ lastName: '新名字' },
{
where: { id: 1 },
returning: true // 返回更新后的记录
}
);

// 批量更新
await User.update(
{ status: 'inactive' },
{ where: { lastLogin: { [Op.lt]: new Date(Date.now() - 90 * 24 * 60 * 60 * 1000) } } }
);

删除记录

// 删除单个记录
await User.destroy({ where: { id: 1 } });

// 批量删除
await User.destroy({ where: { status: 'inactive' } });

// 清空表(不推荐在生产环境使用)
await User.destroy({ truncate: true });

事务

Sequelize提供了事务支持,确保一组操作要么全部成功,要么全部失败。

// 使用自动事务(推荐)
const result = await sequelize.transaction(async (t) => {
// 在事务中执行操作
const user = await User.create({
firstName: '交易',
lastName: '用户',
email: 'transaction@example.com'
}, { transaction: t });

const post = await Post.create({
title: '事务测试',
content: '这是一个事务测试',
userId: user.id
}, { transaction: t });

return { user, post };
});

// 手动控制事务
const t = await sequelize.transaction();

try {
const user = await User.create({
firstName: '手动',
lastName: '事务',
email: 'manual@example.com'
}, { transaction: t });

await Post.create({
title: '手动事务测试',
content: '这是一个手动事务测试',
userId: user.id
}, { transaction: t });

await t.commit(); // 提交事务
} catch (error) {
await t.rollback(); // 回滚事务
throw error;
}

钩子(Hooks)

Sequelize提供了生命周期钩子,可以在模型的不同生命周期阶段执行自定义逻辑。

// 定义钩子
User.beforeCreate(async (user, options) => {
// 在创建用户前加密密码
if (user.password) {
user.password = await hashPassword(user.password);
}
});

User.afterCreate(async (user, options) => {
// 在创建用户后记录日志或发送通知
console.log(`用户 ${user.email} 已创建`);
});

// 支持的钩子类型:
// beforeValidate / afterValidate
// beforeCreate / afterCreate
// beforeUpdate / afterUpdate
// beforeDestroy / afterDestroy
// beforeSave / afterSave (包括create和update)
// beforeUpsert / afterUpsert
// beforeBulkCreate / afterBulkCreate
// beforeBulkUpdate / afterBulkUpdate
// beforeBulkDestroy / afterBulkDestroy

迁移工具

Sequelize提供了迁移工具,用于管理数据库架构的变更。

安装Sequelize CLI

npm install --save-dev sequelize-cli
npx sequelize-cli init

创建迁移

npx sequelize-cli migration:generate --name create-users

编写迁移

'use strict';

module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING,
unique: true
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('users');
}
};

运行迁移

npx sequelize-cli db:migrate

回滚迁移

npx sequelize-cli db:migrate:undo
npx sequelize-cli db:migrate:undo:all

Sequelize的优缺点

优点

  1. 多数据库支持:支持PostgreSQL、MySQL、SQLite等多种数据库
  2. 丰富的功能:提供完整的ORM功能,包括关联、事务、迁移等
  3. 强大的查询构建器:支持复杂的SQL查询构建
  4. Promise支持:基于Promise的API设计
  5. TypeScript支持:提供TypeScript定义
  6. 成熟的生态系统:社区活跃,文档完善

缺点

  1. 性能开销:相比原生SQL,有额外的性能开销
  2. 学习曲线:API较为复杂,学习成本较高
  3. 复杂查询的局限性:对于极其复杂的SQL查询,可能需要回退到原始查询

最佳实践

  1. 合理使用连接池:配置适当的连接池大小
  2. 优化查询:使用select、include等选项优化查询性能
  3. 使用事务:对于需要原子性的操作,使用事务确保数据一致性
  4. 索引优化:为频繁查询的字段创建索引
  5. 模型分离:将模型定义分离到不同的文件中
  6. 避免N+1查询问题:合理使用include选项加载关联数据
  7. 使用迁移管理数据库变更:避免手动修改数据库结构

与其他ORM工具对比

相比Prisma、TypeORM等其他ORM工具,Sequelize的主要优势在于成熟度、多数据库支持和丰富的功能。Prisma提供了更好的类型安全性和更简洁的API,而TypeORM则提供了更多的TypeScript集成特性。选择哪种工具应根据项目需求、技术栈和团队偏好来决定。