objectify documentation声明有关交易的内容:
工作必须是幂等的。各种条件,包括ConcurrentModificationException,可能导致事务重试。如果您需要限制尝试交易的次数,使用transactNew(int,Work)。
但是,谷歌数据存储documentation指出:
Datastore API不会not自动重试事务,但是您可以添加自己的逻辑以重试它们,例如处理冲突当另一个请求同时更新同一实体时。
这些陈述似乎是矛盾的。对象化交易真的重试了吗?为了安全起见,我正在使用transactNew(1, Work)
确保它仅运行一次,但是幕后情况是什么?为什么?
Google文档指出,交易的一种用途是做类似将钱从一个帐户转移到另一个帐户的事情。如果交易正在重试,那将是行不通的,因为从本质上讲,转移资金并不是幂等的。在这种情况下,使用transactNew(1, Work)
是正确的做法吗?基本上,我希望安全地进行非幂等事务。
Objectify将在CME上重试。关于交易真正提交时您是否可以获得CME存在一些疑问-曾经有文献记载这是可能的,但Google可能已经消除了这种可能性。
但是,确保(例如)银行转账完成的“正确方法”是不限制重试。
这最终成为任何类似银行的分类帐的标准行为;您将创建一个交易记录以及借方+贷方。如果创建事务记录,则很容易实现幂等。
您正在查看2个不同的客户端库:
从某种意义上讲,可以通过交易使货币转移成为幂等,从某种意义上说,汇款问题不一定非幂等。关键是在同一笔交易中包括两个帐户修改,如the datastore client example中所示:
void transferFunds(Key fromKey, Key toKey, long amount) {
Transaction txn = datastore.newTransaction();
try {
List<Entity> entities = txn.fetch(fromKey, toKey);
Entity from = entities.get(0);
Entity updatedFrom =
Entity.newBuilder(from).set("balance", from.getLong("balance") - amount).build();
Entity to = entities.get(1);
Entity updatedTo = Entity.newBuilder(to).set("balance", to.getLong("balance") + amount)
.build();
txn.put(updatedFrom, updatedTo);
txn.commit();
} finally {
if (txn.isActive()) {
txn.rollback();
}
}
}
通过这种方式,两个帐户都被更新,或者都不更新-如果交易失败,则不会提交或回滚所有更改。
FWIW,为验证我的(基于ndb
的)事务重试逻辑和幂等性,我将事务(带有相关的调试消息)放置在推式任务队列处理程序中,并同时触发了多个任务以引起冲突。请求和应用日志足以进行验证。