laravel框架输出执行的sql语句的几种方式

一、使用laravel框架自带的相关方法

用laravel框架中的DB类 自带的getQueryLog方法直接打印:

\Illuminate\Support\Facades\DB::connection()->enableQueryLog(); //开启执行日志,加在需要打印的SQL语句之前

$row = Supplier::query()->where('id', 18)->first();

echo "<pre>";
print_r(\Illuminate\Support\Facades\DB::getQueryLog()); //获取查询语句、参数和执行时间

exit;


打印结果类似如下:

Array
(
    [0] => Array
        (
            [query] => select * from `supplier` where `id` = ? limit 1
            [bindings] => Array
                (
                    [0] => 18  
                )

            [time] => 3  //注意 这里的单位是毫秒
        )

)

备注:貌似该方法是从laravel5加入的,我在 laravel 8.17.2 和 laravel 8.50.0 版本中用过,是可以的,至于laravel5、laravel6、laravel7、及后续的laravel更高的版本。。就自行去测试吧哈~

二、使用 Laravel Debugbar 调试器

调试神器 barryvdh/laravel-debugbar 这个扩展组件包,功能非常强大,不仅可以完整输出执行的sql语句(包括查询语句、sql语句的绑定参数、sql执行耗时的时间等),还能显示当前请求的路由信息、当前所加载的视图、显示所有事件、laravel版本及环境、显示 PHP include/require 的文件、显示配置文件的配置值、所有的log信息、使用的内存信息、等等等等。。。该扩展组件包 可以调试带web页面的(即:常见的web页面开发),也可以调试单纯的json api接口(但是,需要做一些额外的改动或配置。。感觉有些麻烦,不是很方便)

but!!warning!!!该扩展组件包非常消耗性能,建议只在开发环境中安装,线上生产环境请不要安装~~

2.1:安装(本文中该扩展组件包的版本号为:3.6.2)

laravel8.x版本的安装方式如下(因为我只在 laravel 8.17.2 和 laravel 8.50.0 版本中安装过):

composer require barryvdh/laravel-debugbar --dev #仅开发环境安装
composer require barryvdh/laravel-debugbar  

#备注:为什么要加上 --dev 参数?
    如果没有加上 --dev,这会使Laravel debugbar被装在composer.json的require字段,而非require-dev字段,这会造成在正式线上的生产环境也会安装Laravel debugbar,这是不需要的。

浏览器刷新页面,即可看到底部的调试工具


然后运行如下的Artisan 命令将该扩展包的配置文件拷贝到 config 目录下(config/debugbar.php):

php artisan vendor:publish --provider="Barryvdh\Debugbar\ServiceProvider"

最终的效果图如下(这里我们 只看执行的sql语句):

QQ截图20210811180650.png

如果想要关闭调试工具,可以设置 config/debugbar.php文件里面的 enabled 字段的值为 false 即可关闭


同时,也可以在相关代码文件中 临时进行开启或关闭

DebugBar::disable();  //启用
DebugBar::enable();  //关闭


特别提示:对于没有页面的纯api接口的调试。单独定义一个路由渲染一个给debugbar注入调试信息的view页面。然后你从任意地方(postman、app、前端项目)请求接口,点开右下角的调试按钮,通过筛选项过滤出你要查看的api请求就行。


可以添加一个单独的路由文件:

<?php

//debugbar 调试工具页面

$router->get('debugbar', function () {
 
    if (env('APP_ENV') != 'production' && env('APP_DEBUG') === true) {
        return view('debug_tool.debugbar');
    }
    abort(404);
});

2.2、laravel5.x版本安装的相关设置

composer安装完成后,在 config/app.php文件中的 providers 数组里面进行 注册服务提供者。


注册如下服务提供者:

Barryvdh\Debugbar\ServiceProvider::class,


该扩展组件包的GitHub 地址:https://github.com/barryvdh/laravel-debugbar

该扩展组件包的packagist地址: https://packagist.org/packages/barryvdh/laravel-debugbar


关于该扩展组件包的安装及使用 也可以参考:https://www.cnblogs.com/guohong-hu/p/12548287.html

三、使用Laravel Telescope调试工具

相关软件版本信息如下:

Laravel版本:Laravel Framework 8.55.0

telescope版本:v4.10.2


Laravel Telescope 是Laravel官方 开发的一个专门为 Laravel 框架 打造的优雅的debug调试助手。Telescope可以为进入应用的请求、异常、日志、数据库查询、队列任务、邮件、通知、缓存操作、调度任务、变量打印等所有操作提供洞察明细功能,因此,它将成为你本地 Laravel 开发环境的又一绝佳伴侣。


