[Laravel] “已达到 10000 次重试仍未找到唯一值”是什么意思?[Faker]

大家好,
我是开发团队野生队的成员 Mandai。
我认为大多数人会使用
Laravel 自带的Faker 它的优点在于支持多语言,并且允许你创建各种类型的测试数据,此外,它还有一个名为 unique 的便捷方法,可以让你创建多个带有唯一 ID 的数据片段,这也非常实用。
然而,根据你的使用方式,你可能会遇到类似标题中的错误,你可能不知道它的含义,或者无法解决,只能尝试其他方法……如果发生这种情况,安装 Faker 就显得毫无意义了!因此,这次我想介绍一下如何解决 Faker 中常见的“已达到最大重试次数 10,000 次但未找到唯一值”错误。
错误原因
从错误信息来看,我感觉自己好像陷入了无限循环,但我想不出具体原因,只知道错误发生在我使用 Faker 的 unique() 函数前后,
因为我没有编写任何会导致无限循环的代码。
如果在合适的时机重置,它就能正常工作,但当然,重置后就会出现重复数据。
你得用一段时间才能掌握诀窍,但一旦你理解了原因,应该就能找到解决办法了……!!
那么,让我们来看一下 Faker 的 unique() 方法的代码。
跟踪 unique() 行为
GitHub 上的这部分代码是 unique() 方法的实现。
接收到的变量会直接传递给一个名为 UniqueGenerator 的类,所以让我们仔细看看 UniqueGenerator 类的代码。
该行为通过魔法方法得到了很好的控制,但本质上它只是调用了使用 UniqueGenerator::__call() 创建对象时接收到的 Faker\Generator 对象上的一个方法。while
循环条件会检查重复项,因此返回值是唯一的。
使用数组键检查重复项看起来相当原始,但原因很容易理解。
抛出 OverflowException 时的错误信息包含标题文本,原因是此 do while 语句中的循环次数已达到重试次数限制。
如何避免错误
要避免这个错误,只有一个办法:修改 unique() 方法的第二个参数的值,增加循环的重试次数。
默认值是 10,000,但如果你想要的值的数量是 15,000,肯定会溢出。
增加重试次数:
$factory->define(User::class, function(Faker\Generator $faker) { return [ 'name' => $faker->name(), 'age' => $faker->unique(false, 15000)->numberBetween(1, 80), // 将重试次数改为 15000 ]; });
另一个原因是,Faker\Generator 对象返回的值的变体数量本来就少于 10,000 个。
如上例所示,numberBetween() 只能返回 1 到 80 之间的值,因此无法为第 81 个数据生成唯一值,导致循环超出重试次数限制。
虽然像人名这样的随机组合看起来变化范围很大,但实际上,虽然英文名字(男女)有大约 3,000 种变体,姓氏也有大约 473 种变体,但日语名字(男女)只有大约 50 种变体,姓氏只有 31 种变体,全名也只有大约 1,500 种变体。
即使你需要 5000 个完整的日语名字,如果只有 1500 种可能的组合,使用 unique() 函数就毫无意义,所以你需要考虑其他方法。
例如,似乎可以通过在 Faker\Generator 类中添加新的提供者来实现,但我还没有深入研究,希望以后有机会能介绍一下。
概括
这次,我深入研究了在使用 Faker 时经常遇到的“已达到最大重试次数 10000 次但未找到唯一值”的错误。
一切都始于我在网上搜索该错误信息时,偶然看到 StackOverflow 上的一篇帖子说“reset(true) 没问题!”,这让我觉得肯定有什么地方出了问题。
我怀疑是不是有什么根本性的误解,所以我调查了一下,但似乎存在不止一个陷阱。
如果您遇到“已达到最大重试次数 10,000 次仍未找到唯一值”的消息,请调查重试次数和获取的虚拟数据量。
就这样。
2