文章目录

  • 参考
  • 描述
  • mysql 模块
  • 连接数据库
    • 检测
  • 基本操作
    • 查询
      • 数据与代码分离原则
      • 占位符
    • 插入
      • 另一种姿态
    • 修改
      • 另一种姿态
    • 删除
      • 标记删除

参考

项目 描述
哔哩哔哩 黑马程序员
搜索引擎 Bing

描述

项目 描述
NodeJS v18.13.0
nodemon 2.0.20
MySQL 5.7.40
mysql 2.18.1

mysql 模块

npm(NodeJS Package Manager) 包管理器提供了第三方模块 mysql,该模块可用于实现 NodeJS 与 MySQL 数据库的连接。

在终端中使用如下命令开始对第三方模块 mysql 的安装:

npm install mysql

在安装该模块后,你可以在 NodeJS 中使用如下代码将该模块进行导入:

const mysql = require('mysql');

连接数据库

提醒:

在实践本示例中的代码时请确保你已经安装了 MySQL 并已经开启了 mysql 服务。

我们可以使用 mysql.createPool() 函数来创建一个与 MySQL 的连接,你需要向该函数传递一个对象,该对象描述了 MySQL 数据库管理系统的相关信息。

const mysql = require('mysql');// 建立 NodeJS 与 MySQL 的连接
const db = mysql.createPool({// MySQL 所在的计算机的 IP 地址host: '127.0.0.1',// 用户名称user: 'root',// 登录密码password: '123456', // 需要使用的数据库database: 'db_test',// MySQL 监听的端口号port: 3360
})

注:

  1. 提交给 mysql.createPool() 函数的对象中的 password 属性不能是数值类型。如果将属性 password 的值 ‘123456’ 中的单引号去掉,那么在正式连接数据库时(此时只是提供连接需要使用到的信息,并没有开始连接)终端将抛出如下错误信息:

TypeError [ERR_INVALID_ARG_TYPE]: The first argument must be of type string or an instance of Buffer, ArrayBuffer, or Array or an Array-like Object. Received type number (123456)

  1. 如果你需要连接的 MySQL 的位于当前计算机中,则你可以省略 host 属性;如果 MySQL 监听的端口为默认端口 3306 时,你可以将 port 属性省略。

检测

你可以在原代码的基础上添加如下代码来检测 NodeJS 与 MySQL 的连接是否成功。

// 对数据库进行查询操作
db.query('select 999', (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message); }else{console.log('{ Win }');}
})

执行该程序,如果终端输出 { Win } ,则表明数据库已经成功连接;如果终端中输出 { Lose },请检查连接 MySQL 所需要用到的相关信息是否正确。

注:

在 NodeJS 对数据库进行查询等操作时 NodeJS 将正式向 MySQL 发起连接,所以通过此法可以检查数据库是否可以正常连接。

基本操作

查询

db.query()

使用 db.query() 函数可以对数据库进行查询操作,该函数可以接收两个参数,第一个参数是对数据库进行查询操作时所需要使用的 SQL 查询语句,第二个参数则是查询操作完成后需要执行的回调函数。

你可以向回调函数提交两个参数,其中第一个参数用以接收查询操作过程中可能产生的错误对象,第二个参数用以接收查询成功后数据库返回的查询结果。

举个栗子:

先瞅瞅我的 users 表中有些什么东西:

我们可以通过 NodeJS 查询该表中 id1 的数据:

const mysql = require('mysql');// 建立 NodeJS 与 MySQL 的连接
const db = mysql.createPool({// MySQL 所在的计算机的 IP 地址host: '127.0.0.1',// 用户名称user: 'root',// 登录密码password: '123456', // 需要使用的数据库database: 'db_test',// MySQL 监听的端口号port: 3360
})// 对数据库进行查询操作
db.query('select * from users where id = 1', (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else{console.log(result[0]);}
})

执行结果:

在执行上述示例中的代码后,终端将输出如下内容:

[ RowDataPacket { id: 1, username: ‘RedHeart’, password: ‘TwoMoons’ } ]

注:

  1. 在使用 mysql 模块的 db.query() 函数数据库中的内容进行查询时将得到一个包含一个或多个对象的数组。
  2. 在上述示例中,我们在查询过程中使用了 console.log(err.message); 来打印错误信息,这有助于我们在发现错误时能够快速的解决错误。
