我正在阅读官方的GAE documentation on transactions,但是我不能理解当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
发布于 2012-01-04 20:21:48
我在GAE邮件列表中找到了答案。
我对GAE中的事务是如何工作的有一个误解。我曾设想在事务开始时会锁定对数据存储的任何并发更新,直到事务提交为止。这将是一个性能噩梦,因为所有的更新都会在这个事务上阻塞,我很高兴情况并非如此。
相反,发生的情况是,第一个更新获胜,如果在后续更新中检测到冲突,则会抛出异常。
这一开始让我很惊讶,因为这意味着许多事务将需要重试逻辑。但它似乎类似于“可序列化隔离”级别的PostgreSQL语义,尽管在PostgreSQL中您还可以选择锁定单独的行和列。
https://stackoverflow.com/questions/8718170
复制相似问题