Java 什么时候在GAE中抛出ConcurrentModificationException?
我正在阅读官方GAE,无法理解何时抛出Java 什么时候在GAE中抛出ConcurrentModificationException?,java,transactions,google-cloud-datastore,Java,Transactions,Google Cloud Datastore,我正在阅读官方GAE,无法理解何时抛出ConcurrentModificationException 请看我在这里复制粘贴的一个示例: int retries = 3; while (true) { Transaction txn = datastore.beginTransaction(); try { Key boardKey = KeyFactory.createKey("MessageBoard", boardName); Entity m
ConcurrentModificationException
请看我在这里复制粘贴的一个示例:
int retries = 3;
while (true) {
Transaction txn = datastore.beginTransaction();
try {
Key boardKey = KeyFactory.createKey("MessageBoard", boardName);
Entity messageBoard = datastore.get(boardKey);
long count = (Long) messageBoard.getProperty("count");
++count;
messageBoard.setProperty("count", count);
datastore.put(messageBoard);
txn.commit();
break;
} catch (ConcurrentModificationException e) {
if (retries == 0) {
throw e;
}
// Allow retry to occur
--retries;
} finally {
if (txn.isActive()) {
txn.rollback();
}
}
}
现在,对数据存储的所有写入(在本例中)都打包在一个事务下。那么为什么会抛出ConcurrentModificationException
当事务中没有包装的其他代码更新被上述代码修改的同一实体时,是否会发生这种情况?如果我确保更新实体的所有代码始终包装在事务中,是否可以保证我不会得到
ConcurrentModificationException
?您似乎在做他们建议您不应该做的事情:
警告!上面的示例描述了仅为简单起见对计数器进行事务性递增。如果你的应用程序有频繁更新的计数器,你不应该以事务方式增加它们,甚至不应该在单个实体内增加它们。使用计数器的最佳实践是使用称为计数器分片的技术
也许上述警告并不适用,但它似乎暗示了您所看到的问题:
这需要一个事务,因为在该代码获取对象之后,但在保存修改后的对象之前,其他用户可能会更新该值。在没有事务的情况下,用户的请求在另一个用户更新之前使用count的值,保存覆盖新值。在事务中,应用程序被告知其他用户的更新。如果在事务期间更新了实体,则事务将失败,出现ConcurrentModificationException
。应用程序可以重复事务以使用新数据
换句话说:在您使用事务更新同一实体的同时,似乎有人在修改您的实体而不使用事务
注意:在极少数情况下,即使事务返回超时或内部错误异常,事务也会完全提交。因此,最好尽可能使事务幂等
一个合理的警告:我不熟悉这个库,但上面的引文取自显示示例事务的文档(这似乎与您在原始问题中发布的内容相同)。我在GAE邮件列表中找到了答案 我对GAE中的事务如何工作有一个错误的概念。我曾设想,在事务提交之前,启动事务将锁定对数据存储的任何并发更新。这将是一场性能噩梦,因为所有更新都会阻止此事务,我很高兴事实并非如此 相反,第一次更新获胜,如果在后续更新中检测到冲突,则会引发异常
一开始这让我很惊讶,因为这意味着许多事务都需要重试逻辑。但它似乎与“可序列化隔离”级别的PostgreSQL语义相似,不过在PostgreSQL中,您也可以选择锁定单个行和列。该警告的原因完全不同:性能。在交易的上下文中,这是一个非常有效的例子。HRJ,在警告后的段落中,它还指出,如果实体在交易过程中更新,则交易可能会因
ConcurrentModificationException
而失败。我想这就是本案发生的情况。谢谢你试着回答这个问题。我已经知道文档中的内容了。我需要一个没有假设的答案。@HRJ,在看不到/不知道还有什么可以改变你的实体的情况下,我想说我们所能做的就是假设。不管怎样,祝你好运。这和我提供的引文的第二段有什么不同?Lirik,它和你的引文没什么不同。但是你下面的总结和我的不同,答案中有一些假设和不相关的引用。因此,我在澄清自己困惑的同时做出了新的回答。感谢您参与这项任务。