2011-01-13 4 views
3

Возможно, это очень маловероятно для меня из-за проблем, которые могут возникнуть, но я решил, что я все равно задам вопрос ...Может ли автоинкрементный идентификатор когда-либо изменяться со значения средней транзакции при совершении?

Представьте себе транзакцию, в которой задействован идентификатор автоинкремента, и значение назначены. До COMMIT задействованный код кэширует копию назначенного идентификатора для последующей ссылки. Затем транзакция совершается.

Предполагая отсутствие прямого вмешательства клиента (удаление или изменение записи), есть ли какая-либо база данных или ситуация, которая когда-либо автоматически изменила бы значение идентификатора сразу после COMMIT, чтобы неверный кешированный идентификатор? Всегда ли безопасно кэшировать ID-транзакцию?

Один гипотетический случай, когда я могу себе представить, что это происходит, если какая-то реализация РСУБД необъяснимо решила, что необходимо иметь бесцельные и зависящие от времени значения автоинкремента (так как я вижу много примеров людей, желающих этого). В этом гипотетическом случае я могу представить, что некоторые магические перетасовки идентификаторов могут быть сделаны, чтобы заполнить пробелы, вызванные откатами после ID-присвоения в другой транзакции (или другой зазор пробела). Это приведет к аннулированию кэшированного значения.

Кто-нибудь знает о такой реализации или другом кеш-убийце?

ответ

4

Реализация генерируемых значений идентификатора обычно включает в себя увеличение значения счетчика в короткой атомной операции. Это значение затем используется для запрашивающей транзакции, и даже если эта транзакция будет откат, зарезервированное значение никогда не будет возвращено в пул свободных значений. Поэтому в этом свете я не думаю, что описанная ситуация очень вероятна. Кроме того, в программах типа pl/sql вам действительно нужно, чтобы сгенерированное значение было правильным, чтобы вставить другие зависимые строки в дочерние таблицы.

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

+0

+1 Хотя я думаю, что вы абсолютно правы в использовании автоначислений ... технически они по определению больше не являются суррогатным ключом, если вы намерены использовать значение для определения порядка создания: D – Matthew

+0

В 'InnoDB', механизм транзакционного хранения, используемый 'MySQL', автоинкрементные идентификаторы могут быть повторно использованы. Если запись с наивысшим «id» удаляется и сервер перезапускается, следующая вставка в таблицу приведет к тому же «id». – Quassnoi

1

PostgreSQL поддерживает DEFERRED триггеры, которые могут изменять данные на COMMIT.

CREATE TABLE test_autoinc (id BIGSERIAL); 

CREATE TABLE test_other (id BIGSERIAL); 

CREATE FUNCTION prc_update_autoinc() 
RETURNS TRIGGER 
AS 
$$ 
BEGIN 
     UPDATE test_autoinc 
     SET  id = id + 10; 
     RETURN NEW; 
END; 
$$ 
LANGUAGE 'plpgsql'; 

CREATE CONSTRAINT TRIGGER 
     trg_other_ai 
AFTER INSERT 
ON  test_other 
DEFERRABLE 
INITIALLY DEFERRED 
FOR EACH ROW 
EXECUTE PROCEDURE prc_update_autoinc(); 

BEGIN TRANSACTION; 

INSERT 
INTO test_autoinc 
DEFAULT VALUES; 

INSERT 
INTO test_other 
DEFAULT VALUES; 

SELECT * 
FROM test_autoinc; 

COMMIT; 

SELECT * 
FROM test_autoinc; 

Первый SELECT (прямо перед COMMIT) возвращает 1, второй (сразу же после COMMIT) возвращает 11.

+0

Thx ... интересный пример. +1 для показа случая, когда это может произойти, хотя и с прямым вмешательством. – Russ