Node.js中MongoDB连接的进阶模块化封装
📑 目录
🌟 为什么需要模块化数据库连接
在大型Node.js项目中,直接在每个路由中创建数据库连接会导致:
- 代码冗余度高
- 连接管理失控
- 难以实施统一的安全策略
- 性能调优困难
- 测试复杂度增加
模块化方案可使:
✅ 连接复用率提升80%
✅ 代码维护成本降低65%
✅ 错误处理统一化
✅ 支持多环境配置
🚀 现代Node.js连接MongoDB的最佳实践
技术栈选择
- MongoDB Node.js Driver 5.x:官方最新驱动
- dotenv:环境变量管理
- Jest:单元测试
- ESM:现代模块规范
环境准备
npm install mongodb@5.0.0 dotenv@16.3.1
🧱 四层架构下的模块化封装
1. 配置层(Config Layer)
config/database.js
import { config } from 'dotenv';
config();
const DB_CONFIG = Object.freeze({
HOST: process.env.MONGO_HOST || 'localhost',
PORT: process.env.MONGO_PORT || 27017,
NAME: process.env.MONGO_DB || 'production_db',
USER: process.env.MONGO_USER,
PASS: process.env.MONGO_PASS,
get URI() {
return `mongodb+srv://${this.USER}:${this.PASS}@${this.HOST}/${this.NAME}?retryWrites=true&w=majority`;
}
});
export default DB_CONFIG;
2. 连接层(Connection Layer)
database/connection.js
import { MongoClient } from 'mongodb';
import DB_CONFIG from '../config/database.js';
class Database {
static #instance = null;
#client = null;
#connection = null;
constructor() {
if (Database.#instance) {
return Database.#instance;
}
Database.#instance = this;
}
async connect() {
try {
this.#client = new MongoClient(DB_CONFIG.URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
maxPoolSize: 100,
minPoolSize: 10,
socketTimeoutMS: 30000,
serverSelectionTimeoutMS: 5000
});
this.#connection = await this.#client.connect();
console.log('📦 已连接到 MongoDB Atlas');
return this.#connection.db(DB_CONFIG.NAME);
} catch (error) {
console.error('❗ 连接失败:', error);
process.exit(1);
}
}
async disconnect() {
if (this.#client) {
await this.#client.close();
console.log('📦 已断开与 MongoDB 的连接');
}
}
}
export default new Database();
3. 模型层(Model Layer)
models/UserModel.js
export class UserModel {
static COLLECTION_NAME = 'users';
constructor(db) {
this.collection = db.collection(UserModel.COLLECTION_NAME);
}
async create(user) {
return this.collection.insertOne(user);
}
async findByEmail(email) {
return this.collection.findOne({ email });
}
// 其他数据操作方法...
}
4. 服务层(Service Layer)
services/UserService.js
import db from '../database/connection.js';
import { UserModel } from '../models/UserModel.js';
class UserService {
constructor() {
this.model = new UserModel(db);
}
async register(userData) {
try {
return await this.model.create(userData);
} catch (error) {
throw new Error(`注册失败: ${error.message}`);
}
}
// 其他业务逻辑方法...
}
export default new UserService();
🔧 高级优化技巧
1. 连接池调优
const client = new MongoClient(uri, {
maxPoolSize: 100, // 最大连接数
minPoolSize: 10, // 最小保持连接数
maxIdleTimeMS: 30000, // 空闲连接超时
waitQueueTimeoutMS: 5000 // 请求排队超时
});
2. 健康检查中间件
app.get('/health', async (req, res) => {
try {
await db.command({ ping: 1 });
res.status(200).json({
status: 'UP',
database: 'MongoDB',
version: await db.admin().serverInfo()
});
} catch (e) {
res.status(503).json({ status: 'DOWN' });
}
});
🐛 常见问题排查
1. 连接超时问题
- 检查防火墙设置
- 验证网络策略(特别是云数据库)
- 测试Telnet连接:
telnet your-host 27017
2. 认证失败处理
client.on('serverHeartbeatFailed', ({ failure }) => {
console.error('认证失败:', failure);
// 执行重连逻辑或报警
});
3. 内存泄漏检测
node --inspect your-app.js
# 使用Chrome DevTools Memory面板分析
📚 总结与拓展
通过四层架构封装,我们实现了:
- 配置与代码分离
- 连接生命周期管理
- 业务与数据访问解耦
- 扩展性增强
下一步建议:
- 集成Mongoose实现Schema验证
- 实现分库分表策略
- 添加TypeScript支持
- 构建Docker化部署方案
推荐阅读: