Nodejs mysql2+express+yaml

现在把需要把mysqlexpress,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 })
相关推荐
烬羽26 分钟前
我把"时间胶囊"部署上腾讯云宝塔,跨域从根源消失了
nginx·node.js·全栈
东风破_9 小时前
danci 2:创建的单词书到底存在哪里?从 Supabase 一路理解 ORM、Drizzle 和 RLS
数据库·后端·node.js
东风破_10 小时前
danci 项目(三):从 JSON 数据到 AI Coding,真实项目里的数据清洗、Prompt 和工程规范
前端·后端·node.js
东风破_10 小时前
danci 项目(一):从需求到架构,一个单词学习系统为什么会这样设计
前端·后端·node.js
__zRainy__16 小时前
Node系列 · Express:常用的中间件
中间件·node.js·express
时寒的笔记18 小时前
jsvmp04_某yuan宝日志还原rc4
node.js
coderCN18 小时前
Nodejs 第三十四章 数据库(表达式和函数、子查询和连表)
前端·node.js
5233AI开发笔记1 天前
Node.js 调用 API:为什么秘密型 Key 不能放前端
node.js
2601_962076251 天前
Node.js 完全教程:从入门到精通
node.js