重学Node.js及其框架(Express, Koa, egg.js) 之 MySQL及Nodejs中使用MySQL(下)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 重学Node.js及其框架(Express, Koa, egg.js) 之 MySQL及Nodejs中使用MySQL

多张表


如果我们想要两张表存在联系。我们就需要在一张表中给联系字段设置外键。


现在假设我们有一张products和一张brand表。将两张表联系起来,我们可以将products中的brand_id关联到brand中的id。


ALTER TABLE `products` ADD FOREIGN KEY (brand_id) REFERENCES brand(id);


我们如何让两个表有关的字段做到联动呢?


当我们更新或者删除外键时,可以设置几个值:


  • RESTRICT(默认属性):当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话会报错的,不允许更新或删除;


网络异常,图片无法展示
|


  • NO ACTION:和RESTRICT是一致的,是在SQL标准中定义的;


  • CASCADE:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话:


  • 更新:那么会更新对应的记录;


  • 删除:那么关联的记录会被一起删除掉;


网络异常,图片无法展示
|


网络异常,图片无法展示
|


  • SET NULL:当更新或删除某个记录时,会检查该记录是否有关联的外键记录,有的话,将对应的值设置为NULL;


网络异常,图片无法展示
|


注 意:当我们使用外键,并且将类型设置为cascade时,我们删除外表数据,那么将会将内表对应数据也删除。但是删除内表数据,将不会影响外表。


尽量不要使用cascade类型,但是对于一些特殊操作,使用cascade类型很方便。 假如我们删除评论数据,想要恢复的数据也删除,就可以设置cascade类型了。方便操作。

如何通过代码修改外键类型呢?


-- 查看表结构,找到外键名称
    SHOW CREATE TABLE `表名`;
    -- 删除之前的外键,根据外键名称
    ALTER TABLE `表名` DROP FOREIGN KEY 外键名称;
    -- 添加新的外键
    ALTER TABLE `表名` ADD FOREIGN KEY (引用的外键字段)
    REFERENCES 外键表(外键字段)
    ON UPDATE 更新时的外键类型 ON DELETE 删除时的外键类型;
    -- 查看表结构,找到外键名称
    SHOW CREATE TABLE `products`;
    -- 删除之前的外键
    ALTER TABLE `products` DROP FOREIGN KEY products_ibfk_1;
    -- 添加新的外键
    ALTER TABLE `products` ADD FOREIGN KEY (brand_id)
    REFERENCES brand(id)
    ON UPDATE CASCADE ON DELETE CASCADE;


多表之间的连接查询


如果我们希望查询到产品的同时,显示对应的品牌相关的信息,因为数据是存放在两张表中,所以这个时候就需要进行多表查询。


我们可以使用 SQL JOIN 操作: 左连接 右连接 内连接 全连接


网络异常,图片无法展示
|


以下查询的sql语句案例。我们假设有products(id, brand, title, price, score, voteCnt, url, pid, brand_id(外键字段))brand(id(外键引用字段), name, website, phoneRank)两个表


左连接如果我们希望获取到的是左边所有的数据(以左表为主):


网络异常,图片无法展示
|


这个时候就表示无论左边的表是否有对应的brand_id的值对应右边表的id,左边的数据都会被查询出来,这个也是开发中使用最多的情况,它的完整写法是LEFT [OUTER] JOIN,但是OUTER可以省略的;


SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id;
    SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id= `brand`.id
    WHERE brand.id IS NULL;


右连接如果我们希望获取到的是右边所有的数据(以由表为主):


网络异常,图片无法展示
|


这个时候就表示无论左边的表中的brand_id是否有和右边表中的id对应,右边的数据都会被查询出来,右连接在开发中没有左连接常用,它的完整写法是RIGHT [OUTER] JOIN,但是OUTER可以省略的。


SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id;
    SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id= `brand`.id
    WHERE products.id IS NULL;


内连接事实上内连接是表示左边的表和右边的表都有对应的数据关联:


网络异常,图片无法展示
|


内连接在开发中偶尔也会常见使用,看自己的场景。内连接有其他的写法:CROSS JOIN, INNER JOIN, JOIN都可以。


