Let The Write Be The Check

A wallet row holds balance = 100. Two withdrawal requests for 80 arrive at the same instant. Both run this single statement, in separate transactions, on PostgreSQL at the default READ COMMITTED isolation.

UPDATE wallets
   SET balance = balance - 80
 WHERE id = 7
   AND balance >= 80
RETURNING balance;

What do the two statements return?

A

One returns a row with balance = 20. The other aborts with a serialization failure and must be retried by the application.

B

One returns a row with balance = 20. The other blocks, then updates zero rows and returns nothing.

C

Both return a row. The balances are 20 and -60.

D

Both return a row with balance = 20, because each transaction reads the row as it was when the statement started.