用 dotenv 按环境加载 .env.{NODEENV} 配置,服务端读取 process.env.DB* 初始化数据库连接池,连接池参数按环境调优,健康检查须执行 SELECT 1 验证真实连通性。
用 dotenv + 环境变量区分数据库配置
不同测试环境(dev/staging/uat)连的数据库地址、账号、库名全不一样,硬编码或手动改配置极易出错。统一入口的关键不是“写一个万能连接函数”,而是让连接参数本身可变且隔离。
实际做法是:每个环境一份 .env 文件,用 dotenv 加载,再由数据库初始化逻辑读取环境变量。比如:
DB_HOST=localhost DB_PORT=5432 DB_NAME=myapp_dev DB_USER=dev_user DB_PASSWORD=dev_pass
启动时加载对应文件:require('dotenv').config({ path: `.env.${process.env.NODE_ENV}` });,然后 pg 或 knex 直接读 process.env.DB_HOST 等变量。
- 别把
.env提交到 Git —— 用.gitignore拦住,只留.env.example -
NODE_ENV必须在启动前设好,比如NODE_ENV=staging node app.js,否则dotenv找不到对应文件 - 某些 ORM(如 TypeORM)会自动读
.env,但默认只读根目录下的,不认带后缀的 —— 得显式传dotenv路径
避免 process.env 在构建时被静态替换
前端项目打包(如 Vite/Next.js)常把 process.env 当常量替换成字符串,导致环境变量在运行时失效 —— 这会让「一套代码跑多环境」变成「一套代码只跑一个环境」。
关键点在于:数据库连接逻辑必须在服务端执行,不能塞进前端 bundle。哪怕你用的是 SSR 框架,也要确认 DB_* 变量没被暴露到客户端。
- Vite 中用
import.meta.env.VITE_*的变量会被注入前端,process.env.DB_*默认不会 —— 但如果你写了define: { 'process.env.DB_HOST': JSON.stringify(process.env.DB_HOST) },就等于亲手泄露 - Next.js 的
getServerSideProps或 API Route 里读process.env是安全的;useEffect里读就是错的 - Node.js 启动脚本里不要用
cross-env混淆变量名,比如CROSS_ENV_DB_HOST—— 容易漏配、难 debug
连接池配置要按环境缩放,不能共用一套 max
开发环境开 10 个连接池,UAT 环境也照搬,轻则浪费资源,重则触发数据库连接数上限报错 FATAL: remaining connection slots are reserved for non-replication superuser connections。
连接池大小不是越大多好,得看并发量和数据库规格。本地开发一般 max: 2–5 足够,Staging 可设 max: 10,生产环境再根据压测调。
- PostgreSQL 默认
max_connections = 100,如果每个服务实例都设max: 20,4 个实例就占满 —— 别忘了还有后台任务、管理连接 - 像
pg的idleTimeoutMillis和connectionTimeoutMillis也要调低:开发环境网络稳定,可以设 30s;UAT 网络抖动多,得缩到 5s 避免卡死 - 别在连接池创建后还动态改
pool.options.max—— 多数驱动不支持运行时重配,改了也不生效
健康检查接口必须验证真实数据库连通性
很多团队的 /health 接口只返回 {"status": "ok"},或者只 ping 通数据库主机就认为 OK —— 这掩盖了权限不足、库不存在、SSL 配置错误等真实问题。
真正的健康检查得执行一条最小代价 SQL,比如 SELECT 1,并捕获具体错误类型。
- PostgreSQL 权限错误报
error: permission denied for database "xxx",MySQL 报Access denied for user 'xxx'@'yyy'—— 这些比超时更早暴露配置问题 - 别在
/health里查业务表(如SELECT COUNT(*) FROM users),加锁或慢查询会影响诊断本身 - 如果用了连接池,健康检查应从池里取连接,而不是新建临时连接 —— 否则测的不是实际路径
环境越多,配置项越容易漏掉一个字段、少设一个超时、误传一个空格。统一入口不是靠一个抽象层兜底,而是靠每个环节都守住自己的边界:变量加载时机、构建阶段剥离、连接池粒度、健康检查深度 —— 少一个,集成就松一扣。











