Estou tendo dificuldade em descobrir como implementar exatamente uma função 'inserir se não for encontrado'. Considere o seguinte.
Temos uma tabela chamada artist
com 2 colunas, (name, id)
onde name
é o único e id
é uma chave primária serial. É um exemplo artificial, mas ilustra o meu problema:
SESSION A SESSION B
1. SELECT id FROM artist
WHERE name = 'Bob';
2. INSERT INTO artist (name)
VALUES ('Bob')
3. INSERT INTO artist (name)
VALUES ('Bob')
4. code that users 'Bob'
(e.g., a FK to Bob's ID)
5. ??? Bob already exists, but we
can't find it
4. COMMIT
A sessão B começa tentando encontrar um artist
Bob chamado, que falha. No entanto, a Sessão A cria Bob. A sessão B tenta inserir um artista chamado Bob, mas falha porque viola a chave primária. Mas aqui está a parte que não entendo - se eu alterar a operação 3 para ser um select na artist
tabela ainda está vazia! Isso ocorre porque estou usando o nível de isolamento serializável, mas como posso lidar com esse caso?
Parece que a única opção que tenho é abortar toda a transação e tentar novamente. Se for esse o caso, devo lançar minha própria exceção 'não foi possível serializar', indicando que o aplicativo deve tentar novamente? Eu já queria esse 'find-or-insert' em uma função plpgsql, onde eu faria INSERT
, e se isso falhasse SELECT
, mas parece impossível encontrar a linha conflitante ...