【全栈】Next.js + MySQL 实现CRUD完整代码(包含部署生产环境)
·
使用Next.js 13+ App Router 路由实现基本的数据库增删改查操作,我的文章中均为完整可用代码。
一、实现思路
- 安装必要依赖(MySQL 客户端、环境变量管理)
- 配置数据库连接(使用环境变量,避免硬编码敏感信息)
- 创建数据库操作工具类(封装连接、关闭、查询方法)
- 实现增删改查(CRUD)的具体接口
- 在 Next.js API 路由中使用这些方法
二、具体实现步骤
项目结构
/
├── .env.local # 本地开发环境
├── .env.production # 生产环境(不上传git)
├── lib/
│ └── db.js # 数据库核心封装(生产级)
└── app/
└── api/
└── users/
└── route.js # CRUD 接口(生产可用)
1. 安装依赖
首先在你的 Next.js 项目根目录执行以下命令:
# 安装 MySQL2(推荐,比 mysql 包性能更好、更现代)
npm install mysql2
# 安装 dotenv 管理环境变量(Next.js 13+ 内置支持,但显式安装更兼容)
npm install dotenv --save-dev
2. 配置环境变量(注意区分本地和生产环境)
在项目根目录创建 .env.local 文件(Next.js 会自动加载此文件,且不会被 Git 追踪):
# 数据库连接配置
MYSQL_HOST=localhost
MYSQL_PORT=3306
MYSQL_USER=root
MYSQL_PASSWORD=你的数据库密码
MYSQL_DATABASE=你的数据库名
# 可选:连接池配置
MYSQL_CONNECTION_LIMIT=10
# 生产禁用
NODE_ENV=development
.env.production(生产环境,绝不提交到 Git)
# 生产数据库(云服务器/云数据库)
MYSQL_HOST=xxx.rds.aliyuncs.com
MYSQL_PORT=3306
MYSQL_USER=prod_user
MYSQL_PASSWORD=生产强密码
MYSQL_DATABASE=prod_db
MYSQL_CONNECTION_LIMIT=20
# 生产开启安全模式
NODE_ENV=production
3. 创建数据库连接工具
在项目中创建 lib/db.js 文件,支持:连接池、防注入、错误捕获、生产日志、自动重连。
封装数据库连接逻辑:
// lib/db.js
import mysql from 'mysql2/promise';
// 生产环境必须校验环境变量
if (process.env.NODE_ENV === 'production') {
const required = [
'MYSQL_HOST',
'MYSQL_USER',
'MYSQL_PASSWORD',
'MYSQL_DATABASE',
];
const missing = required.filter(key => !process.env[key]);
if (missing.length) {
throw new Error(`生产环境缺少环境变量:${missing.join(', ')}`);
}
}
// 创建生产级连接池
const pool = mysql.createPool({
host: process.env.MYSQL_HOST,
port: process.env.MYSQL_PORT || 3306,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
connectionLimit: process.env.MYSQL_CONNECTION_LIMIT || 10,
// 生产关键配置
waitForConnections: true,
queueLimit: 0,
enableKeepAlive: true,
keepAliveInitialDelay: 30000,
charset: 'utf8mb4',
dateStrings: true,
});
// 通用查询(完全防SQL注入)
export async function query(sql, params = []) {
try {
const [rows] = await pool.execute(sql, params);
return rows;
} catch (error) {
console.error('【数据库错误】', error.message);
// 生产环境不返回真实错误
if (process.env.NODE_ENV === 'production') {
throw new Error('服务器繁忙,请稍后再试');
} else {
throw error;
}
}
}
// 测试连接(启动时执行)
export async function testDbConnection() {
try {
const connection = await pool.getConnection();
console.log('✅ 数据库连接成功');
connection.release();
} catch (err) {
console.error('❌ 数据库连接失败', err.message);
process.exit(1); // 生产直接退出,避免异常运行
}
}
// 启动测试
testDbConnection();
export default pool;
4. CRUD 接口(app/api/users/route.js)
包含:参数校验、生产安全返回、统一格式
以用户表为例,假设你有一个 users 表,结构如下:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
接口完整代码
// app/api/users/route.js
import { query } from '@/lib/db';
import { NextResponse } from 'next/server';
// GET:查询用户列表 / 单个用户
export async function GET(request) {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
let sql, params;
if (id) {
sql = 'SELECT * FROM users WHERE id = ?';
params = [id];
} else {
sql = 'SELECT * FROM users ORDER BY id DESC LIMIT 50'; // 生产必须加 LIMIT
}
const data = await query(sql, params);
return NextResponse.json({ success: true, data });
} catch (error) {
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
);
}
}
// POST:创建用户
export async function POST(request) {
try {
const { name, email } = await request.json();
// 严格校验
if (!name?.trim() || !email?.trim()) {
return NextResponse.json(
{ success: false, error: '姓名和邮箱不能为空' },
{ status: 400 }
);
}
const sql = 'INSERT INTO users (name, email) VALUES (?, ?)';
const result = await query(sql, [name, email]);
return NextResponse.json({
success: true,
message: '创建成功',
data: { id: result.insertId, name, email },
});
} catch (error) {
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
);
}
}
// PUT:更新用户
export async function PUT(request) {
try {
const { id, name, email } = await request.json();
if (!id || !name || !email) {
return NextResponse.json(
{ success: false, error: '参数不完整' },
{ status: 400 }
);
}
const sql = 'UPDATE users SET name = ?, email = ? WHERE id = ?';
await query(sql, [name, email, id]);
return NextResponse.json({ success: true, message: '更新成功' });
} catch (error) {
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
);
}
}
// DELETE:删除用户
export async function DELETE(request) {
try {
const { searchParams } = new URL(request.url);
const id = searchParams.get('id');
if (!id) {
return NextResponse.json(
{ success: false, error: '缺少用户ID' },
{ status: 400 }
);
}
const sql = 'DELETE FROM users WHERE id = ?';
await query(sql, [id]);
return NextResponse.json({ success: true, message: '删除成功' });
} catch (error) {
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
);
}
}
三、生产环境必须遵守的 10 条安全规则!!!
- 绝对不能把数据库密码写在代码里(必须用 .env.local / .env.production)
- 必须使用连接池,不能每次请求都新建连接(createPool)
- 必须使用参数化查询(防 SQL 注入)
// ✅ 安全
query('SELECT * FROM users WHERE id = ?', [id])
// ❌ 危险(永远不要写)
query(`SELECT * FROM users WHERE id = ${id}`)
- 生产环境不暴露真实错误(一般返回’服务器繁忙‘)
- 查询必须加 LIMIT(防止全表扫描拖垮数据库)
- 数据库账号必须最小权限(生产环境 MySQL 账号只给:SELECT / INSERT / UPDATE / DELETE不给 DROP / ALTER 权限)
- 生产环境禁止使用 root 连接数据库
- 云数据库必须开启白名单,只允许服务器 IP 访问
- 密码必须是强密码(16 位以上,字母 + 数字 + 符号)
- 绝不把 .env.production 上传到 Git
在 .gitignore 加上:
.env*.local
.env.production
四、上线部署
- 服务器安装 Node.js
- 上传代码(不含环境变量)
- 服务器手动创建 .env.production
- 运行
npm install
npm run build
npm start
完成~~~~~
更多推荐

所有评论(0)