Eu tenho o seguinte código:
create table users (id serial primary key, comments_counter integer default 0);
create table comments (id serial primary key, user_id integer references users(id) not null)
create or replace function users_comments_counter()
returns trigger as $$
begin
update users set comments_counter = comments_counter + 1
where id = NEW.user_id;
return null;
end;
$$ language plpgsql;
create trigger users_comments_counter_trg
after insert on comments
for each row execute procedure users_comments_counter();
É possível que a inserção de uma linha na comments
tabela seja lançada could not serialize access due to concurrent update
?
Ou talvez em outras palavras: é possível usar tal contador (com QUALQUER um dos níveis de isolamento da transação), evitando situações em que "nova tentativa" (devido ao erro de serialização da transação) é necessária e a consistência dos dados é garantida (o contador se comportará conforme o esperado - irá ser incrementado somente se a linha de comentário for inserida com sucesso).
As ações executadas no gatilho fazem parte da transação que o dispara. Isso significa que o incremento do contador acontecerá apenas se toda a transação (ou a subtransação definida por a
SAVEPOINT
) for bem-sucedida. Desta forma podemos dizer que a trigger acima irá incrementar o contador atomicamente, do ponto de vista doINSERT INTO comments
comando.Se isso é tudo que você tem dentro da transação (
INSERT
e do incremento), você está protegido contra problemas de simultaneidade e o nível de isolamento padrão (READ COMMITTED
) é suficiente.Além disso, dependendo de como o
INSERT
é emitido, você pode até poupar o gatilho, o que economizaria algumas despesas gerais. Para fazer isso, as seguintes condições devem ser atendidas:INSERT INTO comments
eUPDATE users
em uma transação