I am trying to create an API for transferring funds i.e withdrawal and deposit. I performed the transaction using @Transactional Annotation. But there are certain criteria i.e if bank account number doesn't exist that should through an Runtime exception. I will attach the code within. Now, when transferBalanceMethod is called and if depositor bank Account doesn't exist than amount that is withdrawn should also be rolled back. But that isn't happening. Means when fund transfer occurs from account A to Account B of 1000 rupees then if an exception occurs in B's deposition then the withdraw in A Account should also be withdrawn. I tried @Transactional annotation and also rollbackFor property of the Exception class too I tried to add @Transaction annotation for deposit and withdraw method too but that we use the same transaction because we use propogation Required**
Model Class//This is the Model Class
//All Imports
@Entity
public class BankAccount {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Integer id;
@Column(name = "bankAccountNumber", nullable = false,unique = true)
@NotNull
@Size(min = 5, message = "Bank account number should be greater than 5 characters")
private String bankAccountNumber;
@NotNull
@Column(name = "balance", nullable = false)
@Min(1000)
private Long balance;
//Getter Setter and Constructor
**Controller File**//This is the Controller Class
//All imports and other stuff such as @RestController, @Autowired
@GetMapping("/bankaccount/transfer")
public void transferBalance(@RequestParam("bankAccountNo1") String bankAccountNo1, @RequestParam("bankAccountNo2") String bankAccountNo2,
@RequestParam("balance") Long balance) throws RuntimeException
{
bankService.transferBalance(bankAccountNo1,bankAccountNo2, balance);
}
}
**Service File:-**//This is Service Layer
//All imports
@Service
public class BankService {
@Autowired
private BankRepository bankRepository;
@Autowired
private ModelMapper modelMapper;
public List<BankAccountDTO> getAllBankAccount() {
List<BankAccountDTO> bankAccountDTO = new ArrayList<BankAccountDTO>();
List<BankAccount> bankAccount = bankRepository.findAll();
for (BankAccount b : bankAccount) {
bankAccountDTO.add(modelMapper.map(b, BankAccountDTO.class));
}
return bankAccountDTO;
}
public ResponseEntity<?> getIndividualBankAccount(String bankAccountNumber) {
BankAccount bankAccount = bankRepository.findByBankAccountNumber(bankAccountNumber);
if (bankAccount == null) {
return new ResponseEntity<>("Account not found", HttpStatus.BAD_REQUEST);
} else {
return new ResponseEntity<>(
modelMapper.map(bankRepository.findByBankAccountNumber(bankAccountNumber), BankAccountDTO.class),
HttpStatus.OK);
}
}
public Object addBankAccount(BankAccountDTO bankAccountDTO) {
return bankRepository.save(modelMapper.map(bankAccountDTO, BankAccount.class));
}
@Transactional(propagation = Propagation.REQUIRED)
public void depositBalance(String bankAccountNumber, Long balance) throws RuntimeException {
BankAccount bankAccNo = bankRepository.findByBankAccountNumber(bankAccountNumber);
if (bankAccNo == null) {
throw new RuntimeException("Bank Accout Number is not found : " + bankAccountNumber);
} else {
if (balance <= 0) {
throw new RuntimeException("Please deposit appropriate balance");
} else {
Long amount = bankAccNo.getBalance() + balance;
bankAccNo.setBalance(amount);
bankRepository.save(bankAccNo);
}
}
}
@Transactional(propagation = Propagation.REQUIRED)
public void withdrawBalance(String bankAccountNumber, Long balance) throws RuntimeException {
BankAccount bankAccNo = bankRepository.findByBankAccountNumber(bankAccountNumber);
if (bankAccNo == null) {
throw new RuntimeException("Bank Account not found :" + bankAccountNumber);
} else {
if (balance <= 0) {
throw new RuntimeException("Please withdraw appropriate balance");
} else {
Long amount = bankAccNo.getBalance() - balance;
if (amount < 1000) {
throw new RuntimeException("Sorry Cannot withdraw.Your minimum balance should be thousand rupees!");
} else {
bankAccNo.setBalance(amount);
bankRepository.save(bankAccNo);
}
}
}
}
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = RuntimeException.class)
public void transferBalance(String bankAccountNo1, String bankAccountNo2, Long balance) throws RuntimeException {
try {
withdrawBalance(bankAccountNo1, balance);
depositBalance(bankAccountNo2, balance);
} catch (RuntimeException e) {
throw e;
}
}
}