Nodejs mysql2+express+yaml

现在把需要把mysql和express,nodejs连接起来。

安装依赖

复制代码
npm install mysql2 express js-yaml
  1. mysql2 用来连接mysql和编写sql语句
  2. express 用来提供接口 增删改差
  3. js-yaml 用来编写配置文件

编写代码

  • db.config.yaml
yaml 复制代码
db:
   host: localhost #主机
   port: 3306 #端口
   user: root #账号
   password: '123456' #密码 一定要字符串
   database: xiaoman # 库
  • index.js
js 复制代码
import mysql2 from "mysql2/promise";
import * as jsyaml from "js-yaml";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import express from "express";

// ESM 获取当前文件所在目录路径
const __filename = fileURLToPath(import.meta.url); //C:\CN\全栈AI\node\nodecode\mysql-express-yaml\index.js
const __dirname = path.dirname(__filename); //C:\CN\全栈AI\node\nodecode\mysql-express-yaml
console.log(__filename, __dirname);
// 读取 db.config.yaml 文件
const yamlText = fs.readFileSync(
  path.join(__dirname, "./db.config.yaml"),
  "utf8"
);
const config = jsyaml.load(yamlText);

// 创建数据库连接------是异步的,所以下面都要用async await
const sql = await mysql2.createConnection({
  ...config.db,
});
// console.log('sql', sql)

const app = express();
app.use(express.json());

//查询接口 全部
app.get("/", async (req, res) => {
  const [data] = await sql.query("select * from user");
  res.send(data);
});
//单个查询 params
app.get("/user/:id", async (req, res) => {
  const [row] = await sql.query(
    `select * from user where id = ${req.params.id}`
  );
  // const [row] = await sql.query(`select * from user where id = ?`, [
  //   req.params.id,
  // ]);
  res.send(row);
});

//新增接口
app.post("/create", async (req, res) => {
  const { name, age, address } = req.body;
  await sql.query(`insert into user(name,age,address) values(?,?,?)`, [
    name,
    age,
    address,
  ]);
  res.send({ ok: 1 });
});

