mpyw / laravel-retry-on-duplicate-key
此包已废弃,不再维护。未建议替代包。
当违反唯一约束时,自动重试非原子性插入更新操作。
v1.3.3
2023-03-15 02:21 UTC
Requires
- php: ^8.0
- ext-pdo: *
- illuminate/contracts: ^9.0 || ^10.0 || ^11.0
- illuminate/database: ^9.0 || ^10.0 || ^11.0
- illuminate/support: ^9.0 || ^10.0 || ^11.0
- mpyw/laravel-unique-violation-detector: ^1.0
Requires (Dev)
- nunomaduro/larastan: >=1.0
- orchestra/testbench: *
- orchestra/testbench-core: >=7.0
- phpstan/extension-installer: >=1.1
- phpstan/phpstan: >=1.1
- phpunit/phpunit: >=9.5
README
注意
废弃:由于Laravel v10.29.0 的变化,此库的功能已集成到Laravel核心中,因此在此大多数情况下不再需要此库。因此,维护将停止。 从现在开始,重试处理将在 Model::createOrFirst()
、Model::firstOrCreate()
和 Model::updateOrCreate()
中自动执行。唯一仍有价值的是 Model::firstOrNew() + save()
模式,但由于等效处理可以由自己编写,请不要再使用此库。
当违反唯一约束时,自动重试 非原子性 插入更新操作。
例如:firstOrCreate()
updateOrCreate()
firstOrNew() + save()
原始问题: 更新或创建时的重复条目 · 问题 #19372 · laravel/framework
要求
包 | 版本 | 必需 |
---|---|---|
PHP | ^8.0 |
✅ |
Laravel | ^9.0 || ^10.0 |
✅ |
mpyw/laravel-unique-violation-detector | ^1.0 |
✅ |
PHPStan | >=1.1 |
安装
composer require mpyw/laravel-retry-on-duplicate-key
基本用法
重要
默认实现由 ConnectionServiceProvider
提供,但 包发现不可用。请注意,您必须自己将其注册到 config/app.php
。
<?php return [ /* ... */ 'providers' => [ /* ... */ Mpyw\LaravelRetryOnDuplicateKey\ConnectionServiceProvider::class, /* ... */ ], ];
<?php use Illuminate\Support\Facades\DB; $user = DB::retryOnDuplicateKey(function () { // Email has a unique constraint return User::firstOrCreate(['email' => 'example.com'], ['name' => 'Example']); });
其他 | 您 |
---|---|
选择 (无结果) |
|
︙ | |
︙ | 选择 (无结果) |
︙ | ︙ |
插入 (OK) |
︙ |
︙ | |
插入 (错误!重复条目) |
|
准备下一次重试,参考主连接 | |
选择 (1 结果) |
高级用法
您可以通过将 RetriesOnDuplicateKey
特性扩展到连接类来自定义。
<?php namespace App\Providers; use App\Database\MySqlConnection; use Illuminate\Database\Connection; use Illuminate\Support\ServiceProvider; class DatabaseServiceProvider extends ServiceProvider { public function register(): void { Connection::resolverFor('mysql', function (...$parameters) { return new MySqlConnection(...$parameters); }); } }
<?php namespace App\Database; use Illuminate\Database\Connection as BaseMySqlConnection; use Mpyw\LaravelRetryOnDuplicateKey\RetriesOnDuplicateKey; class MySqlConnection extends BaseMySqlConnection { use RetriesOnDuplicateKey; }
与其他原生upsert实现的区别
- [8.x] 通过 paras-malhotra 将 upsert 添加到 Eloquent 和基础查询构建器中 · Pull Request #34698 · laravel/framework
- staudenmeir/laravel-upsert: Laravel UPSERT 和 INSERT IGNORE 查询
这些实现侧重于原子地执行 INSERT-or-UPDATE 查询。因此,在用法上肯定存在明显差异。
firstOrCreate()
updateOrCreate()
有效地保存 自增编号空间。- 相比之下,
upsert()
总是增加数字,即使没有发生 INSERT,这会导致出现缺失的数字。如果查询频繁执行,这可能会成为一个严重问题。如果您仍然想使用upsert()
,您可能需要考虑使用 UUID 或 ULID 而不是自增。
- 相比之下,
- 如果
firstOrCreate()
的调用主要是通过只有一个 SELECT 而很少通过一个随后的 INSERT 完成,那么它具有明显的优势。- 相比之下,你必须在所有情况下都使用
upsert()
执行两个查询。
- 相比之下,你必须在所有情况下都使用
- 至于
updateOrCreate()
,这取决于 RDBMS,可能会有额外的考虑。- 对于非 MySQL 的 RDBMS,除非其调用确实更改了行的字段值,否则
updateOrCreate()
会更好。upsert()
可能会破坏当连接既有 Reader(副本)又有 Writer(主)时的sticky
优化,因为它们假设所有由 WHERE 条件缩窄的行都已受到影响。 - 在 MySQL 中,
upsert()
对此没有限制。它认为只有实际更改字段值的行才会受到影响。
- 对于非 MySQL 的 RDBMS,除非其调用确实更改了行的字段值,否则
- 请注意,
upsert()
永远不会触发 Eloquent 事件,如created
或updated
,因为它的实现是在 Eloquent Builder 上,而不是在 Model 上。 - 只有
upsert()
支持批量插入。如果有大量记录且不需要任何 Eloquent 事件,这会很有好处。