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 вашей СУБД.

MySQL:

SELECT GET_LOCK('tablename',10);
SELECT RELEASE_LOCK('tablename');

Pqsql:

LOCK TABLE tablename IN SHARE ROW EXCLUSIVE MODE;

Имейте в виду, что блокировка Pgsql работает только внутри транзакции.

Мое решение этой проблемы:

  • Unique Validator не работает в этом случае
  • Я использую INSERT IGNORE игнорировать новую запись, если существует. Это работает очень быстро.
Другие вопросы по тегам