一、查询数据的问题

brand转为对象

前面我们学习的查询语句,查询到的结果通常是一张表,比如查询手机+品牌信息:

1
SELECT * FROM products LEFT JOIN brand ON products.brand_id = brand.id;

在真实开发中,实际上红色圈起来的部分应该放入到一个对象中,那么我们可以使用下面的查询方式:

这个时候我们要用 JSON_OBJECT;

1
2
3
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;

多对多转为数组

多对多关系中,我们希望查询到的是一个数组:

  • 比如一个学生的多门课程信息,应该是放到一个数组中的;
  • 数组中存放的是课程信息的一个个对象;
  • 这个时候我们要 JSON_ARRAYAGG和JSON_OBJECT结合来使用;
1
2
3
4
5
6
7
# 显示有GROUP BY进行分组
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;

二、Node中使用mysql2

前面我们所有的操作都是在GUI工具中,通过执行SQL语句来获取结果的,那真实开发中肯定是通过代码来完成所有的操作的。

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

  • mysql:最早的Node连接MySQL的数据库驱动;
  • mysql2:在mysql的基础之上,进行了很多的优化、改进;

目前相对来说,更偏向于使用mysql2,mysql2兼容mysql的API,并且提供了一些附加功能更快/更好的性能;

  • Prepared Statement(预编译语句):
    • 提高性能:将创建的语句模块发送给MySQL,然后MySQL编译(解析、优化、转换)语句模块,并且存储它但是不执行,之后我们在真正执行时会给?提供实际的参数才会执行;就算多次执行,也只会编译一次,所以性能是更高的;
    • 防止SQL注入:之后传入的值不会像模块引擎那样就编译,那么一些SQL注入的内容不会被执行;or 1 = 1不会被执行;
  • 支持Promise,所以我们可以使用async和await语法
  • 等等….

所以后续的学习中我会选择mysql2在node中操作数据

npm i mysql2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const mysql = require('mysql2');

const connection = mysql.createConnection({
host: 'localhost',
database: 'xxx',
user: 'root',
password: 'Xy515516@bxt',
});
connection.query(`SELECT * FROM user`, (err, res, fields) => {
console.log(res);
//结束 如果有错误会被监听到
connection.end()
//结束 有错误也不会被监听
connection.destory()
});
// [ { name: 'yy', age: 18, height: 1.78 } ]

Prepared Statement

Prepared Statement(预编译语句):

  • 提高性能:Node中创建的语句模块发送给MySQL,然后MySQL编译(解析、优化、转换)语句模块,并且存储它但是不执行,之后我们在真正执行时会给?提供实际的参数才会执行;就算多次执行,也只会编译一次,所以性能是更高的;
  • 防止SQL注入:之后传入的值不会像模块引擎那样就编译,那么一些SQL注入的内容不会被执行;or 1 = 1不会被执行;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const mysql = require('mysql2');

const connection = mysql.createConnection({
host: 'localhost',
database: 'xxx',
user: 'root',
password: 'Xy515516@bxt',
});

const statement = `SELECT * FROM user WHERE name = ?`;

connection.execute(statement, ['yy'], (err, res, fields) => {
console.log(res);
});

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

ORM

对象关系映射(英语:Object Relational Mapping,简称ORM,或O/RM,或O/R mapping),是一种程序设计的方案:

  • 从效果上来讲,它提供了一个可在编程语言中,使用 虚拟对象数据库 的效果;
  • 比如在Java开发中经常使用的ORM包括:Hibernate、MyBatis;

Node当中的ORM我们通常使用的是 sequelize;

  • Sequelize是用于Postgres,MySQL,MariaDB,SQLite和Microsoft SQL Server的基于Node.js 的 ORM;
  • 它支持非常多的功能;
  • 如果我们希望将Sequelize和MySQL一起使用,那么我们需要先安装两个东西:

mysql2:sequelize在操作mysql时使用的是mysql2;

sequelize:使用它来让对象映射到表中;

Sequelize

Sequelize的连接数据库:

第一步:创建一个Sequelize的对象,并且指定数据库、用户名、密码、数据库类型、主机地址等;

第二步:测试连接是否成功;

1
2
3
4
5
6
7
8
9
10
const { Sequelize } = require('sequelize');

const sequelize = new Sequelize('xxx', 'root', 'Xy515516@bxt', {
host: 'localhost',
dialect: 'mysql',
});
sequelize.authenticate().then(() => {
console.log('sequelize连接成功');
});
//sequelize连接成功