前言
关于第二阶段的内容, 前面我们介绍了restful API设计、路由分组、路由重定向。
这篇我们介绍第二阶段的最后内容:CRUD 操作(对数据表的增删改查)。
在了解和使用CRUD操作之前,我们首先了解和express搭配使用数据库的相关知识,本篇主要介绍的是sequelize+mysql。
一、Sequelize
1、什么是 Sequelize?
Sequelize 简介 | Sequelize中文文档 | Sequelize中文网
Sequelize 是一个基于 Node.js 的 ORM(对象关系映射)工具,用于与关系型数据库(如 MySQL、PostgreSQL 等)进行交互。
它允许开发者使用 JavaScript 对象来操作数据库,而无需直接编写 SQL 语句。
2、Sequelize 的优势
抽象化:将数据库操作抽象为 JavaScript 对象,简化数据库交互。
安全性:自动处理 SQL 注入等安全问题。
易用性:提供丰富的 API,支持同步和异步操作。
灵活性:支持多种数据库,易于迁移和扩展。
二、安装和配置 Sequelize
1、安装 Sequelize 和 MySQL
npm install --save sequelize mysql2
2、连接数据库
官网上提供了三种连接方法。本篇文章采用的是第三种。
// 官网上提供的方法 3: 分别传递参数
const sequelize = new Sequelize('database', 'username', 'password', {
host: 'localhost',
dialect: /* one of 'mysql' | 'postgres' | 'sqlite' | 'mariadb' | 'mssql' | 'db2' | 'snowflake' | 'oracle' */
});
本篇新创建一个express应用程序,进行演示连接数据库等操作。
(而非在前面系列文章的项目基础上进行演示。)
下面是express-generator的安装和使用。
//本篇演示案例的node版本:18.16.1
//安装
npm i -g express-generator
//创建express应用程序 代码:express 名称
express crud_demo
//跟着提示往下操作

在新建service/dbConnect.js。
注意:连接数据库前,确保你已经在运行你的数据库。
(数据库的下载安装和运行,非本篇重点,不进行介绍。)
数据库可视化管理工具,我用的是navicat(数据库已经是运行状态)。


// service/dbConnect.js 该文件负责连接数据库
const { Sequelize } = require("sequelize");
// 创建数据库连接 //对应替换上你自己的数据库信息(数据库名称、账号、密码、地址/端口)
const sequelize = new Sequelize("mysite2", "root", "xxxx", {
host: "localhost", //一般是固定写“localhost”,如果你也是根据我上面的配置。
dialect: 'mysql',
logging: false
});
const startDB=async()=> {
try {
await sequelize.authenticate();
console.log('数据库已建立起连接.');
} catch (error) {
console.error('Unable to connect to the database:', error);
}
}
startDB()
// 向外暴露这个连接实例
module.exports = sequelize;
在app.js中引入连接。
// 引入数据库连接
require("./service/dbConnect")
完整代码:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
// 引入数据库连接
require("./service/dbConnect")
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
启动服务器,查看连接情况。
npm run start
有安装nodemon则使用下面这条语句。
(安装nodemon库: npm install -g nodemon)
nodemon npm start
连接成功。
3、定义一个数据模型(数据表)
定义模型是 Sequelize 的核心功能之一。模型是 Sequelize 中的一个概念,它对应着数据库中的表。以下是一个简单的用户模型示例:
新建service/model/userModel.js:

