Laravel 更新分块结果跳过行

问题描述

我正在尝试将我们的数据库从 ID 转换为 UUID。当我运行以下代码更新数据库时,会跳过随机行。

AppUser::select('id')->orderBy('created_at')->chunk(1000,function ($appUsers) {
        foreach ($appUsers as $appUser) {
            $uuid = Str::orderedUuid();
            DB::table('files')->where('fileable_type',AppUserInfo::class)->where('fileable_id',$appUser->id)->update([
                'fileable_id' => $uuid
            ]);
            DB::table('app_users')->where('id',$appUser->id)->update(['id' => $uuid]);
        }
    });

上次我检查时,总共有 236196 个被跳过了约 290 个。

我尝试使用 chunkById,但同样的事情发生了。 update 函数总是返回 true,所以我必须假设 Laravel 认为每一行在执行时都会更新。

解决方法

Laravel documentation on chunking 中有一个重大警告:

在块回调中更新或删除记录时,对主键或外键的任何更改都可能影响块查询。这可能会导致记录未包含在分块结果中。

您需要找到另一种方法来批量更新您的密钥。我使用了以下问题的答案中描述的技术:How to chunk results from a custom query in Laravel 当我无法使用 chunk 方法所需的回调时,尽管在这种情况下它不适用于 update查询,只有一个 select

,

这就是我最后做的

$appUsers = AppUser::select('id')->get();
    $chunkSize = 1000;
    $numberOfChunks = ceil($appUsers->count() / $chunkSize);
    $chunks = $appUsers->split($numberOfChunks);
    
    foreach($chunks as $chunk) {
        foreach($chunk as $appUser) {
            $uuid = Str::orderedUuid();
            DB::table('files')->where('fileable_type',AppUserInfo::class)->where('fileable_id',$appUser->id)->update([
                'fileable_id' => $uuid
            ]);
            DB::table('app_users')->where('id',$appUser->id)->update(['id' => $uuid]);
        }
    }

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...