db::listen()在tp5.1中不生效,因该版本未支持全局监听,须通过db::getconnection()->setqueryhook()注册回调函数,参数为($sql, $time, $params),并可用getrealsql()还原真实sql或explain分析执行计划。

在 ThinkPHP 5.1 中,Db::listen() 并不能直接使用——它会静默失败,日志里什么都不会出现。真正有效的做法是调用数据库连接实例的 setQueryHook() 方法,手动注册回调函数,才能捕获 SQL、耗时和绑定参数。
为什么 Db::listen() 在 TP5.1 中不生效
TP5.1 的数据库监听机制尚未支持全局 Db::listen() 注册方式,这是 TP6+ 才引入的特性。如果你在 app/common.php 或中间件里直接写 Db::listen(...),代码不会报错,但也不会触发任何回调。
- 必须通过
Db::getConnection()->setQueryHook(...)获取底层连接后注册 - 回调函数签名严格为
function($sql, $time, $params),三个参数缺一不可 -
$sql是带?占位符的原始语句,$params是实际绑定值,两者需同时记录才能还原真实执行条件
如何正确注册慢查询监听
推荐在 app/common.php(应用初始化阶段)或数据库连接建立后立即注册:
- 示例代码:
Db::getConnection()->setQueryHook(function ($sql, $time, $params) { if ($time > 500) { // 自定义阈值,单位:毫秒 \think\Log::record("SLOW SQL: {$sql} | Time: {$time}ms | Params: " . json_encode($params), 'sql'); } }); -
$time是 PDO 执行耗时(毫秒),不含网络延迟、锁等待等真实 DB 层开销 - 日志写入位置默认为
runtime/log/下对应日期的文件,可配合 Log 配置统一管理
如何还原真实 SQL 语句
ThinkPHP 不会自动拼接 $params 到 $sql 中,需手动替换占位符。简单安全的还原方式(适用于调试):
- 逐个用
str_replace('?', var_export($val, true), $sql, 1)替换,注意只替换一次,避免误替字符串内的问号 - 更稳妥的做法是使用
think\db\Connection::getRealSql($sql, $params)(TP5.1 支持) - 例如:
$realSql = Db::getConnection()->getRealSql($sql, $params);
配合 EXPLAIN 分析执行计划
仅看耗时不够,还需知道数据库怎么执行这条 SQL。可在监听回调中追加 EXPLAIN 查询:
- 对 SELECT 语句,在记录慢查的同时执行:
Db::query("EXPLAIN " . $sql, $params) - 结果返回数组,重点关注
type(访问类型)、key(是否用索引)、rows(扫描行数)、Extra(额外信息如 Using filesort) - 注意:EXPLAIN 不会真正执行原 SQL,开销极小,适合开发/测试环境开启
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