//编辑
app.post("/update", async (req, res) => {
  const { name, age, address, id } = req.body;
  await sql.query(`update user set name = ?,age = ?,address = ? where id = ?`, [
    name,
    age,
    address,
    id,
  ]);
  res.send({ ok: 1 });
});
//删除
app.post("/delete", async (req, res) => {
  await sql.query(`delete from user where id = ?`, [req.body.id]);
  res.send({ ok: 1 });
});
const port = 3000;

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`);
});
  • index.http

方便测试接口

http 复制代码
# 查询全部
 GET http://localhost:3000/ HTTP/1.1

# 单个查询
GET http://localhost:3000/user/2 HTTP/1.1

# 添加数据
POST http://localhost:3000/create HTTP/1.1
Content-Type: application/json

{
    "name":"张三",
    "age":18
}

# 更新数据
POST http://localhost:3000/update HTTP/1.1
Content-Type: application/json

{
    "name":"法外狂徒",
    "age":20,
    "id":23
}


#删除
# POST http://localhost:3000/delete HTTP/1.1
# Content-Type: application/json

# {
#     "id":24
# }

db.config.yaml

db.config.yaml 是数据库配置文件 ,后缀 .yaml / .yml。 作用:把数据库连接信息抽离到配置文件,不写死在代码里。

host、端口、账号、密码、库名,全部写在 yaml,代码读取这个文件获取参数,再去连接 mysql2。

好处:

  1. 代码和配置分离;改数据库信息不用修改 js 代码
  2. 开发环境、测试、生产环境可以放不同配置
  3. yaml 格式简洁,比 json 少写引号逗号

⚠️ 重要:yaml 严禁 tab 缩进,只能用空格,一般 2 空格缩进。

典型完整格式 db.config.yaml

yaml 复制代码
# db.config.yaml
# mysql数据库配置
mysql:
  host: 127.0.0.1
  port: 3306
  user: root
  password: "123456"
  database: test_db
  charset: utf8mb4
  # 连接池配置 mysql2 pool
  connectionLimit: 10
  waitForConnections: true
  queueLimit: 0

# 也可以区分环境
dev:
  mysql:
    host: 127.0.0.1
    port: 3306
    user: root
    password: "dev123"
    database: dev_database

prod:
  mysql:
    host: 192.168.1.100
    port: 3306
    user: prod_user
    password: "@Prod#2026"
    database: prod_db

createPool vs createConnection 核心区别

php 复制代码
// ① 创建连接池
const pool = mysql2.createPool({ 
  host: dbConf.host, 
  port: dbConf.port, 
  user: dbConf.user, 
  password: dbConf.password, 
  database: dbConf.database, 
  connectionLimit: dbConf.connectionLimit, 
  waitForConnections: dbConf.waitForConnections 
});

// ② 创建单次连接
const sql = await mysql2.createConnection({ ...config.db })

1. createConnection 单次连接

创建一条独立数据库连接,用完需要手动关闭

csharp 复制代码
const conn = await mysql2.createConnection({...config.db})

// 查询
const [rows] = await conn.query('select * from user')

// ⚠️ 用完必须手动关闭
await conn.end()

特点

  1. 每次调用 createConnection,新建一条物理 TCP 连接和 MySQL 握手认证。
  2. 请求量大的时候,频繁创建销毁连接,性能差。
  3. 如果忘记 conn.end(),连接会一直挂在 MySQL,占用连接数,会造成连接泄漏。
  4. 适合:脚本、一次性小程序,只执行少量 SQL 就退出。
  5. ❌ 不适合 Web 服务接口(Express/Koa) 。每来一个 http 请求新建连接会把 MySQL 连接打满。

如果你写接口,每访问一次接口执行一次createConnection,会疯狂新建连接。

2. createPool 连接池(Web 项目生产环境推荐)

连接池:提前创建好一批数据库连接,放在池子里面,复用连接。

arduino 复制代码
const pool = mysql2.createPool({
  ...config.db,
  connectionLimit: 10, //池子最多保存10条连接
  waitForConnections: true
})

// 直接使用pool,不需要手动获取/释放连接!
const [rows] = await pool.query('SELECT * FROM user')

工作原理

  1. 初始化时,维护最多 connectionLimit 条连接。
  2. 执行 pool.query():自动从池子里拿空闲连接,执行 SQL,执行完自动归还连接回池子 ,不需要手动.end()。
  3. 并发请求过来,复用已有连接,不需要反复和 MySQL 握手认证,性能高。
  4. waitForConnections:true:池子满了,新请求排队等待空闲连接,而不是直接报错。

特点

  • ✅ 连接复用,性能高,避免反复创建销毁 TCP
  • ✅ 自动管理连接,不会连接泄漏
  • ✅ 适合 web 服务、接口服务(Express/Koa 后端必用)
  • ✅ 可以直接 pool.query(),不用手动拿连接
  • 如果你需要事务,可以手动取出连接:const conn = await pool.getConnection(),用完 conn.release() 归还池子。

关键对比表

表格

项目 createConnection createPool(连接池)
连接行为 每次新建物理连接 复用池子里已有连接
关闭 必须手动await conn.end() 自动归还,不用手动关闭
适用场景 一次性脚本、简单 demo Web 接口、后端服务(生产首选)
并发性能 差,频繁创建销毁 好,连接复用
泄漏风险 容易忘记 end,发生泄漏 几乎不会泄漏
事务 直接 conn.beginTransaction () 需要pool.getConnection()拿到连接再事务

两个写法简单示例

createConnection(脚本示例)

javascript 复制代码
// 适合一次性脚本执行完就退出
const conn = await mysql2.createConnection({...config.db})
const [rows] = await conn.query('select 1')
console.log(rows)
await conn.end() // 必须关闭!

createPool(web 后端,项目标准写法)

javascript 复制代码
// db.js 全局只初始化一次pool,整个项目复用这一个pool
const pool = mysql2.createPool({
  ...config.db,
  connectionLimit: 10,
  waitForConnections: true
})

export default pool

// 在业务接口直接导入pool使用
import pool from './db.js'
const [rows] = await pool.query('select * from user')

事务场景区别

  1. createConnection
vbnet 复制代码
const conn = await mysql2.createConnection({...config.db})
await conn.beginTransaction()
await conn.query(sql1)
await conn.query(sql2)
await conn.commit()
await conn.end()
  1. createPool 事务(必须手动取出连接)
csharp 复制代码
const conn = await pool.getConnection() // 从池子拿一条连接
try{
  await conn.beginTransaction()
  await conn.query(sql1)
  await conn.query(sql2)
  await conn.commit()
}catch(e){
  await conn.rollback()
}finally{
  conn.release() // 归还到池子!!不是end()
}

pool 拿到的连接用 .release() 归还池子,不能用 .end(),end 会直接销毁连接。

开发建议

  1. 写后端接口(express):一定用 createPool,全局只 new 一次 pool,不要每次接口都创建连接。
  2. 本地跑一次性脚本:可以简单用 createConnection。
  3. 不要把 pool 到处重复创建,整个应用只初始化一个 pool 实例。

很多新手踩坑:在路由函数内部写 const pool = mysql2.createPool({...}),每次访问接口新建一个池子,这是错误。pool 只需要在项目启动初始化一次。

结合你的 yaml 配置修改你的 db.config.yaml

yaml 复制代码
db:
  host: localhost
  port: 3306
  user: root
  password: '123456'
  database: xiaoman
  connectionLimit: 10
  waitForConnections: true

读取后直接:

arduino 复制代码
const pool = mysql2.createPool({ ...config.db })
相关推荐
wno7044 小时前
node.js中使用jquery
前端·node.js·jquery
damoluomu1 天前
Node 的 Headless 出厂没有前台,Java 的 Headless 是从门户里长出来的
java·开发语言·node.js
Dumbness1 天前
一个手机号验证码登录接口的五个坑:无限发码、无限试码,传个数字就让 Express 进程退出
node.js·express
怒放的生命19911 天前
本地用 pnpm 省磁盘,团队继续用 npm:极简实践
前端·npm·node.js
Hone2 天前
我把「自动发文章到掘金」做成了一个 Agent 技能:juejin-skills
node.js·ai编程·前端工程化
Dumbness2 天前
二十行手写的 SKILL.md 头部解析,遇到 YAML 的折叠写法、单引号和嵌套键就读错:和 js-yaml 逐条对照
node.js·ai编程
只睡四小时3 天前
MCP 弃用 SSE?Node 分帧漏 81.7% 事件
node.js·webassembly·实时通信·mcp·streamable http
hey you~3 天前
个体户门店办理400电话,如何对接订单系统实现来电弹窗
node.js·webhook·400电话·门店数字化·来电弹窗·订单系统对接
YIAN4 天前
RAG 学到最后,我真正学会的不是“检索”,而是让系统知道自己缺什么
langchain·node.js·llm
用户11977079480734 天前
GitHub 电商开源项目分享:用 sharp 批量出饰品主图,试了裁剪、细节图和色彩配置文件三个坑
前端·node.js