【问题标题】:How to Get the Query Executed in Laravel 5? DB::getQueryLog() Returning Empty Array如何在 Laravel 5 中执行查询? DB::getQueryLog() 返回空数组
【发布时间】:2015-03-01 11:25:35
【问题描述】:

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

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

结果

Array
(
)

如何查看此查询的日志?

【问题讨论】:

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

标签: php logging laravel laravel-5


【解决方案1】:

默认情况下,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。在哪里启用查询日志?

对于 HTTP 请求生命周期,您可以在某些 `BeforeAnyDbQueryMiddleware` [中间件][1] 的 `handle` 方法中启用查询日志,然后在同一中间件的 [`terminate`][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();
}

参考文献

【讨论】:

  • 如果您的系统使用多个db连接,您必须指定它,否则可能返回空数组:\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; ... });
【解决方案2】:

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

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 外观。不确定您要做什么,但控制器听起来像是您提到的最正确的选项。 (我通常在单独的帮助类中运行查询)
【解决方案3】:

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

DB::enableQueryLog();

那么你可以通过简单的方式获取查询日志:

dd(DB::getQueryLog());

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

【讨论】:

    【解决方案4】:

    把这个放在 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。你会在 cmets 中找到这个 laravel 5.2 的修复代码。

    【讨论】:

    • 有点脏,但是对于 $query->bindings 和 $query->time 提示 +1
    • 整洁!使用它在视图中显示结果,就在查询发生的地方!
    【解决方案5】:

    显然在 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);
        }
    );
    

    【讨论】:

    【解决方案6】:

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

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

    【讨论】:

    • 感谢兄弟够简单
    【解决方案7】:

    对于 laravel 5.8,您只需添加 dddump

    例如:

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

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

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

    【讨论】:

    • 在 laravel 8 中也很棒
    【解决方案8】:

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

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

    【讨论】:

      【解决方案9】:

      继续上面的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);
      

      【讨论】:

      • 中间件应该放入哪一部分?哪条路线?
      【解决方案10】:

      此代码用于:

      • 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 log sql语句插入数据库的递归。

      【讨论】:

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

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

      $user = User::find(5);
      

      你只需要这样做:

      DB::enableQueryLog();//enable query logging
      
      $user = User::find(5);
      
      print_r(DB::getQueryLog());//print sql query
      

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

      【讨论】:

        【解决方案12】:

        查询执行

        \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 的准确方法

        【讨论】:

          【解决方案13】:

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

          实现查询记录快速简单。

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

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

          【讨论】:

            【解决方案14】:

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

            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"

            【讨论】:

              【解决方案15】:

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

               protected $loggingQueries = false;
              

              改成

              protected $loggingQueries = true; 
              

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

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

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

              【讨论】:

              • 编辑vendor 文件是个坏主意。它们必须保持原样。
              • @shukshin.ivan 是的,不能编辑供应商文件,但要获得确切的查询,我们暂时编辑此代码,然后我们可以将其更改回来。
              猜你喜欢
              • 1970-01-01
              • 2015-04-30
              • 1970-01-01
              • 1970-01-01
              • 2021-09-02
              • 1970-01-01
              • 2016-08-09
              • 1970-01-01
              • 2023-04-03
              相关资源
              最近更新 更多