SELECT * FROM `products` INNER JOIN `brand` ON `products`.brand_id = `brand`.id;


我们会发现它和之前的下面写法是一样的效果:


SELECT * FROM `products`, `brand` WHERE `products`.brand_id = `brand`.id;


但是他们代表的含义并不相同:


  • 内连接,代表的是在两张表连接时就会约束数据之间的关系,来决定之后查询的结果。


  • where条件,代表的是先计算出笛卡尔乘积,在笛卡尔乘积的数据基础之上进行where条件的筛选。全连接SQL规范中全连接是使用FULL JOIN,但是MySQL中并没有对它的支持,我们需要使用 UNION 来实现:


网络异常,图片无法展示
|


(SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id)
UNION
(SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id);
(SELECT * FROM `products` LEFT JOIN `brand` ON `products`.brand_id = `brand`.id 
WHERE `brand`.id IS NULL)
UNION
(SELECT * FROM `products` RIGHT JOIN `brand` ON `products`.brand_id = `brand`.id 
WHERE `products`.id IS NULL);


如何将我们查询到多表字段的数据转化成对象或者数组呢?


我们需要用到JSON_OBJECT(key, value, [...])JSON_ARRAY()方法来将一个表中的字段转化成一个对象或者一个数组。但是如果想把转为的多个对象再放在数组中,我们就需要用到JSON_ARRAYAGG()方法。一对多


SELECT products.id as id, 
    products.title as title, 
    products.price as price, 
    products.score as score,
    JSON_OBJECT(
        'id', brand.id, 
        'name', brand.name, 
        'rank', brand.phoneRank, 
        'website', brand.website
    ) as brand
    FROM products LEFT JOIN brand ON products.brand_id = brand.id;


网络异常,图片无法展示
|


多对多


SELECT stu.id, stu.name, stu.age,
    JSON_ARRAYAGG(JSON_OBJECT('id', cs.id, 'name', cs.name)) as courses
    FROM students stu
    LEFT JOIN students_select_courses ssc ON stu.id = ssc.student_id
    LEFT JOIN courses cs ON ssc.course_id= cs.id
    GROUP BY stu.id;


网络异常,图片无法展示
|


从上面的查询可以看出,我们如果想要合并通记录的数据,可以使用分组。而且分组

后,如果字段是唯一的,那么多可以获取,而不只是只能获取分组字段。


多对多关系查询


如果我们想把两个表建立联系,我们就需要建立一个中间表。这个关系表来记录两张表中的数据关系。然后就是通过多表连接查询语法,来进行查询了。


以下查询的sql语句案例。我们假设有students(id(外键), name, age), courses(id(外键), name, price), 关系表students_select_cources(id, student_id(引用外键字段), course_id(引用外键字段))三个表。 这个关系表用来记录学生id和课程id的对应关系,来确定学生的选课情况。


查询多条数据


# 查询所有的学生选择的所有课程
    SELECT
    stu.id studentId, stu.name studentName, cs.id
    courseId, cs.name
    courseName, cs.price
    coursePrice
    FROM `students` stu
    JOIN `students_select_courses` ssc
    ON stu.id = ssc.student_id
    JOIN `courses` cs
    ON ssc.course_id = cs.id;
    # 查询所有的学生选课情况
    SELECT
    stu.id studentId, stu.name studentName, cs.id
    courseId, cs.name
    courseName, cs.price
    coursePrice
    FROM `students` stu
    LEFT JOIN `students_select_courses` ssc
    ON stu.id = ssc.student_id
    LEFT JOIN `courses` cs
    ON ssc.course_id = cs.id;


查询单挑数据


# why同学选择了哪些课程
    SELECT
    stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price
    coursePrice
    FROM `students` stu
    JOIN `students_select_courses` ssc
    ON stu.id = ssc.student_id
    JOIN `courses` cs
    ON ssc.course_id = cs.id
    WHERE stu.id = 1;
    # lily同学选择了哪些课程(注意,这里必须用左连接,事实上上面也应该使用的是左连接)
    SELECT
    stu.id studentId, stu.name studentName, cs.id courseId, cs.name courseName, cs.price
    coursePrice
    FROM `students` stu
    LEFT JOIN `students_select_courses` ssc
    ON stu.id = ssc.student_id
    LEFT JOIN `courses` cs
    ON ssc.course_id = cs.id
    WHERE stu.id = 5;


