I got a very annoying scenario and Spring Boot or JPA is not helping at all:
I want to give my to kids some money from account A. I have a table where I keep the track of my balance_amount. Whenever I giveaway the money, I update it accordingly by subtracting the money I give to my kids.
Now, I have give my two kids some amount, let say 100rs and 200rs respectively in the form of requests (2 requests). So, to update my balance_amount, these are the steps I follow:
- I stared a for loop.
- Fetch my row from table to know my available balance_amount (single row), let say I have 1000rs left.
- When loop iterates for first time, I pick the requestAmount (100rs) and subtract it from balance_amount (1000rs).
- Update my row in table with updated_balance_amount (1000-100=900rs).
- Loop iterates for second time.
- Second iteration started, I fetch my row from table to know my available balance_amount.
- I again pick the requestAmount (200rs this time) and subtract it from balance_amount.
- Again updated my row in table with updated_balance_amount. Loop ends here (as I have only 2 requests).
- I am expecting that at the end of loop, my remaining balance_amount would be 1000-100-200 = 700rs. But it's not! It's showing 800rs.
How the hell happened? Upon debugging, I found that when loop iterated for second time, at step 6, instead of showing 900rs as my balance_amount (after first iteration ended), it is picking the balance_amount as 1000rs! Why? Why it has not updated my row in the table?
During debugging after step 4, I checked my table's row and it was perfectly showing 900rs. But as soon as second iteration started, It discarded the updated value and picked the original 1000rs like it didn't commit the update query of first iteration.
So, please tell me why it's like that and how can I achieve my purpose. Thanks in advance.
Sample Code is:
Method 1:
@Override
public String doSomething(List<RequesDTO> requestDTO, ...)
{
...
...
String callToDeductBalanceAmount(List<RequesDTO> requestDTO);
...
...
return message;
}
Method 2
@Transactional
private String callToDeductBalanceAmount(List<RequesDTO> requestDTO) {
int remainingBalance = 0;
String message = null;
for (RequestDTO lRequest : requestDTO) {
double requestAmount = lRequest.getRequestAmount;
Wallet isBalanceAvailable = walletRepository.checkForAvailableBalance(...);
if(null != isBalanceAvailable) {
double updatedAmount = isBalanceAvailable.getBalanceAmount() - requestAmount;
remainingBalance = callToUpdateBalanceAmount(..., updatedAmount);
if (remainingBalance == 0) {
message = "Failed";
}
}
}
return message;
}
Method 3
@Transactional
private Integer callToUpdateBalanceAmount(..., updatedAmount) {
return walletRepository.setUpdatedNalanceAmount(..., updatedAmount);
}
**Repository**
@Modifying
@Transactional
@Query("UPDATE...")
Integer setUpdatedNalanceAmount(..., @Param("updatedAmount") double updatedAmount);
CONSOLE LOGS:
Hibernate: select ... from wallet.....
Hibernate: update wallet.....
Hibernate: select ... from wallet.....
Hibernate: update wallet.....