绝大多数场景下不需要自己写连接池;Workerman 的常驻进程通过 onWorkerStart 初始化并复用单连接,已实现轻量高效的“伪连接池”,配合惰性重连和合理配置即可稳定运行。

Workerman里用不用自己写连接池?
绝大多数场景下,不需要。Workerman 的 Worker 进程是常驻的,每个进程在 onWorkerStart 里初始化一个数据库连接并复用,就已经实现了“伪连接池”效果——既避免了每次请求新建连接的开销,又绕开了 PHP 进程间共享连接的难题。
自己硬套一个中心化连接池(比如起 Task 进程做代理),反而会引入 IPC 开销、序列化/反序列化延迟、错误传播路径变长等问题。除非你有上千台应用服务器且数据库连接数已逼近上限,否则这个“池”纯属画蛇添足。
- 单机 50 个 Worker 进程 → 最多 50 个 MySQL 连接,对现代 MySQL 来说完全无压力
- 连接断开时,用惰性重连比维护池更轻量:捕获
MySQL server has gone away或Connection refused后,在 query 失败回调里重建Connection实例即可 - Workerman 自带的
Workerman\MySQL\Connection不支持预处理绑定,参数必须以数组传给query(),别写bindParam
Workerman\MySQL\Connection 怎么配才不掉链子?
这是 Workerman 官方推荐的异步 MySQL 客户端,不是 PDO 封装,底层走的是纯异步 I/O,所以配置项直接影响稳定性。
-
read_timeout和write_timeout建议设为 3~5 秒,太短容易误判超时,太长会拖垮整个 EventLoop -
charset必须显式设为utf8mb4,否则 emoji 或四字节字符入库会截断或报错 - 连接池大小(
pool_size)默认是 10,但注意:它只在使用Workerman\MySQL\Pool时生效;而直接 newConnection是单连接,pool_size不起作用 - 事务必须在同一个
Connection实例上调用begin()、commit()或rollback(),跨实例或跨回调会导致事务丢失
为什么不能在协程里混用 PDO 或 mysqli?
Workerman 默认运行在同步阻塞模型上,即使你启用了 Swoole 或 Fiber 驱动,只要用了 PDO 或 mysqli 这类同步扩展,整个协程就会被卡住——因为它们底层调用的是阻塞 socket API。
表现就是:一个慢查询会让同 Worker 内所有其他请求等在那儿,CPU 占用低但响应时间飙升,日志里看不到明显报错,只有超时堆积。
- 确认驱动类型:
var_dump(Workerman\Events\EventLoop::class),如果是Swoole或Fiber,必须搭配Workerman\MySQL\Connection或原生 Swoole MySQL 客户端 - 别信“PDO + setAttribute(PDO::ATTR_TIMEOUT, 1)”这种伪异步,它只是控制 PHP 层等待,底层仍是阻塞 connect
- 如果业务强依赖 PDO 功能(如命名参数),只能退回到传统 FPM 架构,或者改用 Swoole 的
Swoole\Coroutine\MySQL
连接复用时最容易忽略的三个点
不是连接建起来就万事大吉。Worker 进程生命周期长,环境变量、全局状态、连接自身都可能悄悄变化。
- 不要把
$GLOBALS['db']当成线程安全容器:多个回调并发调用同一个Connection实例的query()是允许的,但不能同时对同一实例调用begin()和query(),会乱序 - 定时心跳检测别写在
onWorkerStart里一次性执行,得用Timer::add()每 30 秒跑一次SELECT 1,否则断连后永远不恢复 - 连接对象不能序列化,别试图存进 Redis 或写入日志 ——
var_export($conn)会直接 fatal error,调试时只打get_class($conn)和连接状态标志位
onWorkerStart 里的连接初始化写稳,再加一层简单的重试逻辑,比折腾连接池靠谱得多。

















