本文详解 Node.js 中 Koa2 连接 MySQL 的多种实现方式。涵盖 mysql2 基础用法、JSON 聚合函数处理复杂查询、预处理语句提升性能及连接池管理。同时介绍基于 Promise 的异步操作,并深入讲解如何使用 Sequelize ORM 进行对象关系映射,包括数据库配置、连接测试及单表、多表关联操作。
在数据库查询场景中,通常需要将返回的结果转换为对象或数组格式,以便在业务逻辑中更便捷地处理数据。
在实际项目开发中,某些特定的查询结果往往需要封装到对象结构中,以便后续的业务逻辑处理。
MySQL 提供了 JSON_OBJECT 函数,其语法要求括号内以 key-value 的形式定义字段映射关系。
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 函数。

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;
接下来介绍 mysql2 库的具体应用。
首先通过 npm 安装 mysql2 依赖。
npm install mysql2以下是 mysql2 的基础使用示例。
const mysql = require('mysql2');
// 1.创建数据库连接
const connection = mysql.createConnection({
host: 'localhost',
port: 3306,
database: 'coderhub',
user: 'root',
password: 'Coderwhy888.'
});
// 2.执行SQL语句
const statement = `
SELECT * FROM products WHERE price > 6000;
`
connection.query(statement, (err, results, fields) => {
console.log(results);
});
若需在获取数据后终止服务,可在回调函数中调用连接结束方法。
connection.end()以下是完整的查询代码示例。
connection.query(statement, (err, results, fields) => {
console.log(results);
connection.end();
});
预处理语句(Prepared Statement)是提升数据库交互效率的关键机制。
其核心原理是将 SQL 语句模板发送至 MySQL 服务器,由服务器进行解析、优化并编译存储,但不立即执行。后续执行时,只需向 ? 提供实际参数即可触发执行;即使多次执行,也仅编译一次,从而显著提升性能。
需注意,再次执行该语句时,MySQL 会从 LRU(最近最少使用)缓存中直接获取已编译的语句对象,从而省略编译时间,进一步优化性能。
// 2.执行SQL语句: 使用 ?来对参数进行占位
const statement = `
SELECT * FROM products WHERE price > ? AND score > ?;
`
connection.execute(statement, [6000, 7], (err, results) => {
console.log(results);
});
连接池(Connection Pools)用于高效管理数据库连接资源。
前文示例仅创建单一连接,若面临高并发请求,该连接可能处于占用状态。此时,是否每次请求都需新建连接?
- 实际上,mysql2 提供了连接池功能以解决此问题。
- 连接池可根据需求自动创建连接,且这些连接不会被销毁,而是保留在池中供后续请求复用。
- 在初始化连接池时,可设置 LIMIT 参数以限制最大连接数。
以下是判断数据库连接是否成功的示例代码。
const mysql = require('mysql2');
// 1.创建连接池
const connections = mysql.createPool({
host: 'localhost',
port: 3306,
database: 'coderhub',
user: 'root',
password: 'Coderwhy888.',
connectionLimit: 10
});
connections.getConnection((err, conn) => {
conn.connect((err) => {
if(err){
console.log('连接失败:',err)
} else {
console.log('数据库连接成功~')
}
})
})
以下是使用数据库的简化操作流程。
const mysql = require('mysql2');
// 1.创建连接池
const connections = mysql.createPool({
host: 'localhost',
port: 3306,
database: 'coderhub',
user: 'root',
password: 'Coderwhy888.',
connectionLimit: 10
});
// 2.使用连接池
const statement = `
SELECT * FROM products WHERE price > ? AND score > ?;
`
connections.execute(statement, [6000, 7], (err, results) => {
console.log(results);
});
介绍基于 Promise 的异步数据库操作方式。
const mysql = require('mysql2');
// 1.创建连接池
const connections = mysql.createPool({
host: 'localhost',
port: 3306,
database: 'coderhub',
user: 'root',
password: 'Coderwhy888.',
connectionLimit: 10
});
// 2.使用连接池
const statement = `
SELECT * FROM products WHERE price > ? AND score > ?;
`
connections.promise().execute(statement, [6000, 7]).then(([results,fields]) => {
console.log(results);
}).catch(err => {
console.log(err);
});
Sequelize 是 Node.js 生态中广泛使用的 ORM 框架。
对象关系映射(ORM)是一种程序设计范式。
- 从效果上看,它允许开发者在编程语言中通过虚拟对象来操作数据库。
在 Node.js 开发中,通常选用 Sequelize 作为 ORM 工具。
- Sequelize 支持 Postgres、MySQL、MariaDB、SQLite 及 Microsoft SQL Server 等多种数据库,是基于 Node.js 的 ORM 库。
- 该框架支持丰富的功能特性。
若希望将 Sequelize 与 MySQL 配合使用,需预先安装两个关键组件。
- mysql2:Sequelize 在操作 MySQL 时依赖此驱动。
- sequelize:用于实现对象到数据库表的映射逻辑。
npm install sequelize mysql2以下是 Sequelize 的具体使用步骤。
首先演示如何连接数据库。
第一步:实例化 Sequelize 对象,并指定数据库名称、用户名、密码、数据库类型及主机地址等配置参数。
第二步:执行测试以验证连接是否成功建立。
const { Sequelize } = require('sequelize');
const sequelize = new Sequelize('coderhub', 'root', 'Coderwhy888.', {
host: 'localhost',
dialect: 'mysql'//连接的数据库类型:mysql,mongoose
});
sequelize.authenticate().then(() => {
console.log("连接数据库成功~");
}).catch(err => {
console.log("连接数据库失败~", err);
});
接下来介绍 Sequelize 的单表数据操作。
const { Sequelize, DataTypes, Model, Op } = require('sequelize');
const sequelize = new Sequelize("coderhub", 'root', 'Coderwhy888.', {
host: 'localhost',
dialect: 'mysql'
})
//1.首先我们需要将数据库中的一张表映射成一个class类
class Product extends Model {}
Product.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,//主键
autoIncrement: true//自动增长
},
title: {
type: DataTypes.STRING,
allowNotNull: false//是否可以为空
},
price: DataTypes.DOUBLE,
score: DataTypes.DOUBLE
}, {//与数据库的表进行映射的配置
tableName: 'products',
createdAt: false,
updatedAt: false,
sequelize
});
//存放操作数据库的代码
async function queryProducts() {
//1.查询数据库中product表中所有的内容
const result1 = await Product.findAll({
where: {//在这里配置条件
price: {
[Op.gte]: 5000//意思是价格大于等于5000
//gte:大于等于,gt:大于,lt:小于,lte:小于等于
}
}
});
console.log(result1);
// 2.插入数据
const result2 = await Product.create({
title: "三星Nova",
price: 8888,
score: 5.5
});
console.log(result2);
// 3.更新数据
const result3 = await Product.update({
price: 3688
}, {
where: {
id: 1
}
});
console.log(result3);
}
queryProducts();//执行这个函数可以实现对数据库的操作
随后讲解 Sequelize 的一对多关联操作。
const { Sequelize, DataTypes, Model, Op } = require('sequelize');
const sequelize = new Sequelize("coderhub", 'root', 'Coderwhy888.', {
host: 'localhost',
dialect: 'mysql'
});
//数据库的第一个表: 主表
class Brand extends Model {};
Brand.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNotNull: false
},
website: DataTypes.STRING,
phoneRank: DataTypes.INTEGER
}, {
tableName: 'brand',
createdAt: false,
updatedAt: false,
sequelize
});
//数据库的第二个表:附表
class Product extends Model {}
Product.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
title: {
type: DataTypes.STRING,
allowNotNull: false
},
price: DataTypes.DOUBLE,
score: DataTypes.DOUBLE,
brandId: {
field: 'brand_id',
type: DataTypes.INTEGER,
references: {//这张表使用了Brand的id作为外键
model: Brand,//product这张表使用了Brand这个表,所以product必须放在下面
key: 'id'
}
}
}, {
tableName: 'products',
createdAt: false,
updatedAt: false,
sequelize
});
// 将两张表联系在一起
Product.belongsTo(Brand, {
foreignKey: 'brandId'//外键
});
async function queryProducts() {
const result = await Product.findAll({
include: { //这里是联合查询:意思是包含别的表的信息
model: Brand
}
});
console.log(result);
}
queryProducts();
最后说明 Sequelize 的多对多关联操作。
const { Sequelize, DataTypes, Model, Op } = require('sequelize');
const sequelize = new Sequelize("coderhub", 'root', 'Coderwhy888.', {
host: 'localhost',
dialect: 'mysql'
});
// Student表
class Student extends Model {}
Student.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNotNull: false
},
age: DataTypes.INTEGER
}, {
tableName: 'students',
createdAt: false,
updatedAt: false,
sequelize
});
// Course表
class Course extends Model {}
Course.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: DataTypes.STRING,
allowNotNull: false
},
price: DataTypes.DOUBLE
}, {
tableName: 'courses',
createdAt: false,
updatedAt: false,
sequelize
});
// StudentCourse表:关系表
class StudentCourse extends Model {}
StudentCourse.init({
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
studentId: {//与Student表建立关系
type: DataTypes.INTEGER,
references: {
model: Student,
key: 'id'
},
field: 'student_id'
},
courseId: {//与Course表建立关系
type: DataTypes.INTEGER,
references: {
model: Course,
key: 'id'
},
field: 'course_id'
}
}, {
tableName: 'students_select_courses',
createdAt: false,
updatedAt: false,
sequelize
});
// 多对多关系的联系:Student StudentCourse Course
Student.belongsToMany(Course, {
through: StudentCourse,
foreignKey: 'studentId',//这里是Student与StudentCourse,所以外键是studentId
otherKey: 'courseId'//StudentCourse与Course,所以外键是courseId
});
//与上面类似
Course.belongsToMany(Student, {
through: StudentCourse,
foreignKey: 'courseId',
otherKey: 'studentId'
});
async function queryProducts() {
const result = await Student.findAll({
include: {//所有学生的选课情况
model: Course
}
});
console.log(result);
}
queryProducts();
至此,关于 Node.js 中 Koa2 连接 MySQL 的实现示例介绍完毕。如需了解更多相关 Koa2 连接 MySQL 的内容,请搜索本站往期文章或继续阅读后续相关文章,感谢大家的支持!