Yii2 уникальный валидатор не работает, когда вставка так быстро
Я использую модель ActiveRecord для сохранения данных.
Unique Validator
работает очень идеально. Но когда я так быстро вставляю данные, они перестают работать идеально. В какой-то запрос я получаю сообщение об ошибке, которое не может поймать Yii
Нарушение ограничения целостности - yii\db\IntegrityException SQLSTATE[23000]: Нарушение ограничения целостности: 1062 Повторяющаяся запись '***'...
Есть ли у нас какое-либо решение для решения этой проблемы без добавления другого сервиса?
Спасибо!
2 ответа
Подводя итоги в комментариях...
Скорее всего, вам нужно вручную заблокировать таблицу перед проверкой и снять блокировку после нее. Yii2 предоставляет механизм оптимистичных замков, но он не подходит для вашего случая. Оптимистичные блокировки поддерживаются только внутри методов update и delete:
Оптимистическая блокировка поддерживается только при обновлении или удалении существующей строки данных с использованием yii\db\ActiveRecord::update() или yii\db\ActiveRecord::delete() соответственно.
Более того, что делает оптимистическую блокировку, так это просто вызывает исключение, когда обновление завершается неудачно из-за конфликта (без фактической блокировки таблицы).
Решение будет зависеть от вашего движка БД. Yii2 предоставляет мьютексный механизм для ручной блокировки. Из коробки Yii2 поддерживал Mysql и Postgres. См. Описание компонентов на следующих страницах руководства Yii2:
Итак, после того, как вы настроили свой мьютекс в конфиге (пример для pgsql из официального руководства):
[
'components' => [
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'pgsql:host=127.0.0.1;dbname=demo',
]
'mutex' => [
'class' => 'yii\mutex\PgsqlMutex',
],
],
]
вам нужно сделать что-то подобное
\Yii::$app->mutex->acquireLock($lockingObject);
// validate uniqueness and save
\Yii::$app->mutex->releaseLock($lockingObject);
Или, конечно, вы можете сделать это вручную, используя синтаксис SQL вашей СУБД.
SELECT GET_LOCK('tablename',10);
SELECT RELEASE_LOCK('tablename');
LOCK TABLE tablename IN SHARE ROW EXCLUSIVE MODE;
Имейте в виду, что блокировка Pgsql работает только внутри транзакции.
Мое решение этой проблемы:
Unique Validator
не работает в этом случае- Я использую
INSERT IGNORE
игнорировать новую запись, если существует. Это работает очень быстро.