Data Upsert
title: Use UPSERT for Insert-or-Update Operations impact: MEDIUM impactDescription: Atomic operation, eliminates race conditions tags: upsert, on-conflict, insert, update
Section titled “title: Use UPSERT for Insert-or-Update Operations impact: MEDIUM impactDescription: Atomic operation, eliminates race conditions tags: upsert, on-conflict, insert, update”Use UPSERT for Insert-or-Update Operations
Section titled “Use UPSERT for Insert-or-Update Operations”Using separate SELECT-then-INSERT/UPDATE creates race conditions. Use INSERT … ON CONFLICT for atomic upserts.
Incorrect (check-then-insert race condition):
-- Race condition: two requests check simultaneouslyselect * from settings where user_id = 123 and key = 'theme';-- Both find nothing
-- Both try to insertinsert into settings (user_id, key, value) values (123, 'theme', 'dark');-- One succeeds, one fails with duplicate key error!Correct (atomic UPSERT):
-- Single atomic operationinsert into settings (user_id, key, value)values (123, 'theme', 'dark')on conflict (user_id, key)do update set value = excluded.value, updated_at = now();
-- Returns the inserted/updated rowinsert into settings (user_id, key, value)values (123, 'theme', 'dark')on conflict (user_id, key)do update set value = excluded.valuereturning *;Insert-or-ignore pattern:
-- Insert only if not exists (no update)insert into page_views (page_id, user_id)values (1, 123)on conflict (page_id, user_id) do nothing;Reference: INSERT ON CONFLICT