问题
In my postgresql DB, I have a table "my_table" with primary key on columns (a, b).
I wrote the query below for inserts into this table which ensures that the primary key constraint is never violated.
INSERT INTO my_table(a, b, c, d, e, f)
(SELECT 'a1',
'b1',
'c1',
1442849052013,
1,
FALSE
FROM
(SELECT 'a1'::VARCHAR(100) AS a,
'b1'::VARCHAR(50) AS b) AS new_fields
LEFT OUTER JOIN my_table AS old_fields ON (new_fields.a = old_fields.a
AND new_fields.b = old_fields.b)
WHERE old_fields.a IS NULL);
As multiple such queries get fired by concurrently running threads, I sometimes get
PSQLException: duplicate key value violates unique constraint "my_table_pkey". Detail: Key (a, b)=(a1, b1) already exists.
I am unable to understand that how can this query lead to the specified error condition as this query inserts into "my_table" only if its primary key columns are missing and that this condition is being checked within the same query.
If this is a valid scenario, doesn't this mean that query execution in postgreSQL is not atomic ?
Can somebody please explain...
Here, Select For Update syntax will not work as well because Select For Update takes a lock on selected row and I want to insert a row if it not already exists.
回答1:
The default transaction isolation level in PostgreSQL, read committed, does not see any uncommitted data.
Thus, if another uncommitted transaction has inserted ('a1', 'b1'), the other transactions cannot see it.
However the presence of constraints will guarantee that another transaction's attempted insert of ('a1', 'b1') cannot complete until the first transaction has either rolled back (and your transaction can complete successfully), or committed (and your transaction will fail with a constraint violation).
A complete explanation is in the documentation.
来源:https://stackoverflow.com/questions/32700837/isnt-postgresql-single-query-execution-atomic