【发布时间】:2020-03-17 08:43:35
【问题描述】:
我们目前在执行以下代码时遇到Duplicate entryQueryException:
Slug::firstOrCreate([
Slug::ENTITY_TYPE => $this->getEntityType(),
Slug::SLUG => $slug
], [
Slug::ENTITY_ID => $this->getKey()
]);
由于 Laravel 的 firstOrCreate 方法在插入之前首先检查具有属性的条目是否存在,因此永远不会发生此异常。但是,我们有一个应用程序,每天有数百万的访问者和数百万的操作,因此还使用带有两个从属的主数据库连接进行读取。因此,可能会出现一些竞争条件。
我们目前尝试分离查询并强制主连接读取:
$slugModel = Slug::onWriteConnection()->where([
Slug::SLUG => $slug,
Slug::ENTITY_TYPE => $this->getEntityType()
])->first();
if ($slugModel && $slugModel->entity_id !== $this->getKey()) {
$class = get_class($this);
throw new \RuntimeException("The slug [{$slug}] already exists for a model of type [{$class}].");
}
if (!$slugModel) {
return $this->slugs()->create([
Slug::SLUG => $slug,
Slug::ENTITY_TYPE => $this->getEntityType()
]);
}
但有时仍会发生异常。
我们的下一个方法是在读取检查之前锁定表并在写入之后释放锁定,以防止在我们的读取和写入之间从其他数据库操作中插入具有相同 slug 的任何插入。有谁知道如何解决这个问题?我真的不明白Laravel's Pessimistic Locking 如何帮助解决问题。我们使用 MySql 作为我们的数据库。
【问题讨论】:
-
我认为悲观锁定不能解决你的问题。这些类型的锁定用于锁定从多个连接更新的资源。此外,由于您的流量非常高,我不建议在没有适当研究它对系统的影响的情况下使用表锁定。 pro and cons of locking tableoptimistic-vs-pessimistic-locking
-
我自己还在学习数据库并发问题,但是通过阅读“设计数据密集型应用程序”,您遇到的现象称为“写入倾斜”。作者说:“自动防止写入倾斜需要真正的可序列化隔离。”在锁定或设置新的隔离级别之前,IMO 可能值得考虑您的应用程序如何处理重复项。如果 slug 是自动生成的,您可以处理异常并生成一个新的。如果它们是用户定义的,用户可以在不同的数据库表或内存数据库中“预先保留” slug。
-
感谢您的回复!我们将尝试处理异常并为这些情况生成一个新异常。谢谢!
标签: php mysql laravel eloquent locking