клиентский код пытается заселектить, обновить или вставить данные. В таблице уникальный индекс на эти данные. При многопоточном доступе и select for update проскакивает вставка одних и тех же данных. Естественно падает по ограничению целостности. Можно как-то заблокироваться, но не на всей таблице?
Может это нормально?
Нужно заблокироваться на строке и не селектить, пока другая транзакция не отпустит.
Вариант 1. Использовать везде SERIALIZABLE (прочитав в документации, как именно), и получить надёжное решение проблемы. Вариант 2. Прочитать и осознать (попробовать на примерах) всю документацию про изоляцию в PostgreSQL (про serializable можно при этом не читать), понять механизмы, подумать о возможных взаимодействиях в конкретном случае, придумать и протестировать подход... и, если Вы хоть что-то сделаете неправильно, то проблема просто будет появляться значительно реже. ;) Для варианта 2 есть набор паттернов, которые часто помогают, а иногда — нет, если что.
Непонятно, в чем проблема? Вы делаете select for update, так? Это значит, что запрос заблокируется, если часть строк, которые вы выбираете, взяты другим select for update. Поэтому тут 2 варианта: 1) вы выбираете разные строки двумя транзакциями, в которых делается select for update, и изменяете их на одни и те же строки, поэтому получаете ошибку 2) либо просто делаете select for update и изменяете данные на те, которые уже вставлены. Выглядит так, что проблема либо в логике приложения, либо в том, что вы не хотите обрабатывать ошибки.
Не совсем. Для примера пытаюсь в несколько потоков в одной транзакции сделать select for update и если нет строки, то вставить. Ожидал, что будет работать блокировка, но по факту проскакивают попытки вставить одно и то же в разных транзакциях.
А unique constraint над суррогатным ключем или над чем-то существенным?
В синтетическом примере на все поля, кроме ключа.
Можете попробовать уровень изоляции serializable поставить, но его нужно будет включать вообще для всех транзакции. Тогда у вас эта ошибка скорей всего уйдёт и будет другая ошибка - ошибка сериализации данных. Более детально тут невозможно что-то подсказать, не поняв логику работы.
Обсуждают сегодня