不能直接用,需手动集成——workerman常驻内存,而thinkorm/eloquent依赖php-fpm请求生命周期,需在onworkerstart中按进程独立初始化、开启break_reconnect、避免静态调用和单例复用。

Workerman 能不能直接用 ThinkORM 或 Eloquent?
不能直接用,但可以「手动集成」——因为 Workerman 是常驻内存的长连接服务,不走传统 PHP-FPM 的请求生命周期,而 ThinkORM 和 Eloquent 默认依赖 $_SERVER、$_GET 等超全局变量,且会自动初始化连接池、事务上下文、请求作用域等,一上来就报错或连接泄漏。
为什么 ORM 初始化后查一次就卡住或连不上数据库?
常见错误现象:PDOException: SQLSTATE[HY000] [2002] Connection refused 或查完第一笔数据后后续查询全超时。根本原因是:Workerman 启动时只初始化一次 ORM,但没重置连接状态;MySQL 连接空闲超时(默认 8 小时)后,ORM 不会自动重连,下次查询就 hang 住。
- ThinkORM 默认开启连接池,但 Workerman 的多进程模型下,每个子进程需独立维护自己的连接池实例,不能共享
- Eloquent 的
DB::connection()在 CLI 模式下不会自动 reconnect,需显式调用reconnect()或捕获异常后重试 - 务必禁用 ORM 的「请求结束自动关闭连接」逻辑(如 ThinkORM 的
app('db')->close()钩子),否则每次请求后把连接关了,下次还得重建,性能崩盘
怎么安全地在 Worker 进程里用 ThinkORM?
核心原则:每个 Worker 进程启动时单独初始化 ORM 实例,不复用,不跨进程共享单例;连接必须带重连机制。
- 在
Worker::onWorkerStart回调里初始化 ThinkORM,例如:Worker::onWorkerStart = function (Worker $worker) { \think\facade\Db::connect([ 'type' => 'mysql', 'hostname' => '127.0.0.1', 'database' => 'test', 'username' => 'root', 'password' => '', 'hostport' => 3306, 'params' => [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION], 'break_reconnect' => true, // 必开!断线自动重连 ]); }; - 避免使用
Db::table()->where(...)->find()这类静态调用,改用$db = \think\facade\Db::connect(); $db->table(...)->find(),确保操作的是当前进程的连接实例 - 不要在
onMessage中反复 new Db 或 connect,连接复用即可;但记得 catchPDOException并 log,防止某次查询失败导致整个连接不可用
Eloquent 在 Workerman 里怎么避免连接泄漏?
典型症状:跑几小时后 MySQL 报 Too many connections。Eloquent 默认不释放连接,尤其用了 DB::transaction() 但没 commit/rollback 就 return,连接就卡死在那。
- 必须在每个业务逻辑出口(包括异常分支)显式处理连接:
try { DB::transaction(function () { // ... }); } finally { DB::disconnect(); // 不要总 disconnect,只在确定不再用时才调;更稳妥是用 try/catch + reconnect } - 推荐改用无状态方式:每次查询前用
$conn = DB::connection(); $conn->reconnect();,查完不 close,靠break_reconnect和连接空闲超时由 MySQL 自动断开 - 别用 Laravel 的 Service Container 自动注入
DB或模型,Workerman 没有 request 生命周期,容器里的单例会跨请求污染
最麻烦的不是连上,而是连上之后的连接状态管理——ORM 默认假设“一次请求一个连接、用完即弃”,而 Workerman 要求“一个连接长期存活、随时可重用”。漏掉 break_reconnect、误用静态门面、在 onMessage 里反复初始化,这三个点踩中任意一个,服务跑两天准出问题。