Nodejs中使用MySQL


如何可以在Node的代码中执行SQL语句来,这里我们可以借助于两个库:


  • mysql:最早的Node连接MySQL的数据库驱动。


  • mysql2:在mysql的基础之上,进行了很多的优化、改进。 目前相对来说,我更偏向于使用mysql2,mysql2兼容mysql的API,并且提供了一些附加功能更快/更好的性能。


  • Prepared Statement(预编译语句):


  • 提高性能:将创建的语句模块发送给MySQL,然后MySQL编译(解析、优化、转换)语句模块,并且存储它但是不执行,之后我们在真正执行时会给?提供实际的参数才会执行;就算多次执行,也只会编译一次,所以性能是更高的;


  • 防止SQL注入:之后传入的值不会像模块引擎那样就编译,那么一些SQL注入的内容不会被执行;or 1 = 1不会被执行;


  • 支持Promise,所以我们可以使用async和await语法。


基本使用


通过调用createConnection()并传入对应数据库连接信息,它将返回一个连接对象。然后通过query执行sql语句。


const mysql = require('mysql2');
    // 1.创建数据库连接
    const connection = mysql.createConnection({
      host: 'localhost',
      port: 3306,
      database: '数据库名',
      user: 'root',
      password: '数据库密码'
    });
    // 2.执行SQL语句
    const statement = `
      SELECT * FROM products WHERE price > 6000;
    `
    connection.query(statement, (err, results, fields) => {
      console.log(results);
    });


通过预处理语句使用


通过?来占位。然后通过execute传入占位的参数,并执行sql语句。


强调:如果再次执行该语句,它将会从LRU(Least Recently Used) Cache中获取获取,省略了编译statement的时间来提高性能。


const mysql = require('mysql2');
    // 1.创建数据库连接
        const connection = mysql.createConnection({
          host: 'localhost',
          port: 3306,
          database: '数据库名',
          user: 'root',
          password: '数据库密码'
        });
    // 2.执行SQL语句
    const statement = `
      SELECT * FROM products WHERE price > ? AND score > ?;
    `
    // 参数:sql语句, 传入的参数[], 执行的回调函数
    connection.execute(statement, [6000, 7], (err, results) => {
      console.log(results);
    });


连接池的使用


前面我们是创建了一个连接(connection),但是如果我们有多个请求的话,该连接很有可能正在被占用,那么我们是否需要每次一个请求都去创建一个新的连接呢?


事实上,mysql2给我们提供了连接池(connection pools);


连接池可以在需要的时候自动创建连接,并且创建的连接不会被销毁,会放到连接池中,后续可以继续使用; 我们可以在创建连接池的时候设置LIMIT,也就是最大创建个数;


const mysql = require('mysql2');
    // 1.创建连接池
    const connections = mysql.createPool({
      host: 'localhost',
      port: 3306,
      database: '数据库名',
      user: 'root',
      password: '数据库密码'
      // 最大连接数
      connectionLimit: 10
    });
    // 2.使用连接池
    const statement = `
      SELECT * FROM products WHERE price > ? AND score > ?;
    `
    connections.execute(statement, [6000, 7], (err, results) => {
      console.log(results);
    });


promise的使用方式


就是连接对象调用promise()方法。