//model/userModel.js
const { DataTypes } = require("sequelize");
const sequelize = require("../dbConnect");
// 定义数据模型
module.exports = sequelize.define("user", {
// 这张表拥有哪些字段
user : {
type : DataTypes.STRING, //字符串类型
allowNull : false
},
age : {
type : DataTypes.INTEGER, //整数类型
allowNull : false
},
},{
//与模型定义时的名称一致。
// 比如定义了上述定义了user模型,设置了这个字段,创建表的名字也是user。否则就是users。
freezeTableName : true,
//用于记录数据的创建时间和更新时间。
createdAt : false,
updatedAt : false
});
4、创建模型(表)、初始化模型(表)数据
定义好了模型(表),我们就可以进行创建和初始化数据操作。
有些时候,我们希望在创建某些表的时候就初始化一些数据。
新建service/db.js:
// 该文件负责对数据库的数据表进行创建和初始化操作
const sequelize = require("./dbConnect"); // 数据库连接实例
const userModel = require("./model/userModel"); // 用户模型
const initData=async function () {
// 将数据模型和表进行同步
await sequelize.sync({
alter: true,
})
// 同步完成之后,有一些表是需要一些初始化数据
// 查询这张表有没有内容,没有内容才初始化数据
const userCount = await userModel.count();
if (!userCount) {
// 进入此 if,说明该表没有数据,我们进行一个初始化
await userModel.create({
user: "Tom",
age: 18,
})
console.log("初始化用户数据表数据完毕...");
}
console.log("数据库数据已经准备完毕....");
}
initData()
在app.js中引入语句
(对数据库对数据表的创建和初始化数据。)
因为在db.js中,其实已经进行了数据库连接的操作,因此我们只需要引入db.js,其实就是引入数据库连接,引入数据表创建和初始化操作了。
(就不需要再单纯引入数据库连接了!!! 把require("./service/dbConnect")去掉)
// 引入数据库连接、数据表创建和初始化数据。
require("./service/db")
启动服务器,查看结果

在可视化工具中查看是否已经创新了数据表以及初始化数据。


创建和初始化成功!
注意点:
1、通过sequelize定义模型的时候,是会自动帮我们创建id字段。
2、以及通过“模型.create”创建数据的时候,是会自动递增加上id字段。
所以一开始并不需要我们特地去定义和初始化id字段。
三、 实现基本的 CRUD 操作
创建(Create):
使用 Sequelize 创建新记录。
读取(Read):
查询数据库中的记录。
更新(Update):
更新数据库中的记录。
删除(Delete):
删除数据库中的记录。
演示的整体思路:通过创建路由(对应的http方法),使用工具进行测试。
新建routes/user.js

在app.js中引入和使用


1、创建(Create)
1.1、创建单条数据
模型.create(xx)
参数是一个对象,如:
{
"user:"Jack",
"age":17
}
//routes/user.js
var express = require('express');
var router = express.Router();
const { addUserService} = require("../service/userService");
// 创建一条用户数据
router.post("/", async function(req, res, next){
const result=await addUserService(req.body);
console.log("返回的数据>>>",result);
res.send(result);
})
新建service/userService.js:
//引入数据模型(表)
const userModel = require("./model/userModel")
// 添加一条数据到user表
module.exports.addUserService = async function(newUserInfo){
const res = await userModel.create(newUserInfo);
const {dataValues}=res; // 提取有效值
return dataValues
}
启动服务,打开工具进行测试。
(这里我的设置的端口是4600,对应替换成自己设置的端口,可以在bin/www中进行对应更改。)


配合这张图,解释上面代码出现的req.body,一个对象,本次案例表示如下信息:
{
"user:"Jack",
"age":17
}
req.body.user="Jack"
req.body.age=17
“模型.create(xx)”,参数的数据类型是一个对象。
官方文档有相关案例:
点击发送,查看结果:



1.2、批量创建数据
(模型.bulkCreate(xx))
//参数是一个对象数组,[{},{},{}...],如:
[{
"user:"Gory",
"age":16
},
{
"user:"Mary",
"age":15
}]
在routes/user.js添加路由方法
const { addUserService,addMoreUserService} = require("../service/userService");
// 创建多条用户数据
router.post("/more", async function(req, res, next){
const result=await addMoreUserService(req.body.dataList);
res.send(result);
})
在service/userService.js中添加方法
// 批量数据到user表
module.exports.addMoreUserService = async function(newUserInfo){
const res = await userModel.bulkCreate(newUserInfo);
const dataValuesArray = res.map(result => result.dataValues);
console.log("批量添加数据方法返回的结果,有效取值>>>",dataValuesArray);
return dataValuesArray
}
打开测试工具

点击发送,得到如下结果