数据与代码分离原则

在编写后端代码时,一定要注意数据与代码分离的原则。

注入攻击是 Web 安全领域中一种最为常见的攻击方式。
注入攻击的本质,是把用户输入的数据当作代码执行。这里有两个关键条件,第一个是用户能够控制输入;第二个是原本程序要执行的代码,拼接了用户的输入。


上述内容引用自吴瀚清的 《白帽子讲Web安全》

当你需要用到用户提供的数据时,一定要小心,恶意的用户会构造特定的数据对你的应用进行攻击。

占位符

为了遵循数据与代码分离的原则,避免网页被 SQL 注入 攻击,mysql 模块为我们提供了占位符这一特性。

mysql 模块中,你可以使用 ? 来代替某个数据。在使用占位符代替数据后,请不要忘记向 mysql 模块提供需要被替代的数据。
向 mysql 模块提供被代替的数据的方式依照需要被替代的数据而定,具体如下:

  1. 当被替代的数据有多个时,你可以通过向 db.query() 函数提供三个实参(其中两个实参我们前面已经见过),第二个实参需要为一个数组,数组中的内容与 SQL 语句中的占位符按从左到右的顺序一一对应。例如:
db.query('select * from users where id = ? and username = ?', [1, 'RedHeart'], (err, result) => {})
  1. 当被替代的数据仅有一个时,你可以通过你可以通过向 db.query() 函数提供三个实参(其中两个实参我们前面已经见过),第二个实参可以为一个仅包含一个元素的数组也可以为被替代的数据。例如:
db.query('select * from users where id = ?', 1, (err, result) => {})

或:

db.query('select * from users where id = ?', [1], (err, result) => {})

注:

并不是 SQL 语句中的所有内容都可以被替换,例如:

db.query('select * from users where ? = 1', 'id', (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else{console.log(result);}
})

终端中的输出将为(一个空数组):

[]

在使用占位符时,仅 SQL 语句中的数据部分可以被替换

插入

const mysql = require('mysql');// 建立 NodeJS 与 MySQL 的连接
const db = mysql.createPool({// MySQL 所在的计算机的 IP 地址host: '127.0.0.1',// 用户名称user: 'root',// 登录密码password: '123456', // 需要使用的数据库database: 'db_test',// MySQL 监听的端口号port: 3360
})// 定义需要插入表中的数据
data = {id: 2, username: 'YJH', password: 'RedHeart'}// 尝试将数据插入表中
db.query('insert into users values(?, ?, ?)', [data.id, data.username, data.password], (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else{console.log(result);}
})

执行结果:

在执行上述代码后,终端将输出如下内容:

OkPacket {fieldCount: 0,affectedRows: 1,insertId: 2,serverStatus: 2,warningCount: 0,message: '',protocol41: true,changedRows: 0
}

注:

在执行插入操作后,mysql 模块将返回一个对象。我们可以通过这个对象中的 affectedRows 来判断插入操作是否成功。affectedRows 表示该操作所影响的行数。

所以我们可以都上述代码做一些适当的修改:

db.query('insert into users values(?, ?, ?)', [data.id, data.username, data.password], (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else if(result.affectedRows === 1){console.log('{ Win }');}
})
另一种姿态

你可以通过向提交给 db.query() 函数的 SQL 查询语句中添加关键字 set (不区分大小写)及占位符 ? 来简化语句。

const mysql = require('mysql');// 建立 NodeJS 与 MySQL 的连接
const db = mysql.createPool({// MySQL 所在的计算机的 IP 地址host: '127.0.0.1',// 用户名称user: 'root',// 登录密码password: '123456', // 需要使用的数据库database: 'db_test',// MySQL 监听的端口号port: 3360
})data = {id: 3, username: 'CYH', password: 'RedHeart'}db.query('insert into users sEt ?', data, (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else if(result.affectedRows === 1){console.log('{ Win }');}
})

执行结果:

在执行上述代码后,终端将输出如下内容:

{ Win }

注:

使用上述方式对数据库进行操作需要注意一点,即提交给 db.query() 函数的第二个参数需要为一个对象且该对象中的属性的个数与表中字段的个数一样且属性名与表中的字段名一一对应。

错误示范:

db.query('insert into users sEt ?', [4, 'XJL', 'RedHeart'], (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else if(result.affectedRows === 1){console.log('{ Win }');}
})

