Can an autoincrement ID ever change from the mid-transaction value upon commit?
The possibility of this happening seems extremely unlikely to me because of the problems it could cause, but I figured I'd ask the question anyway...
Imagine a transaction where an autoincrement ID is involved and a value is assigned. Prior to COMMIT, the involved code caches a copy of the assigned ID for later reference. Then the transaction is committed.
Assuming no direct client intervention (deletion or altering of the record), is there any database or situation that would ever automatically alter the ID value immediately upon COMMIT, making the cached ID incorrect? Is it always safe to cache the ID mid-transaction?
One hypothetical case where I can imagine this happening is if some RDBMS implementation inexplicably decided it was necessary to have gapless and time-dependent autoincrement values (since I see many examples of people wanting this). In this hypothetical case, I can imagine some magical shuffling of IDs might be done to f开发者_开发问答ill in gaps caused by post-ID-assignment rollbacks in another transaction (or other gap causer). This would invalidate the cached value.
Anyone know of such an implementation, or other cache killer?
The implementation of generated id values usually involves incrementing a counter value in a short atomic operation. This value is then used for by the requesting transaction and even if that transaction would roll back, the reserved value will never be given back to the pool of free values. So in this light I dont think the situation described is very likely. Also, in pl/sql type of programs you really do need the generated value to be right in order to insert other dependent rows to child tables.
As for the people who are wanting time-ordered gapless id values: the sole purpose of autoincrement/surrogate key is to create an artificial identification for a row. It should have nothing to do with determining the order in which rows were created. There are far better ways to do this, for example using a creation timestamp.
PostgreSQL
supports DEFERRED
triggers which can alter the data on 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;
The first SELECT
(right before the COMMIT
) returns 1
, the second one (right after the COMMIT
) returns 11
.
精彩评论