Ho questa query che tenta di aggiungere righe alla tabella balances
se non esiste una riga corrispondente nella tabella totals
. La query viene eseguita in una transazione utilizzando il livello di isolamento predefinito su PostgreSQL.Una query INSERT-SELECT può essere soggetta a condizioni di competizione?
INSERT INTO balances (account_id, currency, amount)
SELECT t.account_id, t.currency, 0
FROM balances AS b
RIGHT OUTER JOIN totals USING (account_id, currency) AS t
WHERE b.id IS NULL
Ho un vincolo UNIQUE
su balances (accountId, currency)
. Sono preoccupato che entrerò in una situazione di condizione di competizione che porterà a duplicare gli errori delle chiavi se più sessioni eseguono questa query contemporaneamente. Ho visto molte domande su questo argomento, ma sembrano coinvolgere sia sottoquery, più query o funzioni pgSQL.
Poiché non sto utilizzando nessuno di quelli nella mia domanda, è libero da condizioni di gara? Se non è come posso ripararlo?
Sì, è ancora possibile ottenere errori di chiave duplicati. Per lo stesso motivo puoi ottenerlo quando due sessioni eseguono la stessa istruzione 'insert' con la stessa clausola' values'. L'istruzione vede uno stato consistente del database mentre è in esecuzione, quindi non vedrà nessuna nuova riga anche se sono impegnate durante l'esecuzione dell'istruzione. –
Un loop di funzione plpgsql in caso di violazione di una chiave duplicata può gestire la condizione di competizione sul lato server e al livello di isolamento predefinito, che è * sicuro * tipicamente * più economico *. L'app non deve preoccuparsi di tentativi: http://stackoverflow.com/questions/15939902/is-select-or-insert-in-a-function-prone-to-race-conditions/15950324#15950324 –