同一服务器双MongoDB切换:Node.js CMS多数据库连接管理
如何用Mongoose管理生产/开发双数据库连接
作为经常用Node.js+Mongoose做CMS的开发者,我来给你分享一套实用的多数据库连接管理方案,完美适配你这种需要在生产和开发库之间切换操作的场景:
1. 先搞定环境配置区分
首先你需要把两个数据库的连接信息分开,可以用环境变量或者配置文件来管理,避免硬编码:
比如创建一个config/db.js文件:
require('dotenv').config(); module.exports = { development: { uri: process.env.MONGO_DEV_URI || 'mongodb://localhost:27017/cms_dev', options: { useNewUrlParser: true, useUnifiedTopology: true } }, production: { uri: process.env.MONGO_PROD_URI || 'mongodb://localhost:27017/cms_prod', options: { useNewUrlParser: true, useUnifiedTopology: true, // 生产环境可以加连接池配置 poolSize: 10 } } };
这里用dotenv加载环境变量,本地开发和生产服务器分别配置对应的MongoDB URI就行。
2. 封装连接管理模块
不要用Mongoose默认的全局连接,而是用mongoose.createConnection()创建独立的连接实例,这样能同时维护多个数据库连接:
创建db/connections.js:
const mongoose = require('mongoose'); const dbConfig = require('../config/db'); // 缓存连接实例,避免重复创建 const connections = {}; // 获取指定环境的连接 const getConnection = (env = 'development') => { if (connections[env]) { return connections[env]; } const config = dbConfig[env]; if (!config) { throw new Error(`Invalid environment: ${env}`); } const connection = mongoose.createConnection(config.uri, config.options); // 监听连接事件 connection.on('connected', () => { console.log(`Connected to ${env} database`); }); connection.on('error', (err) => { console.error(`${env} database connection error:`, err); }); connections[env] = connection; return connection; }; module.exports = { getConnection };
这个模块会缓存已创建的连接,每次调用getConnection时返回对应的实例,避免重复建立连接。
3. 基于连接实例定义模型
Mongoose的模型是绑定到特定连接的,所以不能用全局的mongoose.model(),要在每个连接实例上定义模型。你可以先定义共享的Schema,再根据不同连接创建模型:
比如创建models/Post.js:
const mongoose = require('mongoose'); // 定义共享的Schema const postSchema = new mongoose.Schema({ title: { type: String, required: true }, content: { type: String, required: true }, createdAt: { type: Date, default: Date.now } }); // 根据传入的连接创建模型 const getPostModel = (connection) => { return connection.model('Post', postSchema); }; module.exports = { getPostModel };
这样不管是生产还是开发连接,都能复用同一个Schema,保证模型结构一致。
4. 在业务逻辑中切换连接
现在你可以在控制器或者服务层里,根据需要(比如接口参数、请求头或者环境变量)选择对应的连接和模型:
比如创建controllers/postController.js:
const { getConnection } = require('../db/connections'); const { getPostModel } = require('../models/Post'); // 创建文章:根据请求中的env参数选择数据库 exports.createPost = async (req, res) => { try { const { env = 'development' } = req.query; // 从URL参数获取环境 const connection = getConnection(env); const Post = getPostModel(connection); const newPost = new Post(req.body); await newPost.save(); res.status(201).json({ success: true, data: newPost }); } catch (err) { res.status(500).json({ success: false, error: err.message }); } }; // 删除文章同理 exports.deletePost = async (req, res) => { try { const { env = 'development' } = req.query; const connection = getConnection(env); const Post = getPostModel(connection); const deletedPost = await Post.findByIdAndDelete(req.params.id); if (!deletedPost) { return res.status(404).json({ success: false, message: 'Post not found' }); } res.json({ success: true, data: deletedPost }); } catch (err) { res.status(500).json({ success: false, error: err.message }); } };
这样用户调用接口时,只需要加?env=production或者?env=development就能切换操作的数据库了。
额外的最佳实践
- 权限控制:生产数据库的操作一定要加权限验证,比如只有特定管理员才能操作生产库,避免误删数据。
- 连接池优化:生产环境配置合适的连接池大小,提升性能。
- 连接状态监控:可以加个接口返回各个数据库的连接状态,方便排查问题。
- 事务支持:如果需要跨文档操作,Mongoose 5.2+支持事务,但要注意只有MongoDB副本集或分片集群才支持。
内容的提问来源于stack exchange,提问作者maysara
相关产品推荐
相关产品推荐

