检查和更新表中的记录时出现的潜在并发问题

情况是这样的,


成员必须兑换令牌才能访问(解锁)给定物品。相关的数据库表包括:


表 1


Table MEMBER_BALANCE: MEMBER_ID, TOKEN_BALANCE

表 2


Table UNLOCKED_ITEM: MEMBER_ID, DATE_UNLOCKED, ITEM_ID

我需要强制执行的检查或约束是


当用户尝试解锁项目时,TOKEN_BALANCE必须> 0,并且

用户之前未解锁过同一项目。

我的直觉倾向是在会员服务中编写一个简单的方法.java:


@Transactional

public void unlockItem(Member member, Item item){

    memberBalanceDAO.decrementBalance(member);

    itemDAO.unlockItem(member, item);

}

我已经通过在表上添加/对的约束来处理第二个要求。uniqueMEMBER_IDITEM_IDUNLOCKED_ITEM


我认为,我唯一需要注意的是,用户试图同时解锁许多物品,但未满足要求。例如, 是 1,但用户单击以虚拟方式同时解锁两个项目。TOKEN_BALANCETOKEN_BALANCE


以下是我的方法: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");

    }

}

我不认为这可以保护我免受= 1用例的影响。我担心同时有多个解锁请求。如果余额为 1,我可以同时接到两个调用,两个调用都将余额提交到 0,但随后也收到两个成功的调用,对吧?TOKEN_BALANCEdecrementBalance()itemDAO.unlockItem(...)


我应该如何实现这一点?是否应将服务级别方法的事务设置为 ?还是有更清洁/更好的方法来解决这个问题?isolation = Isolation.SERIALIZABLE


江户川乱折腾
浏览 147回答 1
1回答

慕工程0101907

我宁愿建议您在表中引入列。请参阅文档“乐观锁定”。versionmember_balance正如你所提到的,你不能修改架构;你可以去无版本乐观锁,在这里解释。或者你可能想去悲观的锁定,在这里解释。然后,您可以修改您的方法,在那里获取成员余额,不要使用 。例如decrementBalance()findMemberBalance()@Transactionalpublic 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");    }}铌:它可能无法正常工作;它只是为了给你一些提示。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java