如何防止" NucleusDataStoreException:并发修改"?

时间:2015-02-13 14:47:43

标签: java google-app-engine jdo

我们的应用程序突然获得了大量的流量,并且系统中存在一些设计缺陷(或者我们从未想过它会获得如此多的流量,所以我们只是选择跳过它。)

正如主题所述,我正在寻找一种防止错误的方法:org.datanucleus.exceptions.NucleusDataStoreException: Concurrent Modification

目前我有一个名为Group的实体,如下所示:

@PersistenceCapable
public class Group extends PersistableString {
    private static final long serialVersionUID = 6215353466976945628L;

    @Persistent
    private int yesCount;
    @Persistent
    private int noCount;

    public void increaseYesCount()
    {
        yesCount++;
    }
    public void increaseNoCount()
    {
        noCount++;
    }
}

以下代码是如何完成实体的更新:

int answer = Integer.parseInt(req.getParameter("answer"))

try {
    PersistenceManager pm = PMF.getPersistenceManager();
    for(String groupId : allGroupsToBeUpdated)
    {
        Group group = pm.getObjectById(Group.class, groupId);
        if(answer == 0)
            group.increaseNoCount();
        else
            group.increaseYesCount();
    }
    pm.close();
} catch (Exception e) {
    e.printStackTrace();
}

allGroupsToBeUpdated是一个包含大约30个字符串ID的列表。有什么方法可以避免Concurrent Modification - 错误吗?我可以检查我检索的实体是否正在更新,然后只是丢弃(/忽略)更新?写入实际成功并不重要,我只是想确保我没有得到错误(或者它一直试图通过写入成功),因为它导致请求需要10-30秒。

我是否应该打开(获取新的PM-instance)并在每次更新之间关闭连接(pm.close()),而不是等待所有30个更新通过?

我知道分片计数器应该(显然)使用它们,但是现在我正在寻找这个问题的“快速修复”。

编辑: 我正在使用:

App Engine SDK 1.8.9

JDO 3.0

Stacktrace可在以下位置找到: http://pastebin.com/TWnmkpPU

1 个答案:

答案 0 :(得分:0)

由于长度而作为答案发布。

事务可能在您的情况下并不好,因为您实际上只是希望隐藏用户的问题,这在慢请求时间内表现出来。也许开始执行异步推送任务以在请求之外的后台执行写操作将是您最好的选择。

我真的不建议基于隐藏错误和吞咽异常的设计。希望“防止”正在执行预期的异常(由于争用而发出写入失败的信号),意味着您应该首先避免导致它的条件。

我完全理解需要尽早让事情快速完成,但是一旦糟糕的设计决策刚刚开始出现,就开始采用最佳实践可能是一个好主意。继续依赖“快速修复”和隐藏问题可能会让你在以后陷入困境。