现在把需要把mysql和express,nodejs连接起来。
安装依赖
npm install mysql2 express js-yaml
- mysql2 用来连接mysql和编写sql语句
- express 用来提供接口 增删改差
- 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。
好处:
- 代码和配置分离;改数据库信息不用修改 js 代码
- 开发环境、测试、生产环境可以放不同配置
- 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()
特点
- 每次调用
createConnection,新建一条物理 TCP 连接和 MySQL 握手认证。 - 请求量大的时候,频繁创建销毁连接,性能差。
- 如果忘记
conn.end(),连接会一直挂在 MySQL,占用连接数,会造成连接泄漏。 - 适合:脚本、一次性小程序,只执行少量 SQL 就退出。
- ❌ 不适合 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')
工作原理
- 初始化时,维护最多
connectionLimit条连接。 - 执行
pool.query():自动从池子里拿空闲连接,执行 SQL,执行完自动归还连接回池子 ,不需要手动.end()。 - 并发请求过来,复用已有连接,不需要反复和 MySQL 握手认证,性能高。
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')
事务场景区别
- 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()
- 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 会直接销毁连接。
开发建议
- 写后端接口(express):一定用 createPool,全局只 new 一次 pool,不要每次接口都创建连接。
- 本地跑一次性脚本:可以简单用 createConnection。
- 不要把 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 })