如何使用 Objectify 事务以原子方式更新多个实体

How to update multiple entities atomically using Objectify transactions

我正在使用 google-app-engine 作为我的 REST 后端,并使用 google-datastore 作为数据库。我正在通过 objectify 访问数据存储。

我有一个 API 调用,我想更新一个以上的实体(比方说 3 个实体)。

我的要求是要么全部更新,要么更新其中 none 个。我希望在可能的情况下也能保证这一点,包括实例 运行 代码崩溃/下线的错误情况。

即使我在事务中进行所有更新,如何确保原子性

ofy().save().entity(thing1);
ofy().save().entity(thing2);
ofy().save().entity(thing3);

假设上述所有 save() 都发生在事务中,现在如果实例 运行 此代码在保存 "thing1" 后崩溃,我会遇到更新 1 个实体并且其他我想避免的。

我查看了关于交易的 objectify 文档:https://github.com/objectify/objectify/wiki/Transactions#basic-transactions 但找不到任何此类示例或描述

我还查看了数据存储文档:https://cloud.google.com/datastore/docs/concepts/transactions

我没有直接用过datastore所以对它的API不是很熟悉,但是在上面link他们给出了一个从一个账户转账到另一个账户的例子描述看起来两个实体的更新是原子发生的(否则它不会处理实例 运行 代码在从一个帐户中扣除金额并在将其记入另一个帐户之前崩溃的极端情况)。我的理解正确吗?

基本上我的问题是:

  1. 在 objectify 中有没有一种方法可以原子地更新多个实体(处理实例的极端情况 运行 代码崩溃)?如果是那么怎么办?
  2. 如果不能,还有什么选择?
  3. 是否可以直接使用数据存储APIs?我在上面分享的关于转移资金和原子更新示例的 link 中是否提供了该示例?如果我在数据存储的 put() API 中提供多个实体 - 是否保证在所有情况下(包括实例崩溃)所有 none 更新都发生了?
  4. 有一个 API is objectify 来执行实体的批量更新:

    ofy().save().entities(entityList).now();

然而,根据我的理解,这个 API 不能保证是原子的,因此我不能将它用于我的案例。我的理解正确吗?

基本上 Objectify 允许您访问 Cloud Datastore 函数。这意味着为了做你想做的事(原子保存或更新),你必须在事务中 update/save 数据,因为(来自 here):

A transaction is a set of Google Cloud Datastore operations on one or more entities. Each transaction is guaranteed to be atomic, which means that transactions are never partially applied. Either all of the operations in the transaction are applied, or none of them are applied.

  1. 关于您的第一个问题:

您应该使用 交易方法,就像这样 example:

import static com.googlecode.objectify.ObjectifyService.ofy;
import com.googlecode.objectify.Work;

// If you don't need to return a value, you can use VoidWork
Thing th = ofy().transact(new Work<Thing>() {
    public Thing run() {
        Thing thing = ofy().load().key(thingKey).now();
        thing.modify();
        ofy().save().entity(thing);
        return thing;
    }
});

Objectify interface 的 JavaDoc 中指出:

You can run transactions by calling Objectify.transact() or Objectify.transactNew();

  1. 现在你的第三个问题:

您可以使用数据存储 API,在 this tutorial 中有一个事务示例:

boolean markDone(long id) {
  Transaction transaction = datastore.newTransaction();
  try {
    Entity task = transaction.get(keyFactory.newKey(id));
    if (task != null) {
      transaction.put(Entity.newBuilder(task).set("done", true).build());
    }
    transaction.commit();
    return task != null;
  } finally {
    if (transaction.isActive()) {
      transaction.rollback();
    }
  }
}
  1. 第四题:

只需确保在事务中执行该行代码即可。希望这有帮助