Если для столбца имени существует уникальное ограничение, каждый insert
получает блокировку. Любой поток, который попытается вставить его во второй раз одновременно, будет ожидать, пока 1-й insert
не будет выполнен успешно или завершится неудачно (передача или откат tx).
Если 1-я транзакция прошла успешно, 2-я транзакция завершится с ошибкой уникального ключа. Тогда вы знаете, что оно уже существует.
Если в транзакции есть одна вставка, то это ок. Если в транзакции используется более 1 вставки, вы можете зайти в тупик.
Каждый поток передаст имя строки -
где это имя существует в таблице,
база данных должна вернуть идентификатор для
строка, где имя не
уже существует, имя должно быть
вставлен и идентификатор возвращен.
В общем, алгоритм такой:
1 read row with name
2.1 if found, return row id
2.2 if not found, attempt to insert
2.2.1 if insert succeeds, return new row id
2.2.2 if insert fails with unique constraint violation
2.2.2.1 read row with name
2.2.2.2 read should succeed this time, so return row id
Поскольку в уникальном индексе может быть высокая конкуренция , insert
может блокироваться в течение некоторого времени. В этом случае транзакция может истечь . Проведите стресс-тест и настройте конфигурацию, пока она не будет корректно работать с вашей нагрузкой.
Кроме того, вы должны проверить, если вы получаете уникальное нарушение ограничения исключение или какое-либо другое исключение.
И снова, это работает, только если в транзакции есть одна вставка, в противном случае может тупик .
Кроме того, вы можете попробовать прочитать строку на шаге 1 с помощью «select * for update
». В этом случае он ожидает, пока одновременная вставка не завершится или не завершится успешно. Это может немного уменьшить количество ошибок на шаге 2.2.2 из-за конфликта в индексе.