Вставка PostgreSQL по первичному ключу завершается с ошибкой даже на уровне сериализации - PullRequest
3 голосов
/ 20 мая 2010

Я пытаюсь вставить или обновить данные в базе данных PostgreSQL. Простейший случай - это пара ключ-значение (фактические данные более сложные, но это наименьший ясный пример)

Когда вы устанавливаете значение, я бы хотел, чтобы оно вставлялось, если ключа там нет, в противном случае обновите. К сожалению, у Postgres нет оператора вставки или обновления, поэтому я должен сам подражать ему.

Я работал с идеей: SELECT выяснить, существует ли ключ, и затем запустить соответствующий INSERT или UPDATE. Теперь ясно, что это должно быть в транзакции, иначе может случиться что-то плохое.

Однако это работает не совсем так, как мне хотелось бы - я понимаю, что существуют ограничения для сериализуемых транзакций, но я не уверен, как обойти эту проблему.

Вот ситуация -

ab: => set transaction isolation level serializable;
a:  => select count(1) from table where id=1; --> 0
b:  => select count(1) from table where id=1; --> 0
a:  => insert into table values(1); --> 1
b:  => insert into table values(1); --> 
    ERROR:  duplicate key value violates unique constraint "serial_test_pkey"

Теперь я ожидаю, что он выдаст обычное сообщение «не удалось зафиксировать из-за одновременного обновления», но я предполагаю, что поскольку вставки - это разные «строки», этого не происходит.

Есть ли простой способ обойти это?

1 Ответ

2 голосов
/ 12 июня 2011

До Postgres 9.1 были проблемы с изоляцией:

запрос на сериализуемую изоляцию гарантировал только то, что один снимок MVCC будет использоваться для всей транзакции, что допускало определенные задокументированные аномалии.

Возможно, вы сталкиваетесь с этими "аномалиями".

Вы можете попробовать ВЫБРАТЬ… ДЛЯ ОБНОВЛЕНИЯ при проверке, существует ли строка.

В качестве альтернативы, LOCK TABLE самостоятельно.

Если вы пытаетесь реализовать UPSERT, то несколько более надежным (или, скорее, менее ненадежным) способом является сначала попытка ОБНОВИТЬ, проверить количество затронутых строк, а затем попробовать ВСТАВИТЬ, если строки не были обновлены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...