![](/img/trans.png)
[英]Potential concurrency issue when Integer object is used as a lock in synchronized block
[英]Potential concurrency issue while checking and updating a record in table
就是這種情況
成員必須兌換令牌才能訪問(解鎖)給定項目。 相關的數據庫表是:
表格1
Table MEMBER_BALANCE: MEMBER_ID, TOKEN_BALANCE
表2
Table UNLOCKED_ITEM: MEMBER_ID, DATE_UNLOCKED, ITEM_ID
我需要執行的檢查或約束是
我的直覺是在MemberService.java中編寫一個簡單的方法:
@Transactional
public void unlockItem(Member member, Item item){
memberBalanceDAO.decrementBalance(member);
itemDAO.unlockItem(member, item);
}
我已經通過在UNLOCKED_ITEM
表上的MEMBER_ID
/ ITEM_ID
對上添加unique
約束來處理第二個要求。
我認為,我唯一需要照顧的是,用戶試圖同時解鎖許多物品,而未滿足TOKEN_BALANCE
要求。 例如, TOKEN_BALANCE
為1,但是用戶單擊以同時虛擬地解鎖兩個項目。
下面是我的MemberBalanceDAO.decrementBalance
方法:
@Transactional
public void decrementBalance(Member member) {
MemberBalance memberBalance = this.findMemberBalance(member);
if (memberBalance.getTokens() >= 1) {
memberBalance.setTokens(memberBalance.getTokens() - 1);
this.save(memberBalance);
} else {
throw new SomeCustomRTException("No balance");
}
}
我認為這不會保護我免受TOKEN_BALANCE
= 1個用例的影響。 我擔心同時有多個解鎖請求。 如果余額為1,那么我可以同時調用兩次decrementBalance()
並將余額都提交為0,但是也可以成功調用兩次itemDAO.unlockItem(...)
,對嗎?
我應該如何實施呢? 我應該將服務級別方法的事務設置isolation = Isolation.SERIALIZABLE
嗎? 還是有一種更清潔/更好的方式來解決這個問題?
我寧願建議您在member_balance
表中引入version
列。 請參閱文檔樂觀鎖定 。
如前所述,您無法修改架構; 您可以使用無版本的樂觀鎖,如此處所述 。
或者,您可能想要進行悲觀鎖定,如此處所述 。 然后,您可以修改方法decrementBalance()
,以在那里獲取成員余額,請不要使用findMemberBalance()
。 例如,
@Transactional
public void decrementBalance(Member member) {
MemberBalance memberBalance = entityManager.find(
MemberBalance.class, member.id, LockModeType.PESSIMISTIC_WRITE,
Collections.singletonMap( "javax.persistence.lock.timeout", 200 ) //If not supported, the Hibernate dialect ignores this query hint.
);
if (memberBalance.getTokens() >= 1) {
memberBalance.setTokens(memberBalance.getTokens() - 1);
this.save(memberBalance);
} else {
throw new SomeCustomRTException("No balance");
}
}
注意:它可能無法按原樣工作; 只是為您提供一些提示。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.