В настоящее время мы сталкиваемся с Duplicate entry
QueryException при выполнении следующего кода:
Slug::firstOrCreate([
Slug::ENTITY_TYPE => $this->getEntityType(),
Slug::SLUG => $slug
], [
Slug::ENTITY_ID => $this->getKey()
]);
Поскольку метод firstOrCreate
с помощью Laravel сначала проверяет, существует ли запись с атрибутами, перед ее вставкой, это исключение никогда не должно происходить. Однако у нас есть приложение с миллионами посетителей и миллионами действий каждый день, и поэтому мы также используем соединение с основной БД с двумя ведомыми устройствами для чтения. Таким образом, возможно, что возникнут некоторые условия гонки.
В настоящее время мы пытались отделить запрос и принудительно установить мастер-соединение для чтения:
$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()
]);
}
Однако иногда возникает исключение.
Наш следующий подход заключается в блокировке таблицы перед проверкой чтения и снятии блокировки после записи, чтобы предотвратить любые вставки с таким же фрагментом в результате действий других баз данных между нашим чтением и нашей записью. Кто-нибудь знает как это решить? Я не очень понимаю, как Laravel Pessimisti c Блокировка может помочь решить проблему. Мы используем MySql для нашей базы данных.