代码之家  ›  专栏  ›  技术社区  ›  Micro

对objectify事务重试的困惑

  •  0
  • Micro  · 技术社区  · 5 年前

    物化 documentation 关于交易说明如下:

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

    然而,谷歌数据存储 documentation 声明:

    数据存储API 自动重试事务,但您 可以添加自己的逻辑来重试它们,例如处理冲突 当另一个请求同时更新同一实体时。

    这些说法似乎相互矛盾。objectify交易真的会重试吗?为了安全起见,我正在使用 transactNew(1, Work) 确保它只运行一次,但引擎盖下发生了什么,为什么?

    谷歌文档指出,交易的一种用途是将资金从一个账户转移到另一个账户。如果交易正在重试,那么这将不起作用,因为从本质上讲,转账是不幂等的。在这种情况下,使用 新交易(1,工作) 做正确的事对吗?基本上,我希望安全地执行一个非幂等事务。

    2 回复  |  直到 5 年前
        1
  •  2
  •   stickfigure    5 年前

    Objectify将在CME上重试。当交易实际提交时,您是否可以获得CME存在一些问题——曾几何时,有记录表明这是可能的,但谷歌可能已经消除了这一点。

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

    1. 在重试之外创建事务id。只是一些独特的价值。
    2. 启动您的交易,尝试加载该交易id。它存在吗?您的交易已完成。
    3. 如果它不存在,请创建您的交易对象(带有id)并进行借记+贷记。

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

        2
  •  1
  •   Dan Cornilescu    5 年前

    您正在查看两个不同的客户端库:

    • objectify似乎包括自动重试,可定制
    • 对于不包括此类重试的普通数据存储,您必须自己处理重试

    货币转移问题不一定是幂等的,因为可以使用事务使其幂等。关键是将两个帐户修改都包含在同一交易中,如所示 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();
        }
      }
    }
    

    这样,要么两个帐户都更新,要么都不更新——如果事务失败,所有更改要么不提交,要么回滚。

    FWW,验证我的( ndb -基于)事务重试逻辑和幂等性我将事务(以及相关的调试消息)放置在推送任务队列处理程序中,并同时触发多个任务以引起冲突。请求和应用程序日志足以进行验证。

    推荐文章