0

在 play 2.x 应用程序中,我有一个发布请求,用于从父表中删除子成员。如果有多个请求具有相同的请求参数,我如何要求 Play 锁定子列表以避免并发访问和重复删除同一记录?如果重复请求非常接近发送,则会引发如下异常:

javax.persistence.OptimisticLockException:数据已更改。更新了 [0] 行 sql[从 id=? 的 channel_detail 中删除 和 member_id=? 和 channel_info_id=?] 绑定[null]

@BodyParser.Of(BodyParser.FormUrlEncoded.class)
public static Result removeMemberFromChannel() {
    RequestBody body = request().body();
    Map<String, String[]> dict = body.asFormUrlEncoded();
    final String memberId = dict.get("memberId") != null ? dict.get(Config.MEMBER_ID_PARAM)[0] : null;

    ChannelInfo channelInfo = ChannelInfo.getChannelForName(channelName); //method was removed to save space
    if (channelInfo != null) {
       channelInfo.removeMemberId(memberId);
       channelInfo.save();
    }
}

@Entity
@Table(name="channel")
public class ChannelInfo extends Model {
    @Id
    private Long id;

    @Constraints.Required
    private String channelName;

    @OneToMany(cascade=CascadeType.ALL, mappedBy="channelInfo")
    private Set<ChannelDetailMember> members;

    private int membersCount = 0;

    public void removeMemberId(String memberId) {
        Iterator<ChannelDetailMember> iter = this.getMembers().iterator();
        while (iter.hasNext()) {
            ChannelDetailMember dMember = iter.next();
            if (dMember.getMemberId().equals(memberId)) {
               dMember.delete();
               membersCount--;
               break;
            }
         }
    }
}

@Entity
@Table(name="channel_detail")
public class ChannelDetailMember extends Model {

    @Id
    private Long id;

    @Constraints.Required
    private String memberId;

    @Constraints.Required
    @ManyToOne(cascade=CascadeType.PERSIST)
    ChannelInfo channelInfo;
}
4

1 回答 1

1

我不确定 Play 本身是否带有防止此类事情发生的机制,并且抛出的异常已经是锁定策略的一种形式。我认为主要问题是数据有时间在您获取它和您想要删除条目之间进行更改,因此它会执行以下操作之一:

  • 以不同的方式实现删除方法,以便同时查找和删除成员(免责声明:我对 EBean 不太熟悉,所以我完全不确定它如何处理事务管理)

  • 抓住OptimisticLockException,然后在几秒钟后再次尝试删除并重复例如 3 次,如果它再次以相同的方式失败

于 2012-10-30T06:59:31.230 回答