10

考虑“用于事务”中的第二个示例(“使用命名键更新实体,或者如果它尚不存在则创建它”):

https://developers.google.com/appengine/docs/java/datastore/transactions

现在考虑这种情况。多人游戏只允许任何两个玩家之间进行单场比赛。为确保这一点,使用玩家的每个键创建一个键。此键用作 UniqueMatch 实体的键。

因此,为了创建匹配,创建了 XG 交易。在本次交易中:

  1. 我们检查是否已经没有具有该键的 UniqueMatch 实体。如果使用该键的 datastore.get() 调用没有抛出 EntityNotFoundException,那么我们知道这两个玩家之间已经存在匹配,所以我们 rollback() 并向玩家显示错误消息。

  2. 我们 put() 我们需要放置的所有实体以创建匹配。这包括 UniqueMatch 实体,以及其他一些实体。

  3. 然后提交事务。

这似乎工作正常。但是,我注意到我可以在短时间内在任意两个玩家之间创建两场比赛。在一小段时间(实际上,在其中一个测试中长达 10-20 秒),我对 datastore.get(key) 的调用会抛出 EntityNotFoundException,即使该键已经被 put()。

这似乎是最终的一致性。但是,实体检索是否保证是强一致的?这种保证是否受到在 XG 交易中完成这一事实的影响?

提前致谢,

4

1 回答 1

1

我认为您看到的问题可能是因为数据存储区(通过键或查询)仅在事务开始时看到数据存储区的状态。

来自文档(在隔离和一致性下):

在事务中,所有读取都反映事务开始时数据存储的当前一致状态。这不包括事务中先前的放置和删除。事务中的查询和获取保证在事务开始时看到数据存储的单个、一致的快照。

此外,在事务之外,您只会看到已提交的 put ( docs ):

通过查询或获取从数据存储中检索到的实体只会看到已提交的数据。

一个可能的解决方案:

在事务之外创建 UniqueMatch 实体(appengine 不允许您放置具有相同键的实体,因此如果具有相同键的实体已经存在,它将引发异常)。然后,您可以创建/放置在事务中创建匹配所需的其他实体(如果需要)。

最后,确保在为 UniqueMatch 创建密钥时,他们的密钥始终与玩家以相同的顺序创建,因为key(playerA,playerB)!=key(playerB,playerA)

于 2012-10-26T11:51:26.797 回答