Sobes.tech
Senior
41

PostgreSQL-Aufgabe: Sicherstellung der Konsistenz des Kontostands und Schutz vor negativem Saldo bei 10 gleichzeitigen Abbuchungsanfragen

Unternehmen wurden gefragt
РТК ИТ

Antwort von AI

sobes.tech KI

Для обеспечения консистентности баланса и защиты от отрицательного баланса при одновременных списаниях в PostgreSQL можно использовать транзакции с блокировкой строк и проверкой баланса внутри транзакции.

Пример подхода:

  1. Начинаем транзакцию.
  2. Выполняем SELECT ... FOR UPDATE по нужной записи баланса, чтобы заблокировать строку для других транзакций.
  3. Проверяем, что баланс достаточен для списания.
  4. Если достаточно, обновляем баланс.
  5. Фиксируем транзакцию.

Это гарантирует, что параллельные запросы будут последовательно обрабатывать обновление баланса, не допуская отрицательного значения.

Пример 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 и более одновременных запросах.