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:大整数FLOAT、DOUBLE:浮点数DECIMAL:高精度小数BOOLEAN:布尔值DATE:日期时间DATEONLY:日期UUID:UUIDJSON、JSONB: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的优缺点
优点
- 多数据库支持:支持PostgreSQL、MySQL、SQLite等多种数据库
- 丰富的功能:提供完整的ORM功能,包括关联、事务、迁移等
- 强大的查询构建器:支持复杂的SQL查询构建
- Promise支持:基于Promise的API设计
- TypeScript支持:提供TypeScript定义
- 成熟的生态系统:社区活跃,文档完善
缺点
- 性能开销:相比原生SQL,有额外的性能开销
- 学习曲线:API较为复杂,学习成本较高
- 复杂查询的局限性:对于极其复杂的SQL查询,可能需要回退到原始查询
最佳实践
- 合理使用连接池:配置适当的连接池大小
- 优化查询:使用select、include等选项优化查询性能
- 使用事务:对于需要原子性的操作,使用事务确保数据一致性
- 索引优化:为频繁查询的字段创建索引
- 模型分离:将模型定义分离到不同的文件中
- 避免N+1查询问题:合理使用include选项加载关联数据
- 使用迁移管理数据库变更:避免手动修改数据库结构
与其他ORM工具对比
相比Prisma、TypeORM等其他ORM工具,Sequelize的主要优势在于成熟度、多数据库支持和丰富的功能。Prisma提供了更好的类型安全性和更简洁的API,而TypeORM则提供了更多的TypeScript集成特性。选择哪种工具应根据项目需求、技术栈和团队偏好来决定。