我遇到了一個非常煩人的場景,而 Spring Boot 或 JPA 根本沒有幫助:
我想從賬戶 A 給我的孩子一些錢。我有一張表,我可以在其中記錄我的 balance_amount。每當我贈送錢時,我都會通過減去我給孩子的錢來相應地更新它。
現在,我給了我的兩個孩子一些金額,分別以請求(2 個請求)的形式說 100 和 200。因此,要更新我的 balance_amount,這些是我遵循的步驟:
- 我盯著一個 for 回圈。
- 從表中獲取我的行以了解我可用的 balance_amount (單行),假設我還剩 1000 盧比。
- 當回圈第一次迭代時,我選擇 requestAmount (100rs) 并從 balance_amount (1000rs) 中減去它。
- 使用 updated_balance_amount (1000-100=900rs) 更新我在表中的行。
- 回圈迭代第二次。
- 第二次迭代開始,我從表中獲取我的行以了解我可用的 balance_amount。
- 我再次選擇 requestAmount(這次是 200rs)并從 balance_amount 中減去它。
- 再次使用updated_balance_amount 更新了我在表中的行。回圈到此結束(因為我只有 2 個請求)。
- 我期望在回圈結束時,我剩余的 balance_amount 將是 1000-100-200 = 700rs。但事實并非如此!它顯示800rs。
這到底是怎么回事?在除錯時,我發現當回圈第二次迭代時,在第 6 步,我的 balance_amount 沒有顯示為 900rs(第一次迭代結束后),而是將 balance_amount 選擇為 1000rs!為什么?為什么它沒有更新我在表中的行?
在第 4 步之后的除錯程序中,我檢查了我表的行,它完美地顯示了 900rs。但是一旦第二次迭代開始,它就丟棄了更新的值并選擇了原始的 1000rs,就像它沒有提交第一次迭代的更新查詢一樣。
所以,請告訴我為什么會這樣,我怎樣才能達到我的目的。提前致謝。
示例代碼是:
方法一:
@Override
public String doSomething(List<RequesDTO> requestDTO, ...)
{
...
...
String callToDeductBalanceAmount(List<RequesDTO> requestDTO);
...
...
return message;
}
方法二
@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;
}
方法三
@Transactional
private Integer callToUpdateBalanceAmount(..., updatedAmount) {
return walletRepository.setUpdatedNalanceAmount(..., updatedAmount);
}
**Repository**
@Modifying
@Transactional
@Query("UPDATE...")
Integer setUpdatedNalanceAmount(..., @Param("updatedAmount") double updatedAmount);
控制臺日志:
Hibernate: select ... from wallet.....
Hibernate: update wallet.....
Hibernate: select ... from wallet.....
Hibernate: update wallet.....
uj5u.com熱心網友回復:
checkForAvailableBalance在每次呼叫時從存盤庫中獲取資料。但是,當您進行更改(通過扣除金額)時,該更改只會在您退出帶@Transactional注釋的方法后重繪 到 db 。您需要將業務邏輯從這個 Repository 中提取到一個服務類。Spring 使用代理模式來了解它在幕后是如何作業的,看看這個答案
uj5u.com熱心網友回復:
你能在方法 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;
}
這將起作用。但這將有一些性能問題,因為它在不同的事務中運行。但是要修復性能,您需要改進您的設計。如果啟用了 auto_commit,還要檢查您的休眠配置。否則,您必須在每次交易后手動提交。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/324727.html
