应使用 db::getpdo() 获取 pdo 实例后执行 select 1 探活,配合 try/catch 捕获异常判断连接状态;该机制适用于 swoole 等常驻进程场景,在 workerstart 中通过 tick 定时上报,需监控连接存活时长与重连次数等多维指标。

如何用 Db::getPdo() 检查连接是否还活着
ThinkPHP 的数据库连接对象本身不提供 ping() 方法,直接调用 $connection->ping() 会报错。真实可用的方式是拿到底层 PDO 实例后手动执行简单查询——不是靠异常兜底,而是主动探测。
常见错误现象:SQLSTATE[HY000] [2006] MySQL server has gone away 在定时任务里突然冒出,但上一秒查库还正常。这是因为连接空闲超时被 MySQL 主动断开,而 TP 默认不自动重连。
- 必须用
Db::getPdo()获取原生 PDO 对象,不能依赖Db::connect()返回的连接实例 - 执行
SELECT 1最轻量,比PING更兼容(PDO 不支持原生 ping 命令) - 加
try/catch捕获PDOException,仅凭返回值无法判断失败(查询成功但结果为空也正常)
try {
$pdo = Db::getPdo();
$pdo->query('SELECT 1');
return true;
} catch (\PDOException $e) {
return false;
}
定时上报该放在哪里:别塞进 command 生命周期钩子
TP 的命令行命令(php think xxx)每次执行都是新进程,连接状态只反映“那一瞬间”,对服务长期运行无意义。健康上报真正要盯的是常驻进程里的连接池状态,比如 Swoole Worker 或 Hyperf Server。
使用场景很明确:你用了 swoole_http_server 或 think-swoole,Worker 启动后复用数据库连接,这时才需要每 30 秒检查一次连接是否失效并上报。
- 上报逻辑应注册在 Worker 进程启动后(如
Swoole\Server::on('WorkerStart')) - 用
tick定时器,不要用sleep()阻塞协程 - 上报目标如果是 Prometheus,注意指标名需带
_total或_gauge后缀,否则采集端不识别
db.ping_interval 配置没生效?那是你没配对地方
TP 官方文档提过 db.ping_interval,但它只在 think-swoole 的连接池管理中起作用,且仅控制“连接取出前是否 ping”。它不会触发外部上报,也不影响传统 FPM 场景。
参数差异明显:db.ping_interval=30 表示每 30 秒对池中每个空闲连接做一次 SELECT 1;而你自己写的上报逻辑,可能每 5 秒就扫一次全部连接,两者叠加反而增加 DB 压力。
- FPM 下该配置完全无效——每次请求都是全新连接,无需 ping
- Swoole 下若开启连接池,此配置默认为
0(即不 ping),必须显式设为正整数才启用 - 若同时自己实现 ping + 开启该配置,会出现重复探测,建议关掉配置,统一走自定义上报逻辑
上报指标里最易被忽略的字段:连接生命周期时长
只报“是否连通”远远不够。一个连接刚建立就报 OK,3 小时后还报 OK,但中间经历过 12 次重连——这种“虚假健康”会让监控失去意义。
真正有用的指标至少包含三个维度:db_connection_up{pool="default"}(当前是否可用)、db_connection_age_seconds{pool="default"}(当前连接存活秒数)、db_connection_reconnect_total{pool="default"}(累计重连次数)。
获取连接创建时间得从 TP 源码里挖:Db::getConnect()->getOptions()['created_time'] 是整型时间戳,差值就是 age。别试图用 microtime(true) 减去连接对象构造时间——TP 会复用连接对象,那个时间点早就失真了。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











