Eu tenho duas mesas:
create table name
(
id bigserial primary key,
name text not null
);
create table name_score
(
id bigserial primary key,
name text not null,
score bigint default 1 not null
);
e um índice exclusivo na tabela name_score:
create unique index name_score_name_uindex
on name_score(name);
e uma função de gatilho:
create or replace function add_name_func() returns trigger as
$name_count$
DECLARE
new_name text;
begin
new_name := NEW.name;
insert into name_score(name)
values (new_name)
on conflict (name) do update set score=(select score from name_score where name = new_name for update) + 1;
return null;
end;
$name_count$ language plpgsql;
create trigger name_score_trigger
after insert
on name
for each row
execute procedure add_name_func();
e agora, quando insiro 3 linhas pela primeira vez usando muti thread, obtive:
ERROR: null value in column "score" of relation "name_score" violates not-null constraint
Detail: Failing row contains (273, "test", null).
Where: SQL statement "insert into name_score(name)
values (new_name)
on conflict (name) do update set score=(select score from name_score where name = new_name for update) + 1"
PL/pgSQL function add_name_func() line 7 at SQL statement
e há uma linha inserida com sucesso no banco de dados com pontuação 1
depois disso, essa função às vezes apresenta pontuação errada.
Eu tentei lock table e está funcionando, estou confundindo isso.
E eu quero saber se existe alguma maneira melhor de resolver isso?
Muito obrigado por ler minha pergunta.
O problema é a subconsulta que você está usando no
UPDATE
branch. O problema desaparecerá se você escrevercontanto que você esteja usando o
READ COMMITTED
nível de isolamento de transação padrão. Os bloqueios de linha obtidos peloUPDATE
serializarão as atualizações, e a segunda operação verá o resultado da primeira, para que não haja condições de corrida.