Consider the following example:
-- Transaction 1 -> T1
BEGIN;
SELECT * FROM table1 WHERE id = 1 FOR UPDATE;
SELECT * FROM table1 WHERE id = 2 FOR UPDATE;
UPDATE table1 set col1 = 'abcd' where id = 1;
COMMIT;
-- Transaction 2 -> T2
BEGIN;
SELECT * FROM table1 WHERE id = 2 FOR UPDATE;
SELECT * FROM table1 WHERE id = 1 FOR UPDATE;
UPDATE table1 set col1 = 'defg' where id = 2;
COMMIT;
In this example it's obvious that a deadlock could happen if both transaction are executed concurrently because if T1 locks row with id=1 and then T2 locks row with id=2, both T1 and T2 can not perform the second SELECT FOR UPDATE query and we have a deadlock.
Now, to solve this, we could just perform the SELECT FOR UPDATE queries in the same order:
-- Transaction 1 -> T1
BEGIN;
SELECT * FROM table1 WHERE id = 1 FOR UPDATE;
SELECT * FROM table1 WHERE id = 2 FOR UPDATE;
UPDATE table1 set col1 = 'abcd' where id = 1;
COMMIT;
-- Transaction 2 -> T2
BEGIN;
SELECT * FROM table1 WHERE id = 1 FOR UPDATE;
SELECT * FROM table1 WHERE id = 2 FOR UPDATE;
UPDATE table1 set col1 = 'defg' where id = 2;
COMMIT;
We solved the deadlock problem for this example.
Now, my question is, if you consider the following similar example:
-- Transaction 1 -> T1
BEGIN;
SELECT * FROM table1 WHERE id IN (1, 2) FOR UPDATE;
UPDATE table1 set col1 = 'abcd' where id = 1;
COMMIT;
-- Transaction 2 -> T2
BEGIN;
SELECT * FROM table1 WHERE id IN (1, 2) FOR UPDATE;
UPDATE table1 set col1 = 'defg' where id = 2;
COMMIT;
My questions:
Is it possible to have a deadlock in the last example?
In other terms: will Postgres lock all rows that match a WHERE condition atomically at the same time?
If yes, can we also say that the WHERE clause order does not count? So that in T1 we could use:
SELECT * FROM table1 WHERE id IN (1, 2) FOR UPDATE;
While in T2 we could use:
SELECT * FROM table1 WHERE id IN (2, 1) FOR UPDATE;
Without risking to cause a deadlock?