上述示例中,我们传递的并不是一个对象而是一个数组。数组中的元素的个数虽能够与字段一一对应,但由于不是对象,mysql 模块将抛出错误。执行该示例代码,你将得到如下内容:

{ Lose }
ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘4’ at line 1

修改

const mysql = require('mysql');// 建立 NodeJS 与 MySQL 的连接
const db = mysql.createPool({// MySQL 所在的计算机的 IP 地址host: '127.0.0.1',// 用户名称user: 'root',// 登录密码password: '123456', // 需要使用的数据库database: 'db_test',// MySQL 监听的端口号port: 3360
})db.query('update users set password = ? where id = ?', ['Other', 3], (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else if(result.affectedRows === 1){console.log('{ Win }');console.log(result)}
})

执行结果:

{ Win }
OkPacket {fieldCount: 0,affectedRows: 1,insertId: 0,serverStatus: 2,warningCount: 0,message: '(Rows matched: 1  Changed: 1  Warnings: 0',protocol41: true,changedRows: 1
}

可以看到,使用 mysql 模块对数据库进行修改操作,返回的结果仍是一个对象,我们依旧可以通过 affectedRows 来判断修改操作是否成功。

另一种姿态

与插入一样,我们可以使用 set 关键字来简化语句,但同样的,我们需要向 db.query() 函数传递一个对象作为第二个实参,且该对象中的属性需要为被修改的字段,而属性值则需要为字段修改后的结果值。

const mysql = require('mysql');// 建立 NodeJS 与 MySQL 的连接
const db = mysql.createPool({// MySQL 所在的计算机的 IP 地址host: '127.0.0.1',// 用户名称user: 'root',// 登录密码password: '123456', // 需要使用的数据库database: 'db_test',// MySQL 监听的端口号port: 3360
})data = {password: 'Other'}db.query('update users set ? where id = ?', [data, 3], (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else if(result.affectedRows === 1){console.log('{ Win }');console.log(result)}
})

执行结果:

{ Win }
OkPacket {fieldCount: 0,affectedRows: 1,insertId: 0,serverStatus: 2,warningCount: 0,message: '(Rows matched: 1  Changed: 1  Warnings: 0',protocol41: true,changedRows: 1
}

注:

在这里我们向 db.query() 的第二个参数传递了一个数组,这似乎违背了我们前面的推断,使用这种方式对表进行插入或是修改操作时,第二个参数也可以是一个数组。但这个数组中的元素需要有一个元素为对象,且这个对象在数组中的排位与 set 关键字右边第一个占位符在该语句中所有占位符的排位相对应。

删除

