Lost Update in a Transfer Transaction
A money-transfer function wrapped in a transaction still loses updates under concurrency — find out why.
Codejavascript
async function withdraw(client, accountId, amount) {
await client.query('BEGIN'); // default READ COMMITTED
const { rows } = await client.query(
'SELECT balance FROM accounts WHERE id = $1',
[accountId]
);
const current = rows[0].balance;
if (current < amount) {
await client.query('ROLLBACK');
throw new Error('Insufficient funds');
}
const newBalance = current - amount;
await client.query(
'UPDATE accounts SET balance = $1 WHERE id = $2',
[newBalance, accountId]
);
await client.query('COMMIT');
}Two concurrent calls to withdraw() can leave the balance too high (a lost update). Why, and how should it be fixed?