Postgresql SERIAL работает по-другому?

У меня есть таблица postgres с серийным идентификатором.

id (serial) name age

Вставка обычно происходит из веб-приложения.

Я вставил две новые записи вручную, установив id как max (id) +1****

После этих 2 вставок, когда веб-приложение вставляет 2 записи, выдает ошибку дублированного ключа.

Всего за 2 записи. После этого все работает нормально.

Вопрос в том, почему моя ручная вставка не увеличивает серийный номер?

Отличаются ли автоинкремент и серийный номер?

Что мне здесь не хватает? MySQL или любой другой SQL имеют такую ​​же проблему?

3 ответа

Решение

Когда вы создаете serial или жеbigserial столбец, PostgreSQL на самом деле делает три вещи:

  1. Создает int или же bigint колонка.
  2. Создает последовательность (принадлежит столбцу) для генерации значений для столбца.
  3. Устанавливает значение столбца по умолчанию для последовательности nextval(),

Когда вы ВСТАВЛЯЕТЕ значение без указания serial столбец (или если вы явно указываете DEFAULT как его стоимость), nextval будет вызываться в последовательности:

  1. Вернуть следующее доступное значение для столбца.
  2. Увеличьте значение последовательности.

Если вы вручную указали значение не по умолчанию для serial столбец, то последовательность не будет обновлена ​​и nextval может вернуть значения, которые ваш serial колонка уже использует. Так что если вы делаете такие вещи, вам придется вручную исправить последовательность, вызвав nextval или жеsetval,

Также имейте в виду, что записи могут быть удалены, поэтому пробелы в serial столбцы следует ожидать, так что с помощью max(id) + 1 не очень хорошая идея, даже если бы не было проблем с параллелизмом.

Если вы используете serial или же bigserialЛучше всего позволить PostgreSQL позаботиться о назначении значений для вас и притвориться, что это непрозрачные числа, которые просто появляются в определенном порядке: не присваивайте их себе и не думайте о них иначе чем уникальность. Это правило применимо ко всей базе данных IMO.


Я не уверен, как MySQL auto_increment работает со всеми различными типами баз данных, но, возможно, хорошее руководство поможет.

Если вы хотите вставить запись в таблицу с serial столбец - просто пропустите его из запроса - он будет сгенерирован автоматически.

Или вы можете вставить значение по умолчанию с помощью чего-то вроде:

insert into your_table(id, val)
values (default, '123');

Третий вариант - брать значения из последовательной последовательности неправильно:

insert into your_table(id, val)
values (nextval(pg_get_serial_sequence('your_table','id')), '123');

Я вставил две новые записи вручную, установив id как max (id) + 1 * *

Этот подход абсолютно неверен и не будет работать ни в одной базе данных. До сих пор в MySQL это работало только по счастливой случайности.

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

Это также ужасно неэффективно.

Вот почему существуют последовательности, так что вы можете надежно получить идентификаторы при наличии одновременных вставок.

Просто используйте:

INSERT INTO my_table(data1, data2) VALUES ('a','b') RETURNING id;

или же:

INSERT INTO my_table(id, data1, data2) VALUES (DEFAULT, 'a','b') RETURNING id;

DEFAULT является специальным заполнителем, который сообщает базе данных получить значение по умолчанию для этого столбца из определения таблицы. По умолчанию nextval('my_table_id_seq'), поэтому будет вставлено следующее значение последовательности.

Поскольку вы задаете базовые вопросы о последовательностях, я рекомендую вам также учитывать, что последовательности не являются пропусками. Для последовательностей нормально иметь "дыры", где значения таблиц уходят в 1, 3, 4, 5, 9, 10, ... .

Другие вопросы по тегам