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


171

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

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

结果

Array
(
)

如何查看此查询的日志?


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

Answers:


256

默认情况下,Laravel 5中禁用了查询日志:https : //github.com/laravel/framework/commit/e0abfe5c49d225567cb4dfd56df9ef05cc297448

您将需要通过调用以下命令来启用查询日志:

DB::enableQueryLog();

或注册一个事件监听器:

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.在哪里启用查询日志?

对于HTTP请求生命周期,可以在handle某些BeforeAnyDbQueryMiddleware 中间件的方法中启用查询日志,然后terminate在同一中间件的方法中检索执行的查询。

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();
}

参考资料


6
如果系统使用多个数据库连接,则必须指定它,否则它可能返回空数组:\DB::connection('myconnection')->enableQueryLog(); print_r(\DB::connection('myconnection')->getQueryLog());
Diana

发表您的评论作为您的答案@DianaR。
Narendrasingh Sisodia


如何启用它来记录雄辩的“ NameController :: create();” 声明?
鲁本·鲁伊斯

2
请注意,在Laravel 5.4中,DB::listen回调函数具有不同的签名。它更像是这样: DB::listen(function($query) { $sql = $query->sql; $bindings = $query->bindings; $time = $query->time; ... });
racl101

45

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

DB::enableQueryLog();

# your laravel query builder goes here

$laQuery = DB::getQueryLog();

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

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

做一个print_r()$laQuery[0]得到充分的查询,包括绑定。($lcWhatYouWant上面的变量会将变量替换为??

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

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

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

(连接名称为“ mysql2”)


1
这段代码在哪里呢?(5.4)我已经尝试过控制器,模型,并在中间件中进行了研究,但在得到db错误之前不确定在哪里执行它。
blamb

如果在运行停止执行的查询时遇到错误,则该错误应告诉您问题出在哪里。如果您关闭了错误,则可以在/ storage / log / laravel中检查错误日志或类似内容。(目前我不在电脑上)如果您说的是在运行我在答案中建议的代码时出错,请确保无论运行代码的位置都包括数据库外观。不确定您要做什么,但控制器听起来像您提到的最正确的选项。(我通常在单独的帮助程序类中运行查询)
Skeets

14

把它放在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提交,此页面中的源代码。您将在注释中找到laravel 5.2的此修复代码。


有点脏,但是$ query-> bindings和$ query-> time提示为+1
Paolo Stefan

整齐!使用它可以在视图中显示查询结果的正确位置!
查尔斯伍德

14

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

DB::enableQueryLog();

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

dd(DB::getQueryLog());

最好在应用程序启动之前启用查询日志记录,这可以在BeforeMiddleware中进行,然后在AfterMiddleware中检索已执行的查询。


11

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

因此,如果要DB::listen在Laravel 5.2中使用,则应执行以下操作:

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
Csongor Halmai'7


5

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

$users = User::orderBy('name', 'asc')->toSql();
echo $users;
// Outputs the string:
'select * from `users` order by `name` asc'

2

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

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

1

在继续使用Laravel 5.2进行“ 表观”时,DB :: listen中的闭包仅收到一个参数...上面的响应:您可以将此代码放入Middleware脚本中,并在路由中使用它。

另外:

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);

哪一部分应该放入中间件?哪条路线?
user1016265 '16

1

该代码用于:

  • Laravel 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 logsql语句插入数据库的递归操作。


0

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

实现查询记录的快速简便的方法。

您只需要AppServiceProviderboot方法中添加回调即可监听数据库查询:

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));
        });
    }
}

0

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

$user = User::find(5);

您只需要执行以下操作:

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

$user = User::find(5);

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

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


-3

对于laravel 5及更高版本,仅使用DB :: getQueryLog()不会这样做。默认情况下,此值

 protected $loggingQueries = false;

更改为

protected $loggingQueries = true; 

在以下文件中进行日志记录查询。

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

然后,我们可以使用要在DB::getQueryLog()其中打印查询的位置。


1
编辑vendor文件是个坏主意。它们必须保持原始。
shukshin.ivan

@ shukshin.ivan是的,不得编辑供应商文件,但要获取确切的查询,我们暂时已编辑此代码,然后可以将其更改回。
Rupali Pemare
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.