コミット時に自動インクリメント ID がトランザクション中の値から変更されることはありますか?
-
10-10-2019 - |
質問
問題が発生する可能性があるため、このようなことが起こる可能性は非常に低いように思えますが、とにかく質問してみようと思いました...
自動インクリメント ID が関係し、値が割り当てられるトランザクションを想像してください。COMMIT の前に、関連するコードは、後で参照できるように、割り当てられた ID のコピーをキャッシュします。その後、トランザクションがコミットされます。
クライアントの直接の介入 (レコードの削除または変更) がないと仮定すると、COMMIT 直後に ID 値が自動的に変更され、キャッシュされた ID が不正確になるようなデータベースまたは状況はありますか?トランザクション中に ID をキャッシュしても常に安全ですか?
これが起こると私が想像できる仮説の 1 つは、RDBMS 実装によってギャップのない時間依存の自動インクリメント値が必要であると不可解に決定された場合です (これを望んでいる人々の例をたくさん見ているので)。この仮定のケースでは、別のトランザクション (または他のギャップの原因) での ID 割り当て後のロールバックによって生じたギャップを埋めるために、魔法のような ID のシャッフルが行われる可能性があると想像できます。これにより、キャッシュされた値が無効になります。
そのような実装、または他のキャッシュキラーを知っている人はいますか?
解決
生成された ID 値の実装には、通常、短いアトミック操作でカウンター値をインクリメントすることが含まれます。この値は、要求元のトランザクションによって使用され、そのトランザクションがロールバックしたとしても、予約された値が空き値のプールに返されることはありません。したがって、この観点からすると、ここで説明されている状況が起こる可能性は非常に低いと思います。また、pl/sql タイプのプログラムでは、他の依存行を子テーブルに挿入するために、生成された値が正しい必要があります。
時間順のギャップのない ID 値が必要な場合は、次のようになります。自動インクリメント/代理キーの唯一の目的は、行の人為的な識別を作成することです。これは、行が作成される順序の決定とは何の関係もありません。これを行うには、作成タイムスタンプを使用するなど、はるかに優れた方法があります。
他のヒント
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
, 、2番目(直後) COMMIT
) 戻り値 11
.