Nodejs 第三十八章 MySQL实战案例
Nodejs 第三十八章 MySQL实战案例
- 在前面的演练过了MySQL的诸多常用方法,那在实践中往往都是怎么使用的呢?
- 这一章节,我们就融会前面所学的Node框架express结合MySQL数据库来实现一个案例
- 案例内容是:一个简单的REST API,基本的CRUD(创建、读取、更新、删除)操作的Web服务
- 如果你写过
xxx后台管理系统
,那估计会非常熟悉
初始化项目
安装依赖
第三方库mysql2介绍
mysql2
是Node.js的一个流行库,用于连接和操作MySQL数据库。它是mysql
库的一个改进版本,提供了更快的性能和更多的功能,包括Promise API的支持,可以做到和现代异步编程模式更加兼容。
为什么使用mysql2
- 性能优化:
mysql2
针对查询速度进行了优化,提供了更快的解析和数据包处理能力。 - Promises API:支持Promises,异步操作更加方便,可以使用
async/await
来处理数据库操作,提高代码的可读性和可维护性。 - 完全兼容:
mysql2
设计为与原始mysql
库API兼容,因此在大多数情况下可以直接替换使用,无需改动大量代码。 - 准备语句支持:支持服务器端的准备语句(prepared statements),这可以提高安全性(防止SQL注入攻击)和性能(减少SQL解析时间)。
- 连接池:内置连接池支持,可以有效管理多个数据库连接,提高资源利用率和查询效率
依赖命令集合
- 在我们这个案例中,我们用到新的第三方库的是
mysql2
,和前面章节用过的node框架express
、js-yaml
(第二十八章节邮件服务中有介绍)
//安装第三方库
npm install mysql2 express js-yaml
//对应的声明文件
npm i --save-dev @types/express
npm i --save-dev @types/js-yaml
第三方库 | 作用 |
---|---|
mysql2 | 连接mysql和编写sq语句 |
express | 提供接口 增删改查 |
js-yaml | 编写配置文件 |
创建对应文件夹
index.js
:写主要代码的文件db.config.yaml
:yaml配置文件(配置数据库连接的信息)index.http
:模拟发送客户端请求测试
项目实战
连接数据库
- 那在正式开始编写代码的时候,我们需要先能够连接上数据库。那为什么要先进行这一步,而不是先写代码呢?
- 因为我们此时要编写的接口,乃是对数据库进行的增删改查。换而言之,数据库是我们编写代码所必须的依靠,没有数据库的话,我们的下一步就是空中阁楼,水中映月
- 而连接数据库就要我们mysql2派上用场了
- 我们这里使用的是
ESM导入
,所以需要在package.json文件
中设置"type": "module"
- 下方的代码中就是正常的创建数据库连接的形式
- 我们这里使用的是
import mysql2 from "mysql2"
// 创建与数据库的连接,其中connection是连接的意思
const connection = mysql.createConnection({
host: localhost, //主机
port: 3306,//端口
user: root,//账号
password: 'root',//密码 一定要字符串
database: xiaoyu // 数据库
});
- 但在正常的开发中,我们肯定是不会这样做的。在邮件服务(28章节)的那里,我们已经学到了,像这种敏感的信息,一定是要抽离出去的。不然你开发一不小心把代码发到托管平台,就会连着数据库上传上去,这不把家门口的钥匙交给别人保管嘛?
- 此时就需要我们yaml派上用场了
- 这种配置信息,我们可以用JS文件来存,也可以用JSON存,或者我们用的yaml都是可以的。根据自己的个人喜好来
- 然后在开发中上传代码,就可以通过git的忽略文件配置限制yaml配置文件的上传
#db.config.yaml配置文件
db:
host: localhost #主机
port: 3306 #端口
user: root #账号
password: "root" #密码 一定要字符串
database: xiaoyu # 库
-
此时,我们
index.js
这里编写的代码就可以简化了- 我们直接读取到的yaml信息是文件本身的信息形式,而这其实是不好获取其中的某一点的
- 所以我们需要借用
js-yaml
这个第三方库,来将其转化为对象,此时获取对应的值才方便
import mysql2 from "mysql2"
import jsYaml from "js-yaml"
import fs from "fs"
//读取配置信息
const yaml = fs.readFileSync("./db.config.yaml", "utf8")
const config = jsYaml.load(yaml)
// 创建与数据库的连接
const connection = mysql2.createConnection({
...config.db
});
- 我们这里采用异步进行会更好一点,返回
Promise
的异步函数。而且mysql2是支持异步的写法,但我们导入的mysql2就需要发生一下改变- await在这里,必须要我们连接上数据库了才能进行下一步。这也是思想的体现,因为后面的功能都是要基于已经连接上数据库才能实现,所以我们才这样做
import mysql2 from "mysql2/promise"
// 创建与数据库的连接
const connection =await mysql2.createConnection({
...config.db
});
增删改查
- 创建
数据库连接
后,我们就使用express框架来启动项目,来进入我们对数据库的操作
import mysql2 from "mysql2/promise"
import jsYaml from "js-yaml"
import express from "express"
import fs from "fs"
const app = express()
const yaml = fs.readFileSync("./db.config.yaml", "utf8")
const config = jsYaml.load(yaml)
console.log(config);
// 创建与数据库的连接
const connection =await mysql2.createConnection({
...config.db
});
const port = 3000
app.listen(port, () => {
console.log("端口开启成功");
})
查询接口
-
想要测试是否正常连接数据库了,就让我们查询一下是否可以获取到数据库中的内容吧!
- 由于查询到的内容返回的形式是一个二维数组,且我们只需要第一项内容(数据),所以只解构出前面一个
//直接拿到的二维数组 [[数据],[表结构]] 形式 [ [ { id: 1, name: '迷你余', email: 'mini@gmail.com' }, { id: 2, name: '小余', email: 'small@gmail.com' }, { id: 3, name: '中余', email: 'medium@gmail.com' }, { id: 4, name: '大余', email: 'large@gmail.com' }, { id: 5, name: '超大余', email: 'xlarge@gmail.com' } ], [ `id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(255) NOT NULL, `email` VARCHAR(255) ] ]
// 查询接口
app.get("/api/search", async (req, res) => {
const [data] = await connection.query("SELECT * FROM `users`")
res.send(data)
})
- 目前我们实现的是查询所有的数据,但如果有写过后台管理系统的同学,应该就会知道,我们一般是不会请求所有的数据的,因为一次性请求过多的数据,是属于没有必要的事情(页面一次性能展示的数据有限)
- 通常我们就会进行分页展示,比如我们一次请求多少行数据
- 或者针对性的查询单个内容数据
- 而根据用户返回的需求要查询多少条数据,查询哪条具体的数据
- 通常情况下,这种查询不涉及隐私的,可以继续使用get请求,然后请求携带参数直接拼接在URL地址后面就好了
- 而我们接口
如何接收客户端传来的具体参数内容
,在express的讲解中也有讲到,通过:xxx
动态参数就行
// 查询单个内容接口
app.get("/api/search/:id", async (req, res) => {
const [data] = await connection.query("SELECT * FROM `users` WHERE `id` = ?", [req.params.id])
res.send(data)
})
- 大家可以看到,我们这里的SQL语句,是采用占位符来进行传递动态参数的
# 占位符形式
"SELECT * FROM `users` WHERE `id` = ?", [req.params.id]
- 但传递的方式除了这种之外,在前端还可以通过模板字符串来进行,至于通过哪种方式,则也是取决于个人的爱好。
- 通过占位符的形式可以最大程度保持SQL语句的完整连贯性,会更整齐
- 而通过模板字符串的形式,则可以更清晰的看到我们参数位于SQL语句中的哪里
//模板字符串形式
`SELECT * FROM users WHERE id = '${req.params.id}'`
新增接口
- 对于新增内容来说,我们这个案例是对用户表的增删改查,而用户信息是明显的敏感信息,是具备隐私性的。
- 所以我们不能够在通过GET来发起请求,该用POST了
POST请求
通常都是接收一个JSON数据
,而在express
中想要接收JSON数据
的话。是需要使用中间件来加持的,不然无法识别(前面章节讲过)
- 根据我们上一章节所创建的用户数据表来说,我们需要
name
、email
这两个参数,而id
是属于自增内容- 同时当成功接收到内容后,返回给用户响应成功的信息
const app = express()
app.use(express.json())
//新增接口
app.post('/api/create', async (req, res) => {
const { name, email } = req.body
await connection.query("insert into `users`(name,email) values(?,?)", [name, email])
res.send({ ok: 1 })
})
- 接着我们需要编写一下对应的HTTP请求接口
- 需要注意的是,
Content-Type
这行设置与第一行POST请求回车后不能够像与JSON数据有间隔,不然会断掉 - 发送的json请求数据将无法传达
- 需要注意的是,
POST http://localhost:3000/api/create HTTP/1.1
Content-Type: application/json
{
"name":"小余2002",
"email":"1045098807@qq.com"
}
- 成功发送请求,也返回了成功的响应,让我们用刚才的查询接口看下内容是否真的添加了进去
- 通过查询接口的结果,我们能看到新增效果是理想的
编辑接口
//编辑接口
app.post('/api/update',async (req,res)=>{
const {name,email,id} = req.body
await connection.query("update users set name = ?,email = ? where id = ?",[name,email,id])
res.send({ok:1})
})
#编辑接口(更新数据)的测试代码
POST http://localhost:3000/api/update HTTP/1.1
Content-Type: application/json
{
"name":"XiaoYu2002",
"email":"xiaoyu20020805@gmail.com",
"id":6
}
- 修改成功,让我们继续看下查询结果是否发生改变
- 通过针对查询我们修改的id,可以看到名称已经发生了改变
删除接口
//删除接口
app.post('/api/delete',async (req,res)=>{
await connection.query(`delete from users where id = ?`,[req.body.id])
res.send({ok:1})
})
#删除
POST http://localhost:3000/api/delete HTTP/1.1
Content-Type: application/json
{
"id":6
}
- 此时数据可就查不到咯
完整接口代码(增删改查)
import mysql2 from "mysql2/promise"
import jsYaml from "js-yaml"
import express from "express"
import fs from "fs"
const app = express()
app.use(express.json())
const yaml = fs.readFileSync("./db.config.yaml", "utf8")
const config = jsYaml.load(yaml)
// 创建与数据库的连接
const connection = await mysql2.createConnection({
...config.db
});
// 查询全部内容接口
app.get("/api/search", async (req, res) => {
const [data] = await connection.query("SELECT * FROM `users`")
res.send(data)
})
// 查询单个具体内容接口
app.get("/api/search/:id", async (req, res) => {
const [data] = await connection.query("SELECT * FROM `users` WHERE `id` = ?", [req.params.id])
res.send(data)
})
//新增接口
app.post('/api/create', async (req, res) => {
const { name, email } = req.body
await connection.query("insert into `users`(name,email) values(?,?)", [name, email])
res.send({ ok: 1 })
})
//编辑接口
app.post('/api/update',async (req,res)=>{
const {name,email,id} = req.body
await connection.query("update users set name = ?,email = ? where id = ?",[name,email,id])
res.send({ok:1})
})
//删除接口
app.post('/api/delete',async (req,res)=>{
await connection.query(`delete from users where id = ?`,[req.body.id])
res.send({ok:1})
})
const port = 3000
app.listen(port, () => {
console.log("成功开启端口:", port);
})
总结
- 通过以上的代码,我们完成了MySQL、express的案例闭环,将前面所学的知识和思想运用了起来,实现了日常开发中最离不开的功能点的雏形
- 前面所浇的水,在此时也是长出了对应的果实,恭喜你在此刻成功入门Node了
转载自:https://juejin.cn/post/7368320489890414628