Laravel 5.1队列中模型查询无结果

14

我正在尝试从 Laravel 的官方文档中学习数据库队列。我已经按照文档中给出的配置完成了设置。

这里是我的工作:

<?php

namespace App\Jobs;

use App\SearchLog;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendTicket extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    protected $log;

    protected $searchLog = array();



    public function __construct(SearchLog $log , $data = array())
    {
        $this->log = $log;
        $this->searchLog = $data;
    }

     /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {

      $this->log->create($this->searchLog);     
    }

在我的控制器中,我这样调用

public function store(Request $request)
{
 $searchLog = array();
 // searchLog contains the data to be inserted into database 
 $log = new SearchLog();
 $this->dispatch(new SendTicket($log , $searchLog));
 }

当我运行php artisan queue:listen时,我会遇到以下错误:

  

[Illuminate\Database\Eloquent\ModelNotFoundException]找不到模型[App\SearchLog]的查询结果。

但是,当我像这样编辑工作时:

//only edited code 
public function __construct($data = array())
{
    $this->searchLog = $data;
}

/**
 * Execute the job.
 *
 * @return void
 */
public function handle()
{
  SearchLog::create($this->searchLog);   
}

当像这样调用时

 public function store(Request $request)
 {
    $searchLog = array();
    // searchLog contains the data to be inserted into database 
    $this->dispatch(new SendTicket($searchLog));
 }

它很好用并且数据已插入。
我的问题是:

  1. 如何将对象发送到队列?
  2. 最佳的发送数据到队列的方法是什么,以便我们可以处理它?

这个 Laravel 行为出乎意料,许多人都感到惊讶,所以我很高兴看到这里有一个相关的错误报告:https://github.com/laravel/framework/issues/14526 - Ryan
3个回答

23
问题出在使用了use Illuminate\Queue\SerializesModels;,它试图序列化你传递给构造函数的SearchLog $log参数。由于你的模型还没有被保存,所以它没有标识符。

根据Laravel文档:

如果您的队列任务在其构造函数中接受一个Eloquent模型,则只会将该模型的标识符序列化到队列上。当实际处理作业时,队列系统会自动从数据库重新获取完整的模型实例。

解决方法是从你想要保存模型的Job类中删除SerializesModels trait。

https://dev59.com/4aDia4cB1Zd3GeqPBEVV#42981667 是一个相关的问题,对我很有帮助。 - Ryan
@Ryan Hi Ryan,请帮我理解一下“只有模型的标识符将被序列化”的意思。对我来说还不太清楚。即使我将一个模型实例传递给Job构造函数,它仍然可以正常工作。但有时会抛出“没有找到模型的查询结果”的异常。我相信解决我的问题的方法就在你所说的内容中。 - Aman
@ronen谢谢你指出这一点。我也遇到了同样的问题。我的查询有一个group by,但没有包括主键,所以我只能选择外键(按外键分组),结果遇到了这个问题。我在邮件类中删除了serialize,嘭!它就好了。 - w1n78
@Ronen 尝试移除 SerializesModels 特性,结果运行良好。但根据您在文档中的引用,我意识到当我从数据库获取数据时,没有将 id 字段包含在结果中。因此,我将 id 添加到 Eloquent 对象中,也成功了。 - simpsons3
是的,“模型标识符”是被存储的内容。默认情况下,Laravel使用$id字段作为模型的主键。尽管您可以覆盖它。有时人们喜欢使用uuid代替。您可以在此处阅读更多信息:https://laravel.com/docs/eloquent#primary-keys - Ronen

4
我遇到了同样的问题。
如果你想将一个模型推送到队列中,似乎只有它的ID会保存在载荷中。所以,如果你还没有保存这个模型,它在处理程序中是不可用的。
最后,我在文档的队列和Eloquent模型部分中找到了解决方法。
为了解决这个问题,我看到有两种解决方案,第一种是确保你有一个持久化的模型:
public function store(Request $request)
{
 $searchLog = array();
 // searchLog contains the data to be inserted into database 
 $log = new SearchLog();
 //Save the Searchlog beforehand if it doesn't have any data constraints
 $log->save();
 //Dispatch the Job with the saved Model
 $this->dispatch(new SendTicket($log , $searchLog));
 }

或者将完整的模型保存过程仅放在处理程序中,就像您在示例中所做的那样。
//Full saving/initializing is happening here
public function handle()
{
  SearchLog::create($this->searchLog);   
}

在我的情况下,我需要将 Model 以高性能的方式保存到数据库中,因此我将其完全放在处理程序中,这样我的进程就不会依赖于数据库保存速度。因此,我会将它放在 handle() 函数中。


3
如果模型尚未保存或持久化,则通常会出现此问题。检查您的模型实例和持久性。另一个可能引发此问题的原因是多租户。因此,如果您正在使用或构建具有多个数据库的多租户应用程序,则可能需要找到一种将数据库连接传递给队列的方法,或者只需像Tylor Otwell在这里所述那样使用数据数组[5.4] Support queued jobs with unpersisted models

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接