当前位置: 首页 > 知识库问答 >
问题:

Laravel:如何在子进程中通过Eloquent更新MySQL?

裴俊雅
2023-03-14

我编写了一个Laravel命令,它将派生一些子进程。子进程将通过Eloquent更新数据库。

代码:

<?php

namespace App\Console\Commands;

use App\Console\BaseCommand;
use App\Item;
use Illuminate\Console\Command;

class Test extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'test';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        Item::first();
        $children = [];
        for($i = 0; $i < 5; $i++) {
            $pid = pcntl_fork();
            if ($pid == -1) {
                die('pmap fork error');
            } else {
                if ($pid) {
                    $children[] = $pid;
                } else {
                    Item::first(); exit;
                }
            }
        }
        foreach ($children as $child) {
            pcntl_waitpid($child, $status);
        }
    }
}

运行我的代码:

vagrant@homestead:~/ECAME$ php artisan test


  [Illuminate\Database\QueryException]
  Packets out of order. Expected 1 received 116. Packet size=6255201 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)



  [Illuminate\Database\QueryException]
  Packets out of order. Expected 1 received 100. Packet size=6238815 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)



  [Illuminate\Database\QueryException]
  Packets out of order. Expected 1 received 0. Packet size=2816 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)



  [Illuminate\Database\QueryException]
  Packets out of order. Expected 1 received 116. Packet size=6381412 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)



  [ErrorException]
  Packets out of order. Expected 1 received 100. Packet size=6238815



  [ErrorException]
  Packets out of order. Expected 1 received 116. Packet size=6381412



  [ErrorException]
  Packets out of order. Expected 1 received 116. Packet size=6255201



  [ErrorException]
  Packets out of order. Expected 1 received 0. Packet size=2816

这背后的原因是什么?以及如何在子进程中通过口才更新MySQL?

附言:

我认为这个问题的原因是,所有子进程都使用从父进程分叉的相同MySQL连接。

