【express-generator】09-第二阶段完结-express+mysql实现CRUD操作

前言

关于第二阶段的内容, 前面我们介绍了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的安装和使用。

【express-generator】01-安装和基本使用

//本篇演示案例的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)”,参数的数据类型是一个对象。

官方文档有相关案例:

模型查询(基础) | Sequelize中文文档 | Sequelize中文网

 点击发送,查看结果:

 

 

 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发布这个系列的第一阶段的第一篇文章到第二阶段的最后一篇,前后用了一个多月,

挺不容易的,但自己在撰写博客和练习的过程中,也是复习和强化了这方面的知识。

有始有终,这个系列就告一段落了。


欢迎留言评论!

后续我会整理这个系列出现的代码示例,然后总结成完整代码。

如果感兴趣,可以私信、关注我,及时获取最新消息。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十八朵郁金香

感恩前行路上有你相伴

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值