App-Engine中的原子计数器增量
atomic counter increment in App-Engine
我对事务还是有点疑惑,到底是用DatastoreService还是Objectify。 (是的,我读 What is the correct way to atomically increment a counter in App Engine?)。我需要自动增加一个计数器。我怎么做? App Engine 文档中的示例在其 finally 块中有一个回滚。但我不想回滚,我希望系统继续尝试。另一方面,objectify 文档说它的事务模型与低级 api 的事务模型不同。所以我正在编写这两个代码,我只需要帮助更正或确认它们。
DatastoreService 版本
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService()
Transaction txn = datastore.beginTransaction();
try {
Key commentKey = KeyFactory.createKey(“Comment”, id);
Entity comment = datastore.get(commentKey);
int views = (Integer)comment.getProperty(“views”);
views++;//increment step
comment.setProperty(“views”, views);
datastore.put(comment);
txn.commit();
} finally {
if (txn.isActive()) {
txn.rollback();
}
}
对象化版本
ofy().transact(new VoidWork() {
@Override
public void vrun() {
Comment comment = ofy().load().type(Comment.class).id(commentId).now();
long views = 1+ comment.getViews();
comment.setViews(views);
ofy().save().entity(comment).now();
}
});
重要的一点是,我希望系统可以无限次地尝试。当然,我希望客户端调用 return 而所有这些都是异步发生的。感谢您的帮助
如果发生并发冲突,Objectify 版本将重试。您可以修改 DatastoreService 版本以在 ConcurrentModificationException 上循环,您将有效地获得相同的逻辑。
然而,这并不能使您得到一个非常准确的计数器(尽管对于大多数用途来说它通常足够接近)。但是,您不会希望 运行 像这样进行银行交易。
问题(存在于所有分布式事务处理系统中)是在您的事务处理过程中可能会出现问题,比如抛出 DatastoreException。这使您的计数器处于不确定状态 - 提交是否成功?你不知道。
如果你想要精确(你确实说 非常 准确),你需要执行一些变体:
- 在您开始交易
之前创建一个带有唯一键的交易记录
- 开始交易
- 查看记录是否存在;如果没有,你已经完成了
- 删除记录,递增计数器,然后提交
- 如果出错,从2开始重复直到成功
并且您需要某种查询来清理完全失败的交易的剩余交易记录。
它的一个变体是在交易之前只创建id并在交易内部创建txn记录,使用记录的积极存在来指示成功。如果您长期保留该记录,它基本上就是交易历史记录。
这种级别的事务确定性需要额外的写入操作并增加明显的延迟,因此您可能只想在 确实 需要准确性时使用它。
我对事务还是有点疑惑,到底是用DatastoreService还是Objectify。 (是的,我读 What is the correct way to atomically increment a counter in App Engine?)。我需要自动增加一个计数器。我怎么做? App Engine 文档中的示例在其 finally 块中有一个回滚。但我不想回滚,我希望系统继续尝试。另一方面,objectify 文档说它的事务模型与低级 api 的事务模型不同。所以我正在编写这两个代码,我只需要帮助更正或确认它们。
DatastoreService 版本
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService()
Transaction txn = datastore.beginTransaction();
try {
Key commentKey = KeyFactory.createKey(“Comment”, id);
Entity comment = datastore.get(commentKey);
int views = (Integer)comment.getProperty(“views”);
views++;//increment step
comment.setProperty(“views”, views);
datastore.put(comment);
txn.commit();
} finally {
if (txn.isActive()) {
txn.rollback();
}
}
对象化版本
ofy().transact(new VoidWork() {
@Override
public void vrun() {
Comment comment = ofy().load().type(Comment.class).id(commentId).now();
long views = 1+ comment.getViews();
comment.setViews(views);
ofy().save().entity(comment).now();
}
});
重要的一点是,我希望系统可以无限次地尝试。当然,我希望客户端调用 return 而所有这些都是异步发生的。感谢您的帮助
如果发生并发冲突,Objectify 版本将重试。您可以修改 DatastoreService 版本以在 ConcurrentModificationException 上循环,您将有效地获得相同的逻辑。
然而,这并不能使您得到一个非常准确的计数器(尽管对于大多数用途来说它通常足够接近)。但是,您不会希望 运行 像这样进行银行交易。
问题(存在于所有分布式事务处理系统中)是在您的事务处理过程中可能会出现问题,比如抛出 DatastoreException。这使您的计数器处于不确定状态 - 提交是否成功?你不知道。
如果你想要精确(你确实说 非常 准确),你需要执行一些变体:
- 在您开始交易 之前创建一个带有唯一键的交易记录
- 开始交易
- 查看记录是否存在;如果没有,你已经完成了
- 删除记录,递增计数器,然后提交
- 如果出错,从2开始重复直到成功
并且您需要某种查询来清理完全失败的交易的剩余交易记录。
它的一个变体是在交易之前只创建id并在交易内部创建txn记录,使用记录的积极存在来指示成功。如果您长期保留该记录,它基本上就是交易历史记录。
这种级别的事务确定性需要额外的写入操作并增加明显的延迟,因此您可能只想在 确实 需要准确性时使用它。