Senior
PostgreSQL task: ensure balance consistency and protection against negative balance with 10 concurrent withdrawal requests.
sobes.tech AI
Answer from AI
To ensure balance consistency and protection against negative balances during concurrent withdrawals in PostgreSQL, transactions with row locking and balance checks within the transaction can be used.
An example approach:
- Start a transaction.
- Perform
SELECT ... FOR UPDATEon the relevant balance record to lock the row for other transactions. - Check if the balance is sufficient for withdrawal.
- If sufficient, update the balance.
- Commit the transaction.
This guarantees that parallel requests will process balance updates sequentially, preventing negative values.
Example SQL inside Java (JDBC):
connection.setAutoCommit(false);
try (PreparedStatement psSelect = connection.prepareStatement(
"SELECT balance FROM accounts WHERE id = ? FOR UPDATE")) {
psSelect.setInt(1, accountId);
ResultSet rs = psSelect.executeQuery();
if (!rs.next()) {
throw new RuntimeException("Account not found");
}
BigDecimal balance = rs.getBigDecimal("balance");
if (balance.compareTo(amountToWithdraw) < 0) {
throw new RuntimeException("Insufficient funds");
}
try (PreparedStatement psUpdate = connection.prepareStatement(
"UPDATE accounts SET balance = balance - ? WHERE id = ?")) {
psUpdate.setBigDecimal(1, amountToWithdraw);
psUpdate.setInt(2, accountId);
psUpdate.executeUpdate();
}
connection.commit();
} catch (Exception e) {
connection.rollback();
throw e;
} finally {
connection.setAutoCommit(true);
}
This approach prevents race conditions and guarantees that the balance will not go negative even with 10 or more concurrent requests.