Являются ли триггеры AFTER UPDATE атомарными?
Я хотел бы вставлять строку в таблицу «истории» всякий раз, когда исходная строка изменяется (обновляется). Я хотел бы использовать идентификатор исходной строки в качествеFOREIGN KEY
дляhistory
стол. Но этот идентификатор может измениться.
Посмотрите на пример ниже:
CREATE TABLE account
(
id BIGSERIAL PRIMARY KEY,
username TEXT NOT NULL,
balance BIGINT NOT NULL DEFAULT 0
);
CREATE TABLE account_balance_change
(
account_id BIGINT NOT NULL,
diff BIGINT NOT NULL,
ts TIMESTAMPTZ NOT NULL,
FOREIGN KEY (account_id) REFERENCES account (id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE FUNCTION dump_diff()
RETURNS TRIGGER
LANGUAGE plpython3u
AS
$$
from datetime import datetime
now = datetime.now()
old = TD['old']
new = TD['new']
diff = new['balance'] - old['balance']
query = f"""
INSERT INTO
account_balance_change
(
account_id,
diff,
ts
)
VALUES
($1, $2, $3)
;
"""
# i know it should be cached, but for the sake of simplicity...
stmt = plpy.prepare(query, ["BIGINT", "BIGINT", "TIMESTAMPTZ"])
# see how it's using new['id'], so that there can be no mistake in the new record
stmt.execute([new['id'], diff, now])
$$;
CREATE TRIGGER after_account_balance_update_trigger
AFTER UPDATE OF balance ON account
FOR EACH ROW
EXECUTE FUNCTION
store_diff()
;
Ожидаемое поведение заключается в том, что каждый раз, когда кто-тоaccount
'sbalance
стоимости, балансовая разница, а также дата и время такого изменения будут записаны вaccount_balance_change
стол.
Но в соответствии с системными требованиями идентификатор может измениться или быть удален.
Следовательно, можем ли мы с уверенностью предположить, что это не изменится во время выполнения этого триггера? Можем ли мы на самом деле оказаться в месте, где возникло состояние гонки иnew['id']
больше нет в базе данных?
По сути
, все сводится к одному вопросу:AFTER UPDATE
TRIGGER
является атомарным по отношению к
UPDATE
операции, к которой они принадлежат ?