闭包实现的“单例连接池”在多 Worker 环境下无法跨进程共享连接,仅实现进程级单例,5个Worker即产生5个独立连接;应改用onWorkerStart初始化连接+惰性重连方案。

闭包实现的“单例连接池”在多 Worker 环境下**无法真正复用数据库连接**——它只能保证每个 Worker 进程内部连接唯一,但不同 Worker 之间仍是彼此隔离、互不共享的多个连接。这不是传统意义的连接池,而是“进程级单例连接”,需先厘清概念再谈落地。
为什么闭包单例不能跨 Worker 共享连接
Workerman 启动后会 fork 出多个独立 Worker 进程,每个进程拥有自己的内存空间和执行上下文。闭包所封装的 instance 变量仅存在于当前进程内,即使所有 Worker 都运行同一段闭包代码,它们各自持有的 instance 也是完全不同的对象,指向不同的数据库连接资源。
这意味着:
- 5 个 Worker 进程 → 至少 5 个独立数据库连接(哪怕都用了同一个闭包单例)
- 连接不会被“池化”或动态分配,只是静态绑定到进程生命周期
- 无法统一控制最大连接数、空闲超时、连接回收等池化行为
如何正确设计 Worker 环境下的连接管理
推荐采用 Workerman 原生适配的方式:每个 Worker 在 onWorkerStart 中初始化一个连接,并复用至进程结束。这是最轻量、最稳定、也最符合其架构的设计。
- 在
onWorkerStart回调中创建连接,存入全局变量(如$GLOBALS['db']或静态属性) - 请求处理时直接使用该连接,避免每次 new 或 connect
- 配合惰性重连:SQL 执行失败时检查错误码(如 MySQL 的 2006、2013),确认断连后重建连接并重试一次
- 可选加心跳:Worker 内定时(如每 30 秒)执行
SELECT 1,异常则主动重连
什么时候才需要真正的中心化连接池
只有当出现以下情况时,才值得引入外部连接池(如 PDO + DBUtils、ProxySQL、or 自建 TCP 池服务):
- 数据库服务器设置了严格的
max_connections,而 Worker 数量远超该限制 - 多个 PHP 应用(不止 Workerman)需共享同一组数据库连接
- 需要细粒度连接治理:按用户/租户限流、慢查询熔断、连接自动伸缩等
否则,进程内单连接 + 惰性恢复已足够健壮高效。
闭包单例仍可作为连接封装工具(非池)
你可以用闭包封装连接创建逻辑,让每个 Worker “干净地”获取自己的连接实例,例如:
const DbConnection = (function () {
let instance = null;
return {
getInstance() {
if (!instance) {
// 此处实际调用 mysqli/pdo connect,只在本 Worker 内执行一次
instance = new PDO($dsn, $user, $pass);
}
return instance;
}
};
})();
这本质是“延迟初始化的进程单例”,不是连接池,但能避免重复 connect,且结构清晰、易于测试。