const mysql = require('mysql2');
    // 1.创建连接池
    const connections = mysql.createPool({
      host: 'localhost',
      port: 3306,
      database: '数据库名',
      user: 'root',
      password: '数据库密码'
      // 最大连接数
      connectionLimit: 10
    });
    // 2.使用连接池
    const statement = `
      SELECT * FROM products WHERE price > ? AND score > ?;
    `
    connections.promise().execute(statement, [6000, 7]).then(([results]) => {
      console.log(results);
    }).catch(err => {
      console.log(err);
    });


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
9天前
|
Web App开发 JavaScript 前端开发
构建高效Web应用:Node.js与Express框架的深度整合
【9月更文挑战第28天】在现代Web开发领域,Node.js和Express框架的结合已成为打造高性能、易扩展应用的黄金组合。本文将深入探讨如何利用这一技术栈优化Web应用架构,提供具体实践指导,并分析其性能提升的内在机制。通过代码示例,我们将展示从基础搭建到高级功能的实现过程,旨在为开发者提供一条清晰的学习路径,以实现技术升级和项目效率的双重提升。
23 3
|
12天前
|
前端开发 JavaScript API
React、Vue.js 和 Angular前端三大框架对比与选择
前端框架是用于构建用户界面的工具和库,它提供组件化结构、数据绑定、路由管理和状态管理等功能,帮助开发者高效地创建和维护 web 应用的前端部分。常见的前端框架如 React、Vue.js 和 Angular,能够提高开发效率并促进团队协作。
28 4
|
9天前
|
JSON JavaScript 前端开发
构建高效Web应用:Node.js与Express框架的完美结合
【9月更文挑战第28天】在现代Web开发中,Node.js和Express框架的结合为创建高性能、易扩展的应用提供了强有力的支持。本文将深入探讨如何利用这两种技术构建一个简单但功能强大的Web服务,同时提供代码示例以加深理解。
|
1月前
|
Web App开发 JavaScript 前端开发
构建高效后端服务:Node.js与Express框架的实战指南
【9月更文挑战第6天】在数字化时代的潮流中,后端开发作为支撑现代Web和移动应用的核心,其重要性不言而喻。本文将深入浅出地介绍如何使用Node.js及其流行的框架Express来搭建一个高效、可扩展的后端服务。通过具体的代码示例和实践技巧,我们将探索如何利用这两个强大的工具提升开发效率和应用性能。无论你是后端开发的新手还是希望提高现有项目质量的老手,这篇文章都将为你提供有价值的见解和指导。
|
2月前
|
JavaScript 前端开发 中间件
构建高效后端服务:Node.js与Express框架的完美搭档
【8月更文挑战第28天】在追求高性能、可扩展和易维护的后端开发领域,Node.js和Express框架的组合提供了一种轻量级且灵活的解决方案。本文将深入探讨如何利用这一组合打造高效的后端服务,并通过实际代码示例展示其实现过程。
|
2月前
|
JavaScript 中间件 API
深入浅出Node.js后端框架——Express
【8月更文挑战第27天】在这篇文章中,我们将一起探索Node.js的热门框架Express。Express以其简洁、高效的特点,成为了许多Node.js开发者的首选框架。本文将通过实例引导你了解Express的核心概念和使用方法,让你快速上手构建自己的Web应用。
|
2月前
|
存储 JavaScript NoSQL
构建高效Web应用:使用Node.js和Express框架
【8月更文挑战第30天】本文将引导你了解如何使用Node.js和Express框架快速搭建一个高效的Web应用。通过实际的代码示例,我们将展示如何创建一个简单的API服务,并讨论如何利用中间件来增强应用功能。无论你是新手还是有经验的开发者,这篇文章都将为你提供有价值的见解。
|
3天前
|
JavaScript 中间件
**认识**Node.js Express
**认识**Node.js Express
12 3
|
14天前
|
前端开发 JavaScript 安全
node登陆接口权限配置cookie-parser、express-session
本文介绍了在Node.js中使用express-session和cookie-parser实现登录接口的权限配置,包括验证码接口的生成和自定义中间件的创建,用于验证用户权限。
12 0
node登陆接口权限配置cookie-parser、express-session
|
14天前
|
JavaScript 前端开发
vue配合axios连接express搭建的node服务器接口_简单案例
文章介绍了如何使用Express框架搭建一个简单的Node服务器,并使用Vue结合Axios进行前端开发和接口调用,同时讨论了开发过程中遇到的跨域问题及其解决方案。
13 0
vue配合axios连接express搭建的node服务器接口_简单案例
下一篇
无影云桌面