Reputation: 462
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:
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.....
Upvotes: 0
Views: 1587
Reputation: 11
Can you try with this at method 2
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;
}
This will work. but this will have bit performance issue as its running in different transactional. But to fix performance you need to improve your design. Also check your hibernate config if auto_commit enabled. else you have commit manually after each transaction.
Upvotes: 1
Reputation: 21
checkForAvailableBalance
fetches the data from repository on every call. But when you make changes(by deducting amount) that change will only be flushed to db once you've exited the @Transactional
annotated method. You need to pull the business logic out of this Repository to a service class. Spring uses proxy pattern to understand how it works behind the scene have a look at this answer
Upvotes: 0