1. Node.js 里 connect 被调用多次到底是谁在偷偷重连如果你在 Node.js 项目里看到控制台反复打印「数据库连接成功」或者日志里connect被调用了好几次甚至报出connection.model() should not be run with new这类异常那基本可以确定你的连接对象被重复创建了。这个问题在同时连接多个数据库、或者用mongoose.createConnection()管理多库时特别常见。核心原因有两个方向。第一是模块加载层面Node.js 的require有缓存机制但如果你在多个文件里各自require了一个「导出连接实例」的模块而那个模块本身在顶层就执行了createConnection那么每次被不同路径引用时可能触发多次初始化。第二是连接池与生命周期层面mongoose.connect()是全局单例连接只能连一个库要连多个库必须用createConnection()但很多人把createConnection写在了路由处理函数或定时任务里请求一来就新建一个连接连接数暴涨connect自然被反复调用。这篇内容适合正在用 Node.js Mongoose 或原生驱动连数据库、遇到重复连接报错、想统一管理 API 通道和 Key 的开发者。我会从复现步骤开始带你定位根因然后给出可复制的配置骨架最后用 TaoToken 把模型调用和数据库配置的 Key 通道统一收口避免散落在各个文件里。实测下来把连接创建收敛到单一入口再配合统一配置重复 connect 的问题基本一次解决。2. 先复现createConnection 被重复触发的典型写法要排查问题先得能稳定复现。下面这段代码是很多人踩过的坑把连接创建写在一个「工具模块」里然后在多个业务文件里引用。// db.js —— 问题写法 const mongoose require(mongoose); const db mongoose.createConnection(mongodb://localhost/electricity_user_database); db.on(error, console.error.bind(console, connect error)); db.once(open, function () { console.log(数据库连接成功); }); module.exports db;然后在userService.js和orderService.js里都require(./db)。表面上看require有缓存db.js只会执行一次。但如果你在项目里用了动态require、或者打包工具把模块拆成了不同 chunk、又或者你在测试环境里反复delete require.cache那createConnection就会被执行多次connect被调用多次。更隐蔽的一种情况你在app.js里连了一个库又在某个中间件里用createConnection连了第二个库两个连接对象都注册了open事件日志就重复了。复现命令很简单先装依赖npm init -y npm install mongoose然后建两个文件分别引用同一个db.js启动后观察控制台。如果看到两次「数据库连接成功」说明复现成功。注意mongoose.connect()是全局连接只能连一个数据库。要连多个库必须用createConnection()并且每个库对应一个独立的连接实例。这是官方设计不是 bug。3. 用 TaoToken 统一配置通道Key 和 API 收口在解决连接重复问题之前先把配置管理理顺。很多项目里数据库地址、模型 API Key、第三方服务地址散落在.env、config.js、甚至硬编码在业务文件里改一个地方要翻半天。我习惯用 TaoToken 作为统一的 API 通道入口把模型调用和配置读取收口到一处。TaoToken 的官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。你可以在控制台创建 Key然后通过统一的 base URL 调用模型对话、Coding Plan 等能力。对于 Node.js 项目来说这意味着你不需要在代码里维护多个厂商的 endpoint只需要一个 Key 和一个 base URL。具体操作先到控制台生成 API Key地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 。生成后把 Key 写进环境变量不要提交到 Git。# .env TAOTOKEN_API_KEYsk-你的key TAOTOKEN_BASE_URLhttps://taotoken.net/api DB_URImongodb://localhost/electricity_user_database然后在项目里用一个config.js统一读取// config.js require(dotenv).config(); module.exports { taotoken: { apiKey: process.env.TAOTOKEN_API_KEY, baseUrl: process.env.TAOTOKEN_BASE_URL, }, db: { uri: process.env.DB_URI, }, };这样做的价值在于数据库连接配置和模型 API 配置走同一套读取逻辑后续要换环境、换 Key只改.env一个地方。如果你需要查看接入文档可以访问 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有完整的参数说明。4. 可复制的 settings.json / config.toml 骨架与连接修复接下来是重点把连接创建收敛到单一入口并用配置文件管理。先给一个settings.json骨架适合放在项目根目录供 Node.js 读取{ database: { connections: [ { name: electricity_user, uri: mongodb://localhost/electricity_user_database, options: { maxPoolSize: 10, serverSelectionTimeoutMS: 5000 } }, { name: electricity_order, uri: mongodb://localhost/electricity_order_database, options: { maxPoolSize: 10, serverSelectionTimeoutMS: 5000 } } ] }, taotoken: { baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY } }如果你更习惯 TOML可以用config.toml[taotoken] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY [[database.connections]] name electricity_user uri mongodb://localhost/electricity_user_database max_pool_size 10 [[database.connections]] name electricity_order uri mongodb://localhost/electricity_order_database max_pool_size 10然后写一个连接管理器保证每个库只创建一次连接// connectionManager.js const mongoose require(mongoose); const settings require(./settings.json); const connections new Map(); function getConnection(name) { if (connections.has(name)) { return connections.get(name); } const config settings.database.connections.find((c) c.name name); if (!config) { throw new Error(未找到数据库配置: ${name}); } const conn mongoose.createConnection(config.uri, config.options); conn.on(error, (err) console.error([${name}] connect error, err)); conn.once(open, () console.log([${name}] 数据库连接成功)); connections.set(name, conn); return conn; } module.exports { getConnection };关键点用Map做缓存同一个 name 第二次调用直接返回已有连接不会重复createConnection。业务代码里这样用const { getConnection } require(./connectionManager); const userDb getConnection(electricity_user); const userSchema new mongoose.Schema({ name: String }); const UserModel userDb.model(User, userSchema); // 注意用 db.model不是 new mongoose.model module.exports { UserModel };这里就解决了 excerpt 里提到的connection.model() should not be run with new问题用createConnection得到的连接实例创建模型时必须用db.model()不能用new mongoose.model()。5. 验证请求与成功结果日志确认只连一次配置改完后要验证connect只被调用一次。写一个测试脚本模拟多次调用getConnection// verify.js const { getConnection } require(./connectionManager); const a getConnection(electricity_user); const b getConnection(electricity_user); const c getConnection(electricity_order); console.log(同一连接是否复用:, a b); console.log(不同库是否独立:, a ! c); setTimeout(() { console.log(验证结束); process.exit(0); }, 3000);运行node verify.js预期输出[electricity_user] 数据库连接成功 [electricity_order] 数据库连接成功 同一连接是否复用: true 不同库是否独立: true 验证结束如果你看到「数据库连接成功」只打印了两次对应两个库而不是四次或更多说明连接复用生效了。如果还是重复打印检查是不是在别的文件里又直接调用了mongoose.createConnection。再验证一下 TaoToken 通道是否可用。用 Node.js 发一个模型对话请求// testTaotoken.js const config require(./config); async function main() { const res await fetch(${config.taotoken.baseUrl}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${config.taotoken.apiKey}, }, body: JSON.stringify({ model: claude-3-5-sonnet, messages: [{ role: user, content: 回复 ok 即可 }], }), }); const data await res.json(); console.log(TaoToken 响应:, JSON.stringify(data).slice(0, 200)); } main();运行后如果能看到正常返回说明 Key 和 base URL 配置正确。你也可以直接在模型对话页面测试地址是 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 不用写代码就能验证通道。6. 本篇常见错排查connect 多次调用的五个坑第一个坑在路由处理函数里调用createConnection。每个请求进来都新建连接连接池很快耗尽。修复方式就是上面的getConnection缓存。第二个坑require路径大小写不一致。在 macOS 上不敏感到了 Linux 服务器上会当成两个不同模块导致db.js被执行两次。检查所有require(./db)和require(./DB)是否统一。第三个坑测试框架里delete require.cache。Jest 的resetModules或者手动清缓存会让模块重新执行连接也跟着重建。测试环境建议用beforeAll只初始化一次。第四个坑mongoose.connect()和createConnection()混用。全局连接和独立连接同时存在事件监听重复注册。统一用createConnection管理多库或者全局只用一个connect。第五个坑db.model()和new mongoose.model()混用。前者用于独立连接后者用于全局连接。用错了就报should not be run with new。记住createConnection返回的实例创建模型用db.model()。如果你在排查过程中需要生成更多测试用例或者让模型帮你分析日志可以用 Coding Plan 长期跑编码任务入口是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。需要管理多个 Key 时到 API Keys 页面操作https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。最后说一个我踩过的坑连接管理器里的Map缓存在热更新nodemon时不会自动清空旧连接还挂着。开发环境可以在SIGUSR2信号里手动关闭所有连接或者干脆接受 nodemon 重启进程。生产环境用 PM2 的话进程重启会自然清理不用额外处理。把连接创建收敛到connectionManager.js一个文件配合settings.json和 TaoToken 统一 Key 通道重复 connect 的问题就不会再出现了。
企业数字化 ERP 产品动态
相关推荐
Open Source Copilot 替代方案:本地或开源 AI 编程工具该在什么场景下用 TaoToken /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 14:11:52
南阳专业做网站公司哪家好?从零搭建避开这5个安全坑 南阳专业做网站公司哪家好?从零搭建避开这5个安全坑 自己不会代码想做网站,这是很多南阳本地企业主和创业者面临的真实困境。你心里想着找个靠谱的公司,搜“南阳专业做网站公司哪家好”,结果发现报价从两千到两万都有,心里直打鼓:到底哪家能帮我从零搭… · 2026/9/27 14:11:39
拆解DSBA1P与R7KA8T2LFLCAC:装配方向与公差防错实战指南 1. 这套编号到底是什么:从车间里的"对不上"说起两年前我在产线上跟一批装配不良,标签上写着"A向插接NG,检出率3.7%"。当时所有人第一反应是换料、换治具,折腾了一整天,最后发现根本不是物料问题&a… · 2026/9/27 14:11:39
网站哪家做的比较好的?3个维度避开高价坑,选对不踩雷 网站哪家做的比较好的?3个维度避开高价坑,选对不踩雷 找建站公司最怕什么?不是功能少,而是花了大价钱,做出来的网站既丑又慢,还容易被搜索引擎屏蔽。很多老板在问 网站哪家做的比较好的… · 2026/9/27 15:05:20
太仓网站优化实操:0代码基础也能看懂的保姆级建站教程 太仓网站优化实操:0代码基础也能看懂的保姆级建站教程 很多刚入行或者想自己搞个官网的朋友,第一反应往往是“我不会写代码,这网站怎么建?”这种焦虑在太仓这片制造业扎堆的地方特别常见。我也见过不少老板,花大价钱做了个站,结果百度搜不到,谷歌也排… · 2026/9/27 15:05:01
ElasticMM 多模态 LLM 服务实战:用 TaoToken 统一 Key 打通 EMP 弹性并行配置 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 15:04:55
AI工具狂飙时代:三款实用AI产品横向测评,TaoToken统一Key接入实测 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 15:04:06
地产平面网站多少钱?别被拖慢需求坑了,3个实操方案省一半 地产平面网站多少钱?别被拖慢需求坑了,3个实操方案省一半 改个按钮颜色,建站公司让你排期一周? 问一句“上线要多久”,对方回你“还得看排期”? 这时候再问“地产平面网站多少钱”,心里全是问号,毕竟钱花了,效率却卡在半空。… · 2026/9/27 15:04:06
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01