Go + pgx pool + Postgres, default Read Committed, one transaction per withdrawal. Balance 1000, daily_limit 50, 20 goroutines each withdrawing 10. I expect 5 successes and get 7, 8 or 9. sum(amount) for today ends up 70 to 90. With MaxConns=1 it's exactly 5.
The balance guard looks fine. With balance 15, one wins and the rest just get zero rows from the UPDATE. They don't block or error.
INSERT INTO withdrawals (account_id, amount)
SELECT $1, $2
WHERE (SELECT coalesce(sum(amount), 0)
FROM withdrawals
WHERE account_id = $1 AND day = current_date) + $2
<= (SELECT daily_limit FROM accounts WHERE id = $1)
UPDATE accounts
SET balance = balance - $2
WHERE id = $1 AND balance >= $2
Does Postgres recheck the WHERE for the INSERT ... SELECT the way it does for the UPDATE? Or are these two separate things? Logging shows nothing odd, and -race is clean.
Isolation docs I'm reading: https://www.postgresql.org/docs/current/transaction-iso.html