App Engine:创建唯一实体(如果不存在)的机制

App Engine: Mechanics of creating a unique entity if it doesn't exist

我们遇到了一个问题,如果实体不存在,我们想懒惰地创建它。关于如何执行此操作的讨论正在进行中,我想澄清一些有关应用程序引擎事务的事情。我将查询限制为单个实体组交易。

我在示例中使用的是 Go,但我希望代码对于非 Go 程序员来说足够清晰。

我的理解是,在单个实体组上的事务只有在事务期间没有外部修改实体组的情况下才会成功。 'entity group timestamp' 指示实体组何时更改,存储在实体组的根实体中。因此在交易期间,当前 'entity group timestamp' 被读取,并且只有在交易结束时它没有改变时交易才能成功。

key := datastore.NewKey(c, "Counter", "mycounter", 0, nil)
count := new(Counter)
err := datastore.RunInTransaction(c, func(c appengine.Context) error {
  err := datastore.Get(c, key, count)
  if err != nil && err != datastore.ErrNoSuchEntity {
    return err
  }
  count.Count++
  _, err = datastore.Put(c, key, count)
  return err
}, nil)

在上面的例子中(取自https://cloud.google.com/appengine/docs/go/datastore/transactions)有两个非错误的情况,我可以看到:

在第二种情况下,另一个相同的交易可能是 运行。如果两个事务的 Get return ErrNoSuchEntity 数据存储如何确保只有一个 put 成功?我希望数据存储中没有 "entity group timestamp" 来测试?

事务是否知道它需要测试计数器是否存在才能使 Put 和整个事务成功?

在这种情况下,是否有可能两笔交易成功并且一笔 Put 覆盖另一笔交易?

如果有关于控制此机制的文档或视频等,我很乐意阅读它。

要回答您的问题,我们必须深入挖掘开发数据存储的源代码,对我们来说幸运的是它有很好的文档记录,只需看看 LiveTxn._GrabSnapshot:

Gets snapshot for this reference, creating it if necessary.

If no snapshot has been set for reference's entity group, a snapshot is taken and stored for future reads (this also sets the read position), and a CONCURRENT_TRANSACTION exception is thrown if we no longer have a consistent snapshot.

所以边缘情况与您推测的略有不同:两个事务都会创建一个新的时间戳,然后一切都会像往常一样工作。在您提出的情况下,第二笔交易将重试,并且计数器将增加两次。

据我所知,没有关于交易如何工作的深入文档,至少没有这么深,但源代码实际上不是 很难读;在这种情况下,您可以跟踪 CONCURRENT_TRANSACTION 错误。

来自documentation on transactions

Inside of transactions, serializable isolation is enforced.

我建议稍微阅读一下链接 wikipedia page,但简而言之,数据存储将确保最终结果就像两个 t运行 操作一样 运行按顺序。

让两个 t运行sactions 写入一个新的、清零的计数器是不是可能的结果。

Does the transaction know that it needs to test for the non-existence of the counter in order for the Put and the entire transaction to succeed?

在某种程度上:t运行saction只有在没有重叠的t运行saction接触同一个键的情况下才能在第一次尝试时成功.

Is there a chance in this case for two transactions to succeed and for one Put to overwrite the other?

No,如果两个 t运行sactions 时间帧重叠,那么最后一个提交将失败,最终重试然后将看到现有的计数器和增加它。