如果我在调用fork()之前没有在父进程中调用Item::first(),那么它运行良好。(在我的实际用例中,我不能这样做...父进程将在分叉子进程之前使用MySQL做很多事情。

因为在这种情况下,MySQL连接不会在父进程中初始化,所以每个子进程都会自己初始化连接。

那么,如果是这种情况,如何在分叉后为每个子进程初始化新的MySQL连接?

共有3个答案

薛高澹
2023-03-14

在Laravel中进行进程分叉后,将以下代码放入子进程中,在Laravel 4.2中为我创建了一个稳定的mysql客户端连接:

DB::disconnect();

// we need to clone the database connection of the parent and
// create a new connection as using the original causes protocol errors

$dbconn_child = 
    [
        'driver'    => DB::connection()->getConfig('driver'),
        'host'      => DB::connection()->getConfig('host'),
        'port'      => DB::connection()->getConfig('port'),
        'database'  => DB::connection()->getConfig('database'),
        'username'  => DB::connection()->getConfig('username'),
        'password'  => DB::connection()->getConfig('password'),
        'charset'   => DB::connection()->getConfig('charset'),
        'collation' => DB::connection()->getConfig('collation'),
        'prefix'    => DB::connection()->getConfig('prefix'),
        'modes'     => DB::connection()->getConfig('modes'),
        'options'   => DB::connection()->getConfig('options'),
    ];

Config::set('database.connections.DB_CONFIG_CHILD', $dbconn_child);

DB::setDefaultConnection('DB_CONFIG_CHILD');

DB::reconnect();

这将使用与原始连接相同的参数动态创建新连接,然后将子进程切换到新连接并进行连接。

简单地断开并重新连接默认连接会导致类似于OPs结果的各种mysql协议错误。

端木高卓
2023-03-14

如果您在database.php中定义了一个具有相等参数的第二个ddbb,并且您在第二个连接中启动了项目::first?

# Primary database connection
            'mysql' => [
                'driver'    => 'mysql',
                'host'      => 'localhost',
                'database'  => 'myddbb',
                'username'  => 'root',
                'password'  => '',
                'charset'   => 'utf8',
                'collation' => 'utf8_unicode_ci',
                'prefix'    => '',
            ],
  # Secondary database connection
        'mysql_forConnectChildren' => [
            'driver'    => 'mysql',
            'host'      => 'localhost',
            'database'  => 'myddbb',
            'username'  => 'root',
            'password'  => '',
            'charset'   => 'utf8',
            'collation' => 'utf8_unicode_ci',
            'prefix'    => '',
        ],

后来

 $item = \DB::connection('mysql_forConnectChildren')->select('select * from Item')->get(1);

我没有测试,但我认为可以工作

南门向荣
2023-03-14

由于这一切都是关于连接死亡的,因此只需重新连接到数据库即可解决此问题。

use Illuminate\Support\Facades\DB;

[...]

public function handle()
{
    User::first();

    $children = [];

    for ($i = 0; $i < 5; $i++) 
    {
        $pid = pcntl_fork();

        if ($pid == -1) 
        {
            die('pmap fork error');
        } 
        else 
        {
            if ($pid) 
            {
                $children[] = $pid;
            } 
            else
            {
                DB::connection()->reconnect(); // <----- add this
                User::first(); exit;
            }
        }
    }

    foreach ($children as $child) 
    {
        pcntl_waitpid($child, $status);
    }
}

我在Laravel 5.6中测试了这一点,它工作正常。

 类似资料:
  • 问题内容: 我是Laravel的新手。我正在开发laravel 5应用程序,并且卡在这里。我有2个这样的模型: 消息和用户之间存在多对多关系,因此给我一个数据透视表: 我有这样的SQL查询: 如何将此查询转换为laravel对等词? 问题答案: 下面的代码解决了我的问题:

  • 我正在创建一个网站。于是,就有了一个表格给用户看。在我的数据库中,我在操作列下存储了0表示挂起,1表示已批准。如果某个用户有0,则此表中显示待定,如果用户有1,则显示已批准。现在我想当有人点击这个挂起按钮时,我想将数据库值更新为1。我尝试了如下。但是,当我点击挂起按钮,它给我这个错误- 而且我无法更新数据库值。 我怎样才能解决这个问题?? 查看页面(AdminPanel.blade.php) 控制

  • 问题内容: 如何更新子查询中也存在的表?我必须分两个阶段进行吗?(创建一个临时表-将选定的数据放入其中,然后更新最终表) 我正在尝试使用每个CTN的网络标签更新invoiceLine表。 最终结果将是: invoiceLine 我有以下表格: invoiceLine ctn network 1234 null 2345 null 3456 null terminal ctn network 123

  • 我正在与Laravel8合作开发我的论坛项目,目前我已经制作了一个用户可以编辑答案的页面。表格如下: 然后在控制器方法中,我添加了以下内容: 以下是实现这一目标的路线: 现在我想重定向用户到这样的网址: 但是,通过此代码,用户将重定向到此url: 那么我如何才能做到这一点呢? 如果你能和我分享你的想法或建议,我将不胜感激... 谢谢

  • 问题内容: 我有以下口才的查询(这是查询的简化版本,其中包含更多s和s,因此是实现此目的的明显回旋方式-该理论很重要): 如您所见,我最早的约会发生在我的约会上或之后。这导致运行单独的查询来获取该日期,然后将该日期用作主查询中的参数。有没有一种雄辩的方法可以将查询嵌入在一起形成一个子查询,因此只有1个数据库调用而不是2个? 编辑: 根据@Jarek的答案,这是我的查询: 这些块使查询中的所有参数突

  • 我在更新google drive上的现有电子表格时遇到了一个问题,没有使用批量更新(现在我甚至不确定是否可能) 我已经有一些数据现有的电子表格,然后我检索文件从谷歌驱动器通过 我很容易通过名称匹配我的文件,然后我只想在创建的文件中更新电子表格。 这里我从匹配名称的文件中获取电子表格,然后我只想把empy表放在那里(例如)。 第一点,我不确定如何正确地“更新”驱动器上的电子表格,因为我无法使用 我不