ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Laravel 5 中执行查询? DB::getQueryLog() 返回空数组

我正在尝试查看查询的日志,但 DB::getQueryLog() 只是返回一个空数组:

$user = User::find(5);
print_r(DB::getQueryLog());

结果

Array
(
)

如何查看此查询的日志?

Laravel Debugbar 是记录查询的好工具。它还有许多其他很棒的功能。

M
Marty Aghajanyan

Laravel 5 默认禁用查询日志:https://github.com/laravel/framework/commit/e0abfe5c49d225567cb4dfd56df9ef05cc297448

您需要通过调用启用查询日志:

DB::enableQueryLog();

// and then you can get query log

dd(DB::getQueryLog());

或注册一个事件监听器:

DB::listen(
    function ($sql, $bindings, $time) {
        //  $sql - select * from `ncv_users` where `ncv_users`.`id` = ? limit 1
        //  $bindings - [5]
        //  $time(in milliseconds) - 0.38 
    }
);  

一些技巧

1.多个数据库连接

如果您有多个数据库连接,则必须指定要记录的连接

要为 my_connection 启用查询日志:

DB::connection('my_connection')->enableQueryLog();

要获取 my_connection 的查询日志:

print_r(
   DB::connection('my_connection')->getQueryLog()
);

2.在哪里启用查询日志?

class BeforeAnyDbQueryMiddleware
{
    public function handle($request, Closure $next)
    {
        DB::enableQueryLog();
        return $next($request);
    }

    public function terminate($request, $response)
    {
        // Store or dump the log data...
        dd(
            DB::getQueryLog()
        );
    }
}

中间件的链不会针对工匠命令运行,因此对于 CLI 执行,您可以在 artisan.start 事件侦听器中启用查询日志。

例如,您可以将其放在 bootstrap/app.php 文件中

$app['events']->listen('artisan.start', function(){
    \DB::enableQueryLog();
});

3.记忆

Laravel 将所有查询保存在内存中。所以在某些情况下,比如插入大量行,或者有大量查询的长时间运行的作业,这可能会导致应用程序使用过多的内存。

在大多数情况下,您只需要查询日志来进行调试,如果是这种情况,我建议您仅在开发时启用它。

if (App::environment('local')) {
    // The environment is local
    DB::enableQueryLog();
}

参考

https://laravel.com/docs/5.0/database#query-logging


如果您的系统使用多个数据库连接,则必须指定它,否则它可能会返回空数组:\DB::connection('myconnection')->enableQueryLog(); print_r(\DB::connection('myconnection')->getQueryLog());
发表您的评论作为您的答案@DianaR。
如何启用它来记录 Eloquent "NameController::create();"陈述?
请注意,在 Laravel 5.4 中,DB::listen 回调函数具有不同的签名。更像是这样:DB::listen(function($query) { $sql = $query->sql; $bindings = $query->bindings; $time = $query->time; ... });
S
Salman Zafar

如果您真正关心的是用于快速调试目的的实际查询(最后一次运行):

DB::enableQueryLog();

# your laravel query builder goes here

$laQuery = DB::getQueryLog();

$lcWhatYouWant = $laQuery[0]['query']; # <-------

# optionally disable the query log:
DB::disableQueryLog();

$laQuery[0] 上执行 print_r() 以获取完整的查询,包括绑定。 (上面的 $lcWhatYouWant 变量将用 ?? 替换变量)

如果您使用的不是主 mysql 连接,则需要使用这些连接:

DB::connection("mysql2")->enableQueryLog();

DB::connection("mysql2")->getQueryLog();

(你的连接名称是“mysql2”)


这段代码在哪里? (5.4) 我尝试了控制器、模型并查看了中间件,但在我得到 db 错误之前不确定在哪里执行它。
如果您在运行正在停止执行的查询时遇到错误,该错误应该告诉您问题所在。如果您关闭了错误,您可以检查 /storage/log/laravel 或类似内容中的错误日志。 (我现在不在我的电脑旁)如果您说运行我在回答中建议的代码时遇到错误,请确保在运行代码的任何地方都包含 DB 外观。不确定您要做什么,但控制器听起来像是您提到的最正确的选项。 (我通常在单独的帮助类中运行查询)
S
Salman Zafar

您需要首先启用查询日志记录

DB::enableQueryLog();

然后您可以通过简单的方式获取查询日志:

dd(DB::getQueryLog());

如果您在应用程序启动之前启用查询日志记录会更好,您可以在 BeforeMiddleware 中执行此操作,然后在 AfterMiddleware 中检索已执行的查询。


M
MJH

把它放在 routes.php 文件中:

\Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
    echo'<pre>';
    var_dump($query->sql);
    var_dump($query->bindings);
    var_dump($query->time);
    echo'</pre>';
});

由 msurguy 提交,this page 中的源代码。你会在评论中找到这个 laravel 5.2 的修复代码。


有点脏,但是对于 $query->bindings 和 $query->time 提示 +1
整洁的!使用它在视图中显示结果,就在查询发生的地方!
L
Luís Cruz

显然在 Laravel 5.2 中,DB::listen 中的闭包只接收一个参数。

所以,如果你想在 Laravel 5.2 中使用 DB::listen,你应该这样做:

DB::listen(
    function ($sql) {
        // $sql is an object with the properties:
        //  sql: The query
        //  bindings: the sql query variables
        //  time: The execution time for the query
        //  connectionName: The name of the connection

        // To save the executed queries to file:
        // Process the sql and the bindings:
        foreach ($sql->bindings as $i => $binding) {
            if ($binding instanceof \DateTime) {
                $sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
            } else {
                if (is_string($binding)) {
                    $sql->bindings[$i] = "'$binding'";
                }
            }
        }

        // Insert bindings into query
        $query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);

        $query = vsprintf($query, $sql->bindings);

        // Save the query to file
        $logFile = fopen(
            storage_path('logs' . DIRECTORY_SEPARATOR . date('Y-m-d') . '_query.log'),
            'a+'
        );
        fwrite($logFile, date('Y-m-d H:i:s') . ': ' . $query . PHP_EOL);
        fclose($logFile);
    }
);