注意:id为5和6,是因为我先执行了一次发送,然后成功了我就直接在数据库把id为3和4的数据进行手动删除了,接着再执行一次,id就变成5和6了。但实际上你们第一次执行发送的时候,得到的结果是id为3和4。
2、读取(Read)
2.1、查询所有数据
模型.findAll()
在routes/user.js添加路由方法
const { addUserService,addMoreUserService,findUserService,} = require("../service/userService");
// 获取用户数据
router.get("/", async function(req, res, next){
const result=await findUserService();
res.send(result);
})
在service/userService.js中添加方法
// 获取user表的所有数据
module.exports.findUserService = async function(){
const res= await userModel.findAll();
const dataValuesArray = res.map(result => result.dataValues);
console.log("获取所有数据的有效取值>>>",dataValuesArray);
return dataValuesArray;
}
启动服务,打开测试工具


2.2、查询单条数据
通过id(唯一标识)获取指定的数据
模型.findByPk(id)
在routes/user.js添加路由方法
const { addUserService,addMoreUserService,findUserService,findOneUserService} = require("../service/userService");
// 获取单条用户数据
router.get("/:id", async function(req, res, next){
const result=await findOneUserService(req.params.id);
console.log("返回的单条数据>>>",result);
res.send(result);
})
在service/userService.js中添加方法
// 获取其中一个用户数据
module.exports.findOneUserService = async function(id){
const res = await userModel.findByPk(id);
const {dataValues}=res;
return dataValues
}
启动服务,打开测试工具



3、更新(Update)
userModel.update(newInfo,{
where:{ id }
});
//两个参数,第一个是新数据,第二是id。
//通过id(唯一标识)来确定想修改的数据。
在routes/user.js添加路由方法
const { addUserService,addMoreUserService,findUserService,findOneUserService,updateUserService} = require("../service/userService");
// 修改一条用户数据
router.put("/:id", async function(req, res, next){
let id=req.params.id;
let newInfo=req.body;
const result=await updateUserService(id,newInfo);
res.send(result);
})
在service/userService.js中添加方法
// 更新一条用户数据
module.exports.updateUserService = async function(id,newInfo){
return await userModel.update(newInfo,
{
where:{
id
}
}
);
}
启动服务,打开测试工具
假设我们想把id为1的数据项,修改user的值,修改成“Tonny”,age修改成28


点击发送,如果修改成功,则返回1,否则为0
在管理工具中可以看见id为1的user和age的值已经更新成功。

为了明显得知更新结果,这里我们可以对返回的结果作一个简单的判断。
// 更新一条用户数据
module.exports.updateUserService = async function(id,newInfo){
const res= await userModel.update(newInfo,
{
where:{
id
}
}
);
console.log("修改结果>>>>",res,typeof(res),res[0]);
return (res[0]=="1"?"修改成功":"修改失败")
}
我们把age从28改为29




4、删除(Delete)
通过id(唯一标识)进行删除指定数据。
userModel.destroy({
where:{
id
}
});
在routes/user.js添加路由方法
const { addUserService,addMoreUserService,findUserService,findOneUserService,updateUserService,deleteUserService} = require("../service/userService");
// 删除一条用户数据
router.delete("/:id", async function(req, res, next){
const result=await deleteUserService(req.params.id);
res.send(result);
})
在service/userService.js中添加方法
// 删除其中一个用户数据
module.exports.deleteUserService = async function(id){
const res=await userModel.destroy({
where:{
id
}
});
console.log("res>>>>",res,typeof(res),);
return (res==1?"删除成功":"删除失败")
// 若是删除成功则返回1
}
启动服务,打开测试工具
我们演示把id为5的数据删除。



刷新一下数据表,就可以看见id为5的数据项已经被删除。

四、总结
至此,express-generator系列的文章已经更新完毕。
后续我也会不断对文章进行润色,优化、提高文章整体质量。
从2024-12-23发布这个系列的第一阶段的第一篇文章到第二阶段的最后一篇,前后用了一个多月,
挺不容易的,但自己在撰写博客和练习的过程中,也是复习和强化了这方面的知识。
有始有终,这个系列就告一段落了。
欢迎留言评论!
后续我会整理这个系列出现的代码示例,然后总结成完整代码。
如果感兴趣,可以私信、关注我,及时获取最新消息。
1419

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



