Назад к вопросам
Senior
3
Задача по PostgreSQL: обеспечить консистентность баланса и защиту от отрицательного баланса при 10 одновременных запросах на списание
Компании, где спрашивали
РТК ИТ
Ответ от нейросети
sobes.tech AI
Для обеспечения консистентности баланса и защиты от отрицательного баланса при одновременных списаниях в PostgreSQL можно использовать транзакции с блокировкой строк и проверкой баланса внутри транзакции.
Пример подхода:
- Начинаем транзакцию.
- Выполняем
SELECT ... FOR UPDATEпо нужной записи баланса, чтобы заблокировать строку для других транзакций. - Проверяем, что баланс достаточен для списания.
- Если достаточно, обновляем баланс.
- Фиксируем транзакцию.
Это гарантирует, что параллельные запросы будут последовательно обрабатывать обновление баланса, не допуская отрицательного значения.
Пример SQL внутри 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);
}
Такой подход предотвращает гонки и гарантирует, что баланс не уйдет в отрицательное значение даже при 10 и более одновременных запросах.