对于较旧的 Laravel,我将解决方案添加到 stackoverflow.com/a/44920198/3823826
d
doncadavona

像这样使用 toSql() 而不是 get()

$users = User::orderBy('name', 'asc')->toSql();

echo $users;

// Outputs the string:
'select * from `users` order by `name` asc'

谢谢兄弟够简单
l
larp

对于 laravel 5.8,您只需添加 dd 或转储。

前任:

DB::table('users')->where('votes', '>', 100)->dd();

或者

DB::table('users')->where('votes', '>', 100)->dump();

参考:https://laravel.com/docs/5.8/queries#debugging


在 laravel 8 中也很棒
S
Salman Zafar

(Laravel 5.2)我发现最简单的方法就是添加一行代码来监控 sql 查询:

\DB::listen(function($sql) {var_dump($sql); });

M
Mohamed Raza

查询执行

\Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {          
            $sql = $query->sql; 
            $time = $query->time;
            $connection = $query->connection->getName();
 
            Log::debug('query : '.$sql);
            Log::debug('time '.$time);
            Log::debug('connection '.$connection);
        });

询问

StaffRegister::all();

输出

[2021-03-14 08:00:57] local.DEBUG: query : select * from `staff_registers`  
[2021-03-14 08:00:57] local.DEBUG: time 0.93  
[2021-03-14 08:00:57] local.DEBUG: connection mysql  

完整的结构

<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Log;
use App\Models\StaffRegister;

class AuthController extends Controller
{
   public function index(){
   
       \Event::listen('Illuminate\Database\Events\QueryExecuted', function ($query) {
      
           $sql = $query->sql; 
           $time = $query->time;
           $connection = $query->connection->getName();

           Log::debug('query : '.$sql);
           Log::debug('time '.$time);
           Log::debug('connection '.$connection);
       });

       $obj = StaffRegister::all(); 
    
       return $obj;
   }
}

GET REPOSNSE 的准确方法


C
Community

继续上面的 Apparently with Laravel 5.2, the closure in DB::listen only receives a single parameter... 响应:您可以将此代码放入中间件脚本并在路由中使用它。

此外:

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$log = new Logger('sql');
$log->pushHandler(new StreamHandler(storage_path().'/logs/sql-' . date('Y-m-d') . '.log', Logger::INFO));

// add records to the log
$log->addInfo($query, $data);

哪个部分应该放入中间件?哪条路线?
c
ch271828n

此代码用于:

拉拉维尔 5.2

将语句记录到 mysql 数据库中

这是基于@milz 回答的代码:

    DB::listen(function($sql) {
        $LOG_TABLE_NAME = 'log';
        foreach ($sql->bindings as $i => $binding) {
            if ($binding instanceof \DateTime) {
                $sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
            } else {
                if (is_string($binding)) {
                    $sql->bindings[$i] = "'$binding'";
                }
            }
        }
        // Insert bindings into query
        $query = str_replace(array('%', '?'), array('%%', '%s'), $sql->sql);
        $query = vsprintf($query, $sql->bindings);
        if(stripos($query, 'insert into `'.$LOG_TABLE_NAME.'`')===false){
            $toLog = new LogModel();
            $toLog->uId = 100;
            $toLog->sql = $query;
            $toLog->save();
        }
    });

核心是if(stripos...行,它防止了将insert into log sql语句插入数据库的递归。


这行代码是如何工作的? if(stripos($query, 'insert into '.$LOG_TABLE_NAME.'')===false){
@MohamedRaza 防止递归。否则,“INSERT INTO yourlogtable”查询本身将触发此方法,并生成新的插入语句,依此类推。
是的,这是一个无限循环,任何 if 语句也不会破坏循环
G
Gufran Hasan

假设您要打印以下语句的 SQL 查询。

$user = User::find(5);

您只需要执行以下操作:

DB::enableQueryLog();//enable query logging

$user = User::find(5);

print_r(DB::getQueryLog());//print sql query

这将打印 Laravel 中最后执行的查询。


J
Javier Núñez

我认为这篇文章中的答案是:https://arjunphp.com/laravel-5-5-log-eloquent-queries/

快速简单地实现查询记录。

您只需在 boot 方法中的 AppServiceProvider 中添加一个回调即可侦听 DB 查询:

namespace App\Providers;

use DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        DB::listen(function($query) {
            logger()->info($query->sql . print_r($query->bindings, true));
        });
    }
}

S
Siva

将此函数添加到您的帮助文件并简单地调用。

function getRawQuery($sql){
        $query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
        $query = vsprintf($query, $sql->getBindings());     
        return $query;
}

输出:"select * from user where status = '1' order by id desc limit 25 offset 0"


S
Salman Zafar

对于 laravel 5 及更高版本,仅使用 DB::getQueryLog() 是不行的。默认情况下,此值为

 protected $loggingQueries = false;

将其更改为

protected $loggingQueries = true; 

在下面的文件中记录查询。

/vendor/laravel/framework/src/illuminate/Database/Connection.php 

然后我们可以使用您要打印查询的 DB::getQueryLog()


编辑 vendor 文件是个坏主意。它们必须保持原样。
@shukshin.ivan 是的,不能编辑供应商文件,但要获得确切的查询,我们暂时编辑此代码,然后我们可以将其更改回来。