文章目录
一、官方地址(中文版):
https://github.com/demopark/sequelize-docs-Zh-CN
二、新建工程
- ① 新建文件夹,打开终端,输入
npm init -y - ② 在目录下,新建
index.js文件
三、安装
3.1 安装数据库驱动
npm i mysql2
3.2 安装 Sequelize
npm i sequelize
四、使用
4.1 代码
- ①、在根目录下新建
models文件夹,新建db.js,代码如下:
const { Sequelize } = require('sequelize');
module.exports = new Sequelize('数据库表名', '数据库用户名', '数据库密码', {
host: 'localhost', // 本地服务,也可以线上服务
dialect: 'mysql' // 数据库类型
});
- ②、在根目录下的
index.js中书写代码:
const sequelize = require('./models/db');
// 测试连接
(async function () {
try {
await sequelize.authenticate();
console.log('Connection has been established successfully.');
} catch (error) {
console.error('Unable to connect to the database:', error);
}
})();
4.2 测试连接
- 在本地的MySQL中新建一张表(对应上面配置的’数据库表名’)。
- 运行
node index.js,成功的话,控制台会显示'Connection has been established successfully.'。

五、模型
模型相当于数据库中的一张表的概念
- ①、例如数据库有一张 管理员 的表,那么在
models文件夹下新建Admin.js文件:
const { DataTypes } = require('sequelize');
const sequelize = require('./db');
const Admin = sequelize.define('Admin', {
// 第二个参数,定义模型属性(也就是列,id可以省略)
loginId: {
type: DataTypes.STRING, // 该列是 字符串型
allowNull: false // 是否可以 null 值
},
loginPwd: {
type: DataTypes.STRING,
allowNull: false
},
nickName: {
type: DataTypes.STRING,
allowNull: false
}
},{
// 这是第三个参数,可以不写(默认)
});
// 导出模型,后续可以对Admin进行管理
module.exports = Admin; // 在数据库里会生成 Admins 的表名,自动推算成复数形式,若自定义参照文档
- ②、在
index.js中 同步模型
const Admin = require('./models/Admin');
// 模型同步
(async function () {
// Admin.sync(); // 如果表不存在,则创建。若存在,则不创建
// Admin.sync({ force: true }); // 强制创建表,会覆盖之前表
// 如果表不存在,则创建。若存在,则进行比对,比对有差异进行修改
Admin.sync({ alter: true });
})();
- ③、执行成功后,刷新数据库,发现新增一个
admins表。如下:

- ④、第三个参数
{
// 这是第三个参数,可以不写(默认)
createdAt: false, // 不想要 createdAt(也可以将false写成 想要的字符串)
updatedAt: 'updateTime', // 想要 updatedAt 名称改成 updateTime
paranoid: true, // 该表数据不会被真正删除,会增加一列deleteAt 用来记录删除的时间
deletedAt: 'deleteTime', // 配合 paranoid 使用,自定义删除列的名称
}
- ⑤、一次同步所有模型,新建
sync.js文件, 直接node sync.js
require('./Admin');
require('./Book');
require('./Class');
require('./Student');
const sequelize = require('./db');
sequelize.sync({ alter: true }).then(() => {
console.log('模型已全部同步完成')
})
- ⑥、表外联:对应文档中的关联部分。
假如 班级 和学生有个映射,在班级表中:
const { DataTypes } = require('sequelize');
const sequelize = require('./db');
const Student = require('./Student'); // 引入学生表
const Class = sequelize.define('Class',{
className: {
type: DataTypes.STRING,
allowNull: false
},
classStart: {
type: DataTypes.STRING,
allowNull: false
}
},{
createdAt: false,
updatedAt: false,
paranoid: true
});
// 表示一个班级拥有多个学生
Class.hasMany(Student); // 当前表外联 Student 表
module.exports = Class;
六、增删改查
- ①、根目录下新建
services文件夹,新建adminService.js:
// 管理员初始化,判断数据库中是否有管理员,如果没有,则自动添加一个默认管理员(或超级管理员)
const Admin = require('../models/Admin');
/**
* 添加管理员
* @param obj Object
* @param operatorId String 操作者的id
*/
exports.addAdmin = async function(obj, operatorId) {
// 方式一
// const ins = Admin.build(obj);
// ins.save().then(() => {
// console.log('第一个管理员成功了')
// })
// 方式二,相当于上面的 构建完自动运行
const ins = await Admin.create(obj);
console.log('admin 添加成功')
return ins.toJSON(); // 返回ins的平面对象
}
/**
* 删除管理员
* @param id
*/
exports.deleteAdmin = async function(id) {
// 方式一: ①得到实例、②删除实例
// const ins = await Admin.findByPk(id)
// await ins.destroy();
// 方式二:比上面省一条SQL语句
await Admin.destroy({
where: {
id
}
})
}
/**
* 修改管理员
* @param obj
*/
exports.modifyAdmin = async function(id, obj) {
// 方式一:
// const ins = await Admin.findByPk(id);
// ins.loginPwd = obj.loginPwd;
// ins.save();
// 方式二:
await Admin.update(obj, {
where: {
id
}
})
}
/**
* 单个查询 - 登陆查询
* @param loginId
* @param loginPwd
* @returns {Promise<*>}
*/
exports.login = async function(loginId, loginPwd) {
// const res = await Admin.findOne({
// where: {
// loginId,
// loginPwd
// }
// })
// // 如果有结果了,且大小写都相同的话,那么返回,并展开
// if(res && res.loginId === loginId && res.loginPwd === loginPwd) {
// return res.toJSON();
// }
// return null;
// 使用了 md5 方式
loginPwd = md5(loginPwd);
const res = await Admin.findOne({
where: {
loginId,
loginPwd
},
attributes: ['id', 'loginId', 'nickName', 'createdAt'], // 返回指定字段的内容
})
// 如果有结果了,且大小写都相同的话,那么返回,并展开
if(res && res.loginId === loginId) {
return res.toJSON();
}
return null;
}
/**
* 按主键查询
* @param id
* @returns {Promise<void>}
*/
exports.getAdminById = async function(id) {
const res = await Admin.findByPk(id);
if(res) {
return res.toJSON();
}
return null;
}
// 另一张表,分页查询示例
/**
* 查询所有学生 - 分页
* @returns {Promise<string>}
*/
exports.getStudent = async function(page = 1, limit = 10, sex = -1, name = "") {
// 方式一
// const res = await Student.findAll({
// offset: (page - 1) * limit,
// limit: +limit
// })
// const total = await Student.count();
// const data = JSON.parse(JSON.stringify(res));
// return {
// total,
// data
// }
// 方式二
// const { count, rows } = await Student.findAndCountAll({
// offset: (page -1) * limit,
// limit: +limit,
// })
// return {
// count,
// data: JSON.parse(JSON.stringify(rows))
// }
// 如果带条件的话
const condition = {}
if(sex != -1) {
condition.sex = !!sex; // 强制取反,变成布尔类型,再取反变回原数据(解决了 0, 1 以外的数字)
}
// if(name) { // 精准查询
// condition.name = name
// }
// 使用 sequelize 的api:Op,进行 模糊查询
if(name) {
condition.name = {
[Op.like]: `%${name}%`
}
}
const { count, rows } = await Student.findAndCountAll({
where: condition,
offset: (page - 1) * limit,
limit,
attributes: ['id', 'name', 'sex'], // 查出来的,只包含这些
include: [Class], // 查出关系表 对应的内容
});
return {
count,
data: JSON.parse(JSON.stringify(rows))
}
}
- ②、测试,在
index.js中
const adminService = require('./services/adminService');
// 增加
// adminService.addAdmin({
// loginId: 'thirdAdmin',
// loginPwd: '123123',
// nickName: '第三个管理员'
// })
// 删除
// adminService.deleteAdmin(2)
// 修改
// adminService.modifyAdmin(1, {
// loginPwd: '999666'
// })
// 查询所有学生
// studentService.getStudent(1, 5, 1, '秀').then(res => {
// console.log(res);
// })
七、使用事务
const sequelize = require('../models/db');
// 使用事务后 添加
exports.addAdmin = async function(obj) {
try {
const result = await sequelize.transaction(async (t) => {
obj.loginPwd = md5(obj.loginPwd)
const ins = await Admin.create(obj, { transaction: t });
// throw new Error(); // 模拟错误,正常注释掉
return ins.toJSON(); // 如果执行到此行,则表示事务已成功提交,`result`是事务返回的结果,这种情况下,result 中的数据就是 user
});
} catch (error) {
console.log("数据回滚\n" + error);
}
}
八、表关联
在 models下,新建 relation.js
// 设置外键,表关联
const Class = require('./Class');
const Student = require('./Student');
Class.hasMany(Student);
Student.belongsTo(Class);
在 index.js 中,引入即可
// 外键,表外联
require('./models/relation');
九、md5加密
安装 npm install md5
在 adminService.js 中,一般也就 登陆密码的地方需要加密
const Admin = require('../models/Admin');
const md5 = require('md5');
/**
* 添加管理员
* @param obj Object
* @param operatorId String 操作者的id
*/
exports.addAdmin = async function(obj, operatorId) {
// 使用 md5 加密
obj.loginPwd = md5(obj.loginPwd);
const ins = await Admin.create(obj);
return ins.toJSON();
}
/**
* 删除管理员
* @param id
*/
exports.deleteAdmin = async function(id) {
// 方式一: ①得到实例、②删除实例
// const ins = await Admin.findByPk(id)
// await ins.destroy();
// 方式二:比上面省一条SQL语句
await Admin.destroy({
where: {
id
}
})
}
/**
* 修改管理员
* @param obj
*/
exports.modifyAdmin = async function(id, obj) {
// 使用 md5 方式
if (obj.loginPwd) {
obj.loginPwd = md5(obj.loginPwd)
}
await Admin.update(obj, {
where: {
id
}
})
}
/**
* 单个查询 - 登陆查询
* @param loginId
* @param loginPwd
* @returns {Promise<*>}
*/
exports.login = async function(loginId, loginPwd) {
// 使用了 md5 方式
loginPwd = md5(loginPwd);
const res = await Admin.findOne({
where: {
loginId,
loginPwd
}
})
// 如果有结果了,且大小写都相同的话,那么返回,并展开
if(res && res.loginId === loginId && res.loginPwd === loginPwd) {
return res.toJSON();
}
return null;
}
/**
* 按主键查询
* @param id
* @returns {Promise<void>}
*/
exports.getAdminById = async function(id) {
const res = await Admin.findByPk(id);
if(res) {
return res.toJSON();
}
return null;
}
十、数据验证和时间处理
- 验证使用 validate,安装
npm install validate.js - 时间使用 moment,安装
npm install moment - 给validate继承一个时间处理方法,在service目录下,新建
init.js
const validate = require('validate.js');
const moment = require('moment');
validate.extend(validate.validators.datetime, {
/**
* 该函数会自动用于日期格式转换
* 它会在验证时自动触发,它需要将任何数据转换为时间戳返回
* 如果无法转换,返回NaN
* @param {*} value 传入要转换的值
* @param {*} options 针对某个属性的验证配置
*/
parse(value, options) {
let formats = ['YYYY-MM-DD HH:mm:ss', 'YYYY-M-D H:m:s', 'x'];
if(options.dateOnly) {
formats = ['YYYY-MM-DD', 'YYYY-M-D', 'x'];
}
return +moment.utc(value, formats, true);
},
/**
* 用于显示错误消息时,使用的显示字符串
* @param {*} value 传入要转换的值
* @param {*} options 针对某个属性的验证配置
*/
format(value, options) {
let format = 'YYYY-MM-DD';
if(!options.dateOnly) {
format += 'HH:mm:ss';
}
return moment.utc(value).format(format)
}
})
设置过滤函数,在 util 目录下,新建 propertyHelper.js
/**
* 传来一个对象,挑选部分属性
* @param obj
* @param props
* @returns {{}|*}
*/
exports.pick = function(obj, ...props) {
if(!obj || typeof obj !== 'object') {
return obj
}
const newObj = {};
for (const key in obj) {
if(props.includes(key)) {
newObj[key] = obj[key];
}
}
return newObj;
}
以添加学生为例:
const Student = require('../models/Student');
const { Op } = require('sequelize');
const validate = require('validate.js');
const moment = require('moment');
// 假如传过来的对象中有 deletedAt 字段,我并不想要,所以自定义挑选
const { pick } = require('../util/propertyHelper');
const Class = require('../models/Class');
/**
* 添加学生
* @param obj
* @returns {Promise}
*/
exports.addStudent = async function(obj) {
// 挑选 过滤
obj = pick(obj, 'name', 'birthDay', 'sex', 'phone', 'ClassId')
// 写到下面的classId时,得判断传的班级id存不存在,可以在验证规则里自定义一个方法
validate.validators.classExist = async function(value) {
const exist = await Class.findByPk(value);
if (exist) {
return;
}
return 'is not exist'
}
// 使用验证
const result = validate.async(obj, {
name: {
// presence: true
presence: {
allowEmpty: false
}
},
birthDay: {
presence: {
allowEmpty: false
},
datetime: {
dateOnly: true,
earliest: +moment.utc().subtract(100, 'y'), // 最早不能超过100年
latest: +moment.utc().subtract(5, 'y') // 最晚不能小于5年
}
},
sex: {
presence: true,
type: 'boolean'
},
phone: {
presence: {
allowEmpty: false
},
format: /1\d{10}/
},
ClassId: {
presence: true,
// type: 'integer', // 比较严格
numericality: { // 宽松
onlyInteger: true,
strict: false, // 关闭严格模式
},
classExist: true, // 此处见本方法的第一行,自定义验证规则
}
})
// console.log(result); // 通过:undefined,不通过则报错
result.then(res=> {
console.log('通过了')
Student.create(obj).then(ins => {
console.log('开始添加')
return ins.toJSON();
});
}).catch( err => {
console.log(err)
})
}
在index.js 中测试
studentService.addStudent({
name: '大大大',
birthDay: '2012-04-14',
sex: true,
phone: "13913913913",
ClassId: 2,
deleteAt: '2022-05-03'
})
十一、访问器和虚拟字段
1)访问器
假如查询学生表,出来的是这样的,标准的时间格式,并不是我想要的

- 需要设置访问器,相当于 get/set 方法。
- 在模型那里,student.js 中birthDay 设置如下:
birthDay: {
type: DataTypes.DATE,
allowNull: false,
get() {
// this指模型本身,通过自带的方法getDataValue获取birthDay,转换成时间戳
return this.getDataValue('birthDay').getTime();
}
},
2)虚拟字段
在模型中没有的字段,想使用的话。例如模型中没有age 字段,那么在模型中如下:
const moment = require("moment");
age: {
type: DataTypes.VIRTUAL,
get() {
const now = moment.utc();
const birth = moment.utc(this.birthDay);
return now.diff(birth, 'y') // 得到两个日期的年份差异
}
},

十二、日志记录
使用第三方库,安装 npm install log4js
在 index.js 中测试
const log4js = require('log4js');
const logger = log4js.getLogger();
logger.level = 'all'; // 将日志级别调成all(最低),默认off(最高)不显示。具体看官网
logger.info('abc');

- 正式书写:在根目录下新建
logger.js
const { resolve } = require('path');
const log4js = require('log4js');
log4js.configure({
// 出口设置
appenders: {
sql: { // 定义一个sql日志出口
type: "dateFile", // file: 文件,dateFile:带日期的文件
filename: resolve(__dirname, 'logs', 'sql', 'logging.log'), // 出口的路径和名称
maxLogSize: 1024 * 1024, // 配置文件的最大字节数,防止文件过大,字节单位。达到这个长度,则自动新增一个文件
keepFileExt: true, // 当备份时,以log为后缀名
numBackups: 1, // 只保留1个,之前的不要
layout: {
type: "pattern", // 自定义格式
pattern: '%d{yyyy-MM-dd hh:mm:ss} %p %c: %m %n', // 时间 级别 类型 内容 换行
}
},
default: {
type: 'stdout'
}
},
categories: {
sql: {
appenders: ['sql'], // 该分类使用出口sql的配置写入日志
level: 'all', // 级别最低
},
default: {
appenders: ['default'],
level: 'all'
}
}
})
// 在程序退出或崩溃时调用下shutdown,防止没有记录完
process.on('exit', () => {
log4js.shutdown();
})
const sqlLogger = log4js.getLogger('sql');
const defaultLogger = log4js.getLogger('default');
exports.sqlLogger = sqlLogger;
exports.logger = defaultLogger;
- 应用到数据库中:在
db.js中
const { Sequelize } = require('sequelize');
const { sqlLogger } = require('../logger');
module.exports = new Sequelize('test', 'root', '123123', {
host: 'localhost',
dialect: 'mysql',
logging: sql => {
sqlLogger.debug(sql);
}
});
- 然后在
index.js中查询数据测试
studentService.getStudent(1, 5).then(res => {
console.log(res)
})

本文档详细介绍了如何使用 Sequelize,一个基于 Promise 的 Node.js ORM(对象关系映射),适用于 MySQL、Postgres、MariaDB、SQLite 和 Microsoft SQL Server。内容包括安装、连接数据库、创建模型、增删改查操作、事务处理、表关联、数据验证、时间处理、访问器和虚拟字段,以及日志记录等核心功能。
1389

被折叠的 条评论
为什么被折叠?



