0

play 2.x アプリケーションで、親テーブルから子メンバーを削除するために使用されるポスト リクエストがあります。同じ要求パラメーターを持つ複数の要求がある場合、同時アクセスと同じレコードの重複削除を避けるために、Play に子リストをロックするように依頼するにはどうすればよいですか? 重複したリクエストが非常に近い間隔で送信されると、次のように例外がスローされます。

javax.persistence.OptimisticLockException: データが変更されました。更新された [0] 行 sql[channel_detail から削除、id=? と member_id=? および channel_info_id=?] bind[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自体にこのようなことが起こらないようにするメカニズムが付属しているかどうかはわかりません。スローされる例外は、すでにロック戦略の1つの形式です。主な問題は、データをフェッチしてからエントリを削除するまでの間にデータが変更される時間があることだと思います。そのため、次のいずれかを実行します。

  • メンバーのルックアップと削除の両方が一度に行われるように、削除メソッドを別の方法で実装します(免責事項:私はEBeanに精通していないため、トランザクション管理をどのように処理するかについてはまったくわかりません)

  • をキャッチしOptimisticLockException、数秒後に削除を再試行し、同じ方法で再度失敗した場合は、たとえば3回繰り返します。

于 2012-10-30T06:59:31.230 に答える