const mysql = require('mysql');// 建立 NodeJS 与 MySQL 的连接
const db = mysql.createPool({// MySQL 所在的计算机的 IP 地址host: '127.0.0.1',// 用户名称user: 'root',// 登录密码password: '123456', // 需要使用的数据库database: 'db_test',// MySQL 监听的端口号port: 3360
})db.query('delete from users where id = ?', 3, (err, result) => {if(err){console.log('{ Lose }');// 打印在查询过程中遇到的错误的信息console.log(err.message);}else if(result.affectedRows === 1){console.log('{ Win }');console.log(result)}
})

执行结果:

{ Win }
OkPacket {fieldCount: 0,affectedRows: 1,insertId: 0,serverStatus: 2,warningCount: 0,message: '',protocol41: true,changedRows: 0
}
标记删除

使用 DELETE 语句,会把真正的把数据从表中删除掉。为了保险起见,推荐使用标记删除的形式,来模拟删除的动作。所谓的标记删除,就是在表中设置类似于 status 这样的状态字段,来标记当前这条数据是否被删除。
当用户执行了删除的动作时,我们并没有执行 DELETE 语句把数据删除掉,而是执行了 UPDATE 语句,将这条数据对应的 status 字段标记为删除即可

NodeJS 与第三方模块 mysql(基本操作)相关推荐

  1. Nodejs 中的包、npm 、第三方模块、 package.json 以及 cnpm

    一.包与 NPM 包Nodejs 中除了它自己提供的核心模块外,我们可以自定义模块,也可以使用第三方的 模块.Nodejs 中第三方模块由包组成,可以通过包来对一组具有相互依赖关系的模块进行 统一管理 ...

  2. Nodejs 包与 NPM 第三方模块安装和 package.json 以及 CNPM

    包与 NPM Nodejs 中除了它自己提供的核心模块外,我们可以自定义模块,也可以使用 第三方的模块.Nodejs 中第三方模块由包组成,可以通过包来对一组具有相互依 赖关系的模块进行统一管理. 完 ...

  3. mysql 安装dso命令_使用tengine DSO 来动态编译安装第三方模块(Lua

    在使用nginx时,需要增加或者改动一个模块,都需要重新编译nginx文件.最近使用了tengine,它提供的DSO工具来动态加载模块.本例测试需要动态增加lua-nginx模块,记录一下安装过程. ...

  4. 5.Nodejs中的包、npm、第三方模块、package.json以及cnpm

    1.包 Nodejs中除了它自己提供的核心模块(内置模块)外,我们可以自定义模块 ,也可以使用第三方模块.Nodejs中的第三方模块由包组成,它可以通过包来对一组具有相互依赖关系的模块进行统一管理. ...

  5. 第四模块MySQL数据库

    第四模块MySQL数据库 从今天开始,我们将进入系列课程的 第四模块 的学习,这个模块就是给大家讲解MySQL数据库. 以前,在开发程序时,我们会把很多的数据和信息存储到某个文件夹中的文件中,例如:u ...

  6. nodejs linux模块全局,nodejs笔记一--模块,全局process对象;

    一.os模块可提供操作系统的一些基本信息,它的一些常用方法如下: var os = require("os"); var result = os.platform(); //查看操 ...

  7. HTTP和第三方模块

    私人博客 许小墨のBlog -- 菜鸡博客直通车 系列文章完整版,配图更多,CSDN博文图片需要手动上传,因此文章配图较少,看不懂的可以去菜鸡博客参考一下配图! 系列文章目录 前端系列文章--传送门 ...

  8. 31、如何安装第三方模块?以及用过哪些第三方模块?

    在Python中,安装第三方模块,是通过setuptools这个工具完成的.Python有两个封装了setuptools的包管理工具:easy_install和pip.目前官方推荐使用pip 如果你正 ...

  9. python安装第三方库-安装第三方模块

    在Python中,安装第三方模块,是通过setuptools这个工具完成的.Python有两个封装了setuptools的包管理工具:easy_install和pip.目前官方推荐使用pip. 如果你 ...

最新文章

  1. vue refs v-for 使用注意
  2. 解析几何:第三章 平面上的直线
  3. PMCAFF网站和App改版啦!
  4. linux内核启动过程5:启动用户空间
  5. @vail 判断某字段在范围内_怎么判断一台二次元影像测量仪的可靠性?
  6. HTTP与Tcp协议下双工通信的差异
  7. 断代、新生、创未来-Zoomla!逐浪CMS2 x3.9.6全面发布...
  8. MySQL:Specified key was too long; max key length is 1000 bytes
  9. 【御数·原创】数据治理的坑你遇到过几个?
  10. 【Oracle】SQL查询 基本查询语句
  11. 用计算机怎么计算税率,一般纳税人税率计算器,一般纳税人税率如何计算?
  12. 短时傅里叶变换STFT(非使用fft函数)
  13. 房屋租赁合同电子版最新版(word版本适合个人租房用)
  14. 2008秋季-计算机软件基础- vc6 wintc 编译器
  15. 开机动画desc.txt描述文件的分析
  16. SVG 绘制可交互的中国地图
  17. IJCAI‘22 推荐系统论文梳理
  18. 关于电脑网速网占用问题(svchost.exe)(¥72)
  19. P3 元宝第三天的笔记
  20. 注册码方式注册多可系统

热门文章

  1. 安卓案例:学生信息管理
  2. 脑控电脑正在成为现实,但重大障碍仍然存在
  3. Altium Designer格式文件变更为Cadence文件心路历程
  4. android 收藏歌曲功能,基于android的网络音乐播放器-回调实现音乐播放及音乐收藏的实现(三)...
  5. 霍夫变换——HoughLines、HoughLinesP和HoughCircles
  6. B端产品经理与C端产品经理
  7. guestbook.php,guestbook.php
  8. 使用阿里云的OSS图片上传,这里是用的上传网络流
  9. 2021-11-02 PAT厘米换算英尺英寸
  10. ]C++精华基础贴[水木清华]