Какой уровень изоляции транзакций выбрать для операций перевода средств (списание и зачисление)?

«Какой уровень изоляции транзакций выбрать для операций перевода средств (списание и зачисление)?» — вопрос из категории Базы данных, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для финансовых операций, таких как перевод, требуется уровень изоляции, предотвращающий аномалии, которые могут привести к потере или "дублированию" денег.

Рекомендуемые уровни:

  1. REPEATABLE_READ — стандартный выбор. Гарантирует, что данные, прочитанные в транзакции (например, баланс счета), не изменятся другими транзакциями до её завершения. Предотвращает грязное и неповторяемое чтение.
  2. SERIALIZABLE — максимальная защита. Требуется в сценариях с экстремальной конкуренцией, когда необходимо также предотвратить фантомное чтение (например, если в логике есть агрегатные запросы по всем счетам). Снижает производительность.

Пример (Spring Boot с REPEATABLE_READ):

@Service
public class TransferService {
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void transfer(Long fromId, Long toId, BigDecimal amount) {
        Account from = accountRepository.findById(fromId).orElseThrow();
        Account to = accountRepository.findById(toId).orElseThrow();

        if (from.getBalance().compareTo(amount) < 0) {
            throw new InsufficientFundsException();
        }

        from.setBalance(from.getBalance().subtract(amount));
        to.setBalance(to.getBalance().add(amount));
        // Сохранение происходит при коммите транзакции
    }
}