Node.js/Express中MySQL2 Promise API的正确连接方式咨询
MySQL2 Promise API 数据库连接正确方案
使用MySQL2 Promise API时,核心问题是mysql.createConnection()返回的是Promise对象,而非直接的数据库连接实例。如果直接将其赋值给变量,拿到的是Promise而非可用的连接,必须通过await或.then()链式调用获取实际连接实例。
方案1:转为ES模块,使用顶层await
将项目改为ES模块(在package.json中添加"type": "module"),即可直接在顶层使用await获取连接。
import dotenv from 'dotenv' dotenv.config() import mysql from 'mysql2/promise.js' import express from 'express' import ejs from 'ejs' import {faker} from '@faker-js/faker' import path from 'path' const app = express(); app.set("view engine", "ejs"); app.use(express.json()) // mysql2/promise的createConnection已自动建立连接,无需额外调用connect() const connection = await mysql.createConnection({ host: "localhost", user: "root", password: process.env.SQL_PASSWORD, database: "joinus" }) app.get('/users', async(req,res,next) => { // query返回[结果集, 字段信息],通常取第一个元素即可 const [rows] = await connection.query('SELECT * FROM users') res.send(rows) }) app.listen(5000, () => { console.log("服务启动在5000端口"); });
说明:
- 优点:代码简洁,无需额外包裹函数
- 注意:需将项目设为ES模块(
package.json配置"type": "module"),Node.js版本需支持顶层await(v14.8+)
方案2:用async主函数包裹应用逻辑
无需修改模块类型,将所有依赖数据库的逻辑放在async函数中,调用该函数启动应用。
if (process.env.NODE_ENV !== "production") { require("dotenv").config(); } const mysql = require("mysql2/promise"); const express = require("express"); const ejs = require("ejs"); const { faker } = require('@faker-js/faker'); const path = require("path"); const app = express(); app.set("view engine", "ejs"); app.set("views", path.join(__dirname + "/views")); app.use(express.json()) async function main() { const connection = await mysql.createConnection({ host: "localhost", user: "root", password: process.env.SQL_PASSWORD, database: "joinus" }) app.get('/users', async(req,res,next) => { const [rows] = await connection.query('SELECT * FROM users') res.send(rows) }) app.listen(5000, () => { console.log("服务启动在5000端口"); }); } // 记得捕获启动过程中的错误,避免未处理的Promise异常 main().catch(err => console.error("应用启动失败:", err))
说明:
- 优点:兼容CommonJS模块(无需修改
package.json),逻辑清晰易读 - 注意:必须调用
main()并捕获错误,避免程序崩溃
方案3:使用.then()链式调用处理连接
通过Promise的.then()方法获取连接实例,赋值给变量后使用。
if (process.env.NODE_ENV !== "production") { require("dotenv").config(); } const mysql = require("mysql2/promise"); const express = require("express"); const ejs = require("ejs"); const { faker } = require("@faker-js/faker"); const path = require("path"); const app = express(); app.set("view engine", "ejs"); app.set("views", path.join(__dirname + "/views")); app.use(express.json()); let connection; mysql.createConnection({ host: "localhost", user: "root", password: process.env.SQL_PASSWORD, database: "joinus" }).then((result) => { connection = result; console.log("数据库连接成功"); }).catch(err => console.error("数据库连接失败:", err)) app.get("/users", async (req, res, next) => { // 需额外判断连接是否就绪,否则会出现未定义错误 if (!connection) { return res.status(503).send("数据库连接未就绪"); } const [rows] = await connection.query("SELECT * FROM users"); res.send(rows); }); app.listen(5000, () => { console.log("服务启动在5000端口"); });
说明:
- 缺点:存在连接未就绪时请求先到达的风险,代码可读性不如async/await
- 适合:习惯Promise链式调用写法的场景
方案4:使用连接池(推荐生产环境)
单连接无法应对高并发场景,mysql2的连接池会自动管理连接的创建、复用与释放,是生产环境的标准实践。
if (process.env.NODE_ENV !== "production") { require("dotenv").config(); } const mysql = require("mysql2/promise"); const express = require("express"); const ejs = require("ejs"); const { faker } = require('@faker-js/faker'); const path = require("path"); const app = express(); app.set("view engine", "ejs"); app.set("views", path.join(__dirname + "/views")); app.use(express.json()) // 创建连接池,配置最大连接数等参数 const pool = mysql.createPool({ host: "localhost", user: "root", password: process.env.SQL_PASSWORD, database: "joinus", waitForConnections: true, connectionLimit: 10, // 最大并发连接数 queueLimit: 0 }) app.get('/users', async(req,res,next) => { // 直接通过连接池执行查询,无需手动管理连接 const [rows] = await pool.query('SELECT * FROM users') res.send(rows) }) app.listen(5000, () => { console.log("服务启动在5000端口"); });
说明:
- 优点:自动复用连接,提升并发性能,无需手动处理连接关闭
- 推荐:生产环境和有并发需求的应用优先使用
新手开发者推荐方向
- 刚接触Node.js的新手优先选方案2,无需修改模块配置,逻辑清晰,还能熟练掌握async/await的正确用法。
- 熟悉ES模块的开发者可以用方案1,写法更简洁。
- 尽量避免方案3,存在连接未就绪的风险,代码维护性差。
- 当应用需要处理并发请求时,直接采用方案4(连接池),这是生产环境的最优选择。
内容的提问来源于stack exchange,提问作者northendben
相关产品推荐
相关产品推荐

