![](/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.