修改ThinkPHP 5的Query类,添加自己的数据库查询日志,方便记录自己设置时间内的慢日志

TP框架在调试模式下可以看到相关的SQL语句和耗时,在正常情况下记录sql也可以,但是个人感觉不太习惯(怪自己不够熟悉),所以简单修改了一下tp的数据库查询类think\db\Query新增了自定义时间内记录sql的功能,当然文末直接讲开启配置里面的sql_explain分析简单监听即可(推荐)


因为tp的增改删查经过这个文件,在这里操作比较方便,查询和执行是两个独立的方法,分别是query和execute,所以针对这两个查询结果写入日志即可。


当然,利用tp的行为监控更好了,添加一个行为标签tag:listen_log(随便起的名字),在behavior目录的controller下新增Log.php类,写入简单的逻辑

<?php
/** @author 小韦
 * @link http://blog.alipay168.cn
 * @Date: 2021/8/12 20:02
 */

namespace app\behavior\controller;


use app\behavior\behaviorComm;
use app\common\common;

class Log extends behaviorComm
{
    function run($params = [])
    {
        if (!empty($params['call'])) {
            if ($params['call'] == 'db_query' || $params['call'] == 'db_execute') {
                return $this->db_log($params);
            }
        }
        //common::add_log('abb', $params);
    }

    //数据库操作日志——慢查询
    private function db_log($params = [])
    {
        $data = [
            'use_time' => $params['use_time'],
            'sql' => $params['sql'],
            'add_time' => time(),
            'action_type' => ltrim($params['call'], 'db_'),
        ];
        //跳过自己,防止死循环
        if (stripos($params['sql'], 'core_db_log') !== false) {
            return;
        }
        //还是添加到数据库方便后台查询,所以上面要加个判断
        common::data_add('core_db_log', $data);//用简单的方式插入到数据库去
    }


}


然后修改Query.php,大概是240~300行直接的两个方法execute和query

修改前:

/**
     * 执行查询 返回数据集
     * @access public
     * @param string      $sql    sql指令
     * @param array       $bind   参数绑定
     * @param boolean     $master 是否在主服务器读操作
     * @param bool|string $class  指定返回的数据集对象
     * @return mixed
     * @throws BindParamException
     * @throws PDOException
     */
    public function query($sql, $bind = [], $master = false, $class = false)
    {
        return $this->connection->query($sql, $bind, $master, $class);
    }

    /**
     * 执行语句
     * @access public
     * @param string $sql  sql指令
     * @param array  $bind 参数绑定
     * @return int
     * @throws BindParamException
     * @throws PDOException
     */
    public function execute($sql, $bind = [])
    {
        return $this->connection->execute($sql, $bind, $this);
    }


修改后:

/**
 * 执行语句
 * @access public
 * @param string $sql sql指令
 * @param array $bind 参数绑定
 * @return int
 * @throws BindParamException
 * @throws PDOException
 */
public function execute($sql, $bind = [])
{
    $stime = microtime(true);
    $res = $this->connection->execute($sql, $bind, $this);
    $etime = microtime(true);

    //如果时间过长并且行为存在就写入记录
    if ($etime - $stime >= config('database.slow_time') && Hook::get('listen_log')) {
        $p = [
            'call' => 'db_execute',
            'sql' => $this->connection->getRealSql($sql, $bind),
            'use_time' => number_format($etime - $stime, 10),
            'add_time' => time()
        ];
        Hook::listen('listen_log', $p);
    }

    return $res;
}

/**
 * 执行查询 返回数据集
 * @access public
 * @param string $sql sql指令
 * @param array $bind 参数绑定
 * @param boolean $master 是否在主服务器读操作
 * @param bool|string $class 指定返回的数据集对象
 * @return mixed
 * @throws BindParamException
 * @throws PDOException
 */
public function query($sql, $bind = [], $master = false, $class = false)
{
    $stime = microtime(true);
    $res = $this->connection->query($sql, $bind, $master, $class);
    $etime = microtime(true);
    //如果时间过长并且行为存在就写入记录
    if ($etime - $stime >= config('database.slow_time') && Hook::get('listen_log')) {
        $p = [
            'call' => 'db_query',
            'sql' => $this->connection->getRealSql($sql, $bind),
            'use_time' => number_format($etime - $stime, 10),
        ];
        Hook::listen('listen_log', $p);
    }

    return $res;
}




步骤三:给tag写入到config目录tag.php里面

<?php
return array(
    'app_init' =>
        array(),
    'app_begin' =>
        array(
          
        ),
    'module_init' =>
        array(),
    'action_begin' =>
        array(),
    'view_filter' =>
        array(),
    'log_write' =>
        array(),
    'app_end' =>
        array(),
    //这里是新增的,只看这里就行了,系统自动加载进入,后面就listen就行了
    'listen_log'=>[
        'app\\behavior\\controller\\Log'
    ],
)
?>


最后在config目录下面的database.php配置加上自定义的时间:

//慢查询的记录时间
'slow_time'=>'0.01',


改好了之后,可以测试了(数据库自己设计哈):


微信截图_20210813162232.png

图片前面是设置时间为0的,后面是时间0.01测试的。


这样就完成了调整,在后台可以更方便查询日志和进行解释、优化操作了。


最简单的方式是开启database.php里面的sql_explain,这个改成true表示分析数据库,会记录日志哦。


开启语句解释后可以通过自带的监听实现回调(配置自己的监听后是不会自己写入日志的,都进入自己的监听了):

Db::listen(function($sql,$time,$explain){
    // 记录SQL
    echo $sql. ' ['.$time.'s]';
    // 查看性能分析结果
    dump($explain);


    //这里可以根据$time时间进行判断是否数据超时查询
    });


评论/留言