关于对象化事务重试的困惑

问题描述 投票:0回答:1

objectify documentation声明有关交易的内容:

工作必须是幂等的。各种条件,包括ConcurrentModificationException,可能导致事务重试。如果您需要限制尝试交易的次数,使用transactNew(int,Work)。

但是,谷歌数据存储documentation指出:

Datastore API不会not自动重试事务,但是您可以添加自己的逻辑以重试它们,例如处理冲突当另一个请求同时更新同一实体时。

这些陈述似乎是矛盾的。对象化交易真的重试了吗?为了安全起见,我正在使用transactNew(1, Work)确保它仅运行一次,但是幕后情况是什么?为什么?

Google文档指出,交易的一种用途是做类似将钱从一个帐户转移到另一个帐户的事情。如果交易正在重试,那将是行不通的,因为从本质上讲,转移资金并不是幂等的。在这种情况下,使用transactNew(1, Work)是正确的做法吗?基本上,我希望安全地进行非幂等事务。

google-app-engine google-cloud-datastore objectify
1个回答
0
投票

Objectify将在CME上重试。关于交易真正提交时您是否可以获得CME存在一些疑问-曾经有文献记载这是可能的,但Google可能已经消除了这种可能性。

但是,确保(例如)银行转账完成的“正确方法”是不限制重试。

  1. 在重试之外创建交易ID。只是一些独特的价值。
  2. 启动您的交易,尝试加载该交易ID。是否存在?您的交易已经完成。
  3. 如果不存在,请创建交易对象(带有ID),然后进行借方+贷方。

这最终成为任何类似银行的分类帐的标准行为;您将创建一个交易记录以及借方+贷方。如果创建事务记录,则很容易实现幂等。


0
投票

您正在查看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的)事务重试逻辑和幂等性,我将事务(带有相关的调试消息)放置在推式任务队列处理程序中,并同时触发了多个任务以引起冲突。请求和应用日志足以进行验证。

© www.soinside.com 2019 - 2024. All rights reserved.