Telescope 是由一系列监听器组成,这些 “监听器” 监听每个进入应用的请求,不管是来自 HTTP 、命令行、任务调度还是队列的。还是其它方式等等等等......

这些监听器可以捕获这些请求以及其相关数据信息   -- 例如数据库查询以及其执行时间,是否命中缓存,事件触发、邮件触发等等等等......


Telescope既可以调试web页面开发,也可以调试纯api接口开发,(和上面的laravel debugbar调试api接口不一样的是,laravel debugbar工具调试api接口的话 在安装部署好了后 需要单独设置一些相关东西 才可以调试api接口,而Telescope在部署好后 直接就能调试api接口 不需要在进行一些额外的单独设置


上面说的 Laravel Debugbar 与 Telescope 进行对比的话 就是纯 UI界面(Laravel Debugbar) 和 重量级武器(Telescope)。所以Telescope最好也只在开发环境下进行安装部署,不要在线上生产环境进行安装部署,因为Telescope工具比较重,非常消耗性能,所以 最好不要在线上生产环境进行部署Telescope


安装完 Telescope 后,你可以访问 /telescope 来访问该应用

注意:Telescope 要求 Laravel 5.7.7+ 版本。可以通过 php artisan --version 查看自己的 Laravel 版本。建议至少在Laravel 5.8的环境中进行安装,本文是在Laravel 8.50.0 版本中进行部署的

3.1、Telescope工具的安装

。。。。。。怎么安装就先不说了。。。下面我会提供相关文章地址。。

3.2、调试页面效果(这里我们依然 只看执行的sql语句

我用postman工具使用get方式 请求了www.domain.com/test地址,然后Telescope工具会监听到我们本次用postman发出的请求,并记录相关数据(比如:请求的地址、请求携带的参数、服务端所执行的具体sql语句等等等等......)


然后我们访问www.you-laravel-domain.com/telescope(具体域名根据实际情况换成你自己的,/telescope 是固定的访问格式)来查看Telescope工具为我们监听并记录本次请求的相关信息,效果图如下:

123.png


456.png

3.3、Telescope工具一些简单设置(比如 过滤掉 OPTIONS 请求)

telescope扩展组件安装完成后 通常会在 app/Providers/ 目录下生成一个 TelescopeServiceProvider.php 文件,这个文件就可以用代码设置一些Telescope工具的规则。另外 通常也会在 config目录下生成一个 telescope.php 文件 这个文件里面也可以配置一些规则 可以让telescope工具不记录指定规则的相关数据。


现在前后端分离模式开发很常见,因为跨域问题,所以请求相关后端api接口会引出OPTIONS请求  因为这种请求实际上对后端来说没啥作用,所以。。让telescope工具过滤掉OPTIONS请求(让telescope工具 不记录OPTIONS的请求相关信息),我们可以在 app/Providers/TelescopeServiceProvider.php 文件里面的 register()方法里面 使用filter闭包函数来过滤,过滤掉OPTIONS请求的核心代码如下:

Telescope::filter(function(IncomingEntry $entry){
    
    if(request()->getMethod() == 'OPTIONS')
    {
        return  false;
    }
});


完整代码如下:

/**
 * Register any application services.(翻译中文为:注册应用服务)
 *
 * @return void
 */
public function register()
{
    // Telescope::night();

    $this->hideSensitiveRequestDetails();

    Telescope::filter(function (IncomingEntry $entry)
    {
        //注意:代码必须写在 if ($this->app->environment('local')) 这个判断的上面 如果写在了下面 是不会生效的。
        if(request()->getMethod() == 'OPTIONS') {

            //如果当前请求是 OPTIONS 则过滤掉 即 让telescope工具不进行记录该次请求的所有相关数据信息
            return  false;
        }

        //默认情况下,会记录local环境中的所有数据(请求、异常、日志、计划任务等)。当前环境是否是local 取决于 APP_ENV 的值设置的是什么 刚安装的laravel框架 默认情况下 .env 文件里面的 APP_ENV 就是设置的local  
        if ($this->app->environment('local')) {
            return true;
        }

        /*
         * 将过滤 OPTIONS 请求的代码写在这里(
         * 即 写在了 if ($this->app->environment('local')) {
                            return true;
                    }
        ) 这个判断代码的下面 是不会生效的
        */

        //写在这里不会生效!!!!!!
        //if(request()->getMethod() == 'OPTIONS') {
          //  return  false;
        //}

        //下面这块儿代码 只会在 APP_ENV 没有设置为local时才会记录相关数据
        return $entry->isReportableException() ||
               $entry->isFailedRequest() ||
               $entry->isFailedJob() ||
               $entry->isScheduledTask() ||
               $entry->hasMonitoredTag();
    });
}

注意:上面代码的位置顺序,如果没有进行更改或者特殊处理的话 都是安装好的默认的情况下的时候 就按照这样写 就可以过滤掉 OPTIONS 请求了。


上面过滤OPTIONS请求的代码还可以这么写,使用注入的 $entry对象 来获取当前请求的各种详细数据 判断是否需要让 telescope 过滤掉当前请求(即 不记录本次请求的所有相关数据),代码如下:

/**
 * Register any application services.(翻译中文为:注册应用服务)
 *
 * @return void
 */
public function register()
{
    // Telescope::night();

    $this->hideSensitiveRequestDetails();

    Telescope::filter(function (IncomingEntry $entry)
    {
        //dd($entry->content); //content属性是一个数组 里面包含了本次http请求状态码、uri、请求方式、控制器、中间件等各种详细数据

        if($entry->content['response_status'] == 204)
        {
            return false;
        }

        if ($this->app->environment('local')) {
            return true;
        }

        return $entry->isReportableException() ||
               $entry->isFailedRequest() ||
               $entry->isFailedJob() ||
               $entry->isScheduledTask() ||
               $entry->hasMonitoredTag();
    });
}


其它注意事项:

如果在app/Providers/TelescopeServiceProvider.php文件中的register()方法中写的过滤规则没有对telescope生效的话,除了检查register()中写的代码问题,还要检查 config/app.php 文件中的 providers数组中,是否注册了telescope为服务提供者,如果没有,则在providers数组中注册telescope为服务提供者,即 在providers数组中 追加 App\Providers\TelescopeServiceProvider::class


Telescope工具的相关资料如下:

Laravel8.x版本中的Telescope工具的文档:https://learnku.com/docs/laravel/8.x/telescope/9424

视频教程:https://learnku.com/courses/laravel-package/2019/telescope/2492

本地开发调试解决方案:Laravel Telescope:https://laravelacademy.org/index.php/post/9687.html

Laravel Telescope 完美的应用调试工具:https://learnku.com/laravel/t/19013

如何更好地使用 telescope:https://learnku.com/articles/45653

Telescope | 后盾人:https://doc.houdunren.com/%E6%89%8B%E5%86%8C/laravel/10%20%E5%AE%98%E6%96%B9%E6%89%A9%E5%B1%95%E5%8C%85/7%20Telescope.html#介绍

基于Laravel Telescope提供本地调试解决方案:https://laravelacademy.org/post/22039#toc-0

https://cloud.tencent.com/developer/ask/sof/660093?from=16139

https://www.zhblog.net/qa/entries-in-laravel.html

四、使用laravel框架内置的“监听查询事件”

该种方法(监听查询事件) 本文所使用的Laravel框架版本号为:Laravel Framework 8.55.0


如果你想监控程序执行的每一个 SQL 查询,你可以使用 listen 方法。这个方法对于记录查询或调试非常有用。你可以在 服务提供器 中注册你的查询监听器。


这里我就不创建单独的监听器了,直接修改 app/Providers/EventServiceProvider.php 文件中的boot()方法即可,直接把监听laravel框架执行的sql语句代码写在这个方法里面即可,最终 boot()方法中的 监听框架执行的sql语句代码 如下所示:

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        //监听laravel框架执行的sql语句 并记录到log日志文件中
        DB::listen(function(QueryExecuted $event){
			
           $sql      = $event->sql; //执行的sql语句
           $bindings = $event->bindings; //sql语句对应绑定的sql值
           $time     = $event->time; //sql执行的时间

           $bindings = array_map(function($binding){
               if(is_string($binding))
               {
                   return "'$binding'"; //如果$binding是字符串类型 则要将$binding的左右两边拼接上'' 即 字符串=》 '字符串'
               }
               else if($binding instanceof \DateTime)
               {
                   return $binding->format("'Y-m-d H:i:s'"); //如果$binding是一个DateTime对象 则格式化时间 并在左右俩边拼接上''   
               }
               else
               {
                   return $binding; //直接返回$binding原本的值
               }
           }, $bindings);

           $sql = str_replace('?', '%s', $sql); //将sql语句中的?换成%s
           $sql = sprintf($sql, ...$bindings);  //将$bindings数组中的每一个元素替换掉$sql中的%s的位置

           Log::info("sql_log", ["sql" => $sql, "execute_time" => $time]); //将最终生成的sql语句写入到log日志文件中

        });
    }

尾声:

从如何输出Laravel框架执行的sql语句 到 引导出2个调试 Laravel 框架的debug工具,真是nice啊~ 哈哈哈哈哈哈



声明:禁止任何非法用途使用,凡因违规使用而引起的任何法律纠纷,本站概不负责。

小周博客
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

精彩评论

全部回复 0人评论 7,777人参与

loading