Spot the bug
Two concurrent transfers in opposite directions sometimes deadlock. Which line causes it?
import psycopgfrom psycopg.rows import TupleRowdef transfer(conn: psycopg.Connection[TupleRow], src: int, dst: int, amount: int) -> None:with conn.transaction():conn.execute("UPDATE accounts SET balance = balance - %s WHERE id = %s",(amount, src),)conn.execute("UPDATE accounts SET balance = balance + %s WHERE id = %s",(amount, dst),)
Hint 1 of 1
Compare the lock order of transfer(1, 2) and transfer(2, 1).
Choose an answer, then open Show answer below to check it.
Show answer
- Answer: line 9
conn.execute(
Each transfer locks its source row first. transfer(1, 2) locks 1 then wants 2; transfer(2, 1) locks 2 then wants 1: a cycle. Lock both rows in id order first, e.g. SELECT ... WHERE id IN (%s, %s) ORDER BY id FOR UPDATE.