Sobes.tech
Senior

public class MoneyTransferService { /** * @param fromAccountId unique identifier of the user transferring funds * @param toAccountId unique identifier of the user receiving funds * @param amount transfer amount. Positive number */ @Transactional public void transferMoney(Long fromAccountId, Long toAccountId, BigDecimal amount) { if (amount.compareTo(BigDecimal.ZERO) <= 0) { throw new RuntimeException("Amount must be +"); } if (fromAccountId.equals(toAccountId)) { throw new RuntimeException("Account can't be the same"); } Long firstId = Math.min(fromAccountId, toAccountId); Long secondId = Math.max(fromAccountId, toAccountId); Account first = accountRepository.findByIdForUpdate(firstId) .orElseThrow(() -> new RuntimeException("Account not found")); Account second = accountRepository.findByIdForUpdate(secondId) .orElseThrow(() -> new RuntimeException("Account not found")); Account from = fromAccountId.equals(firstId) ? first : second; Account to = fromAccountId.equals(firstId) ? second : first; if (from.getBalance().compareTo(amount) < 0) { throw new RuntimeException("Balance is less 0"); } from.setBalance(from.getBalance().subtract(amount)); to.setBalance(from.getBalance().add(amount)); accountRepository.save(to); accountRepository.save(from); } } @Entity @Data public class Account { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private BigDecimal balance; }

sobes.tech AI

Answer from AI

The provided code has several important points and one critical error:

  1. Checking amount > 0 and that fromAccountId != toAccountId are correct validations.
  2. To prevent deadlocks during concurrent transfers, ordered locking of accounts via findByIdForUpdate is a good practice.
  3. The error in the balance update logic:
from.setBalance(from.getBalance().subtract(amount));
 to.setBalance(from.getBalance().add(amount));

Here, after subtracting amount from from.getBalance(), the new balance for to is calculated using the already decreased from balance, but it should add amount to the current to balance.

Correct:

 to.setBalance(to.getBalance().add(amount));
  1. Saving accounts via accountRepository.save() is correct.

In summary: fix the recipient's balance update, otherwise money will be deducted but not credited.


Example of the corrected section:

from.setBalance(from.getBalance().subtract(amount));
 to.setBalance(to.getBalance().add(amount));
public class MoneyTransferService { /** * @param… - sobes.tech