数据存储区能否生成覆盖我的实体的 ID?

Posted

技术标签:

【中文标题】数据存储区能否生成覆盖我的实体的 ID?【英文标题】:Could the datastore generate ids that overwrite my entities? 【发布时间】:2014-07-07 14:30:45 【问题描述】:

我有一个根实体类型,我想重构它以拥有一个父实体。

这些实体都有自动分配的 ID。

我克隆了所有现有实体,从父实体和旧实体的 id 创建了克隆的密钥。然后我删除了旧实体。

创建的任何新实体都会从数据存储区中获得自动分配的 ID。

The docs say:

Datastore 的自动 ID 分配器从不将属于现有实体的键分配给新实体。

...但我不确定这是否仅适用于预分配 ID 的上下文。

我创建的新实体会覆盖现有实体吗? 或者,尽管父级不同,数据存储区仍会将这些 ID 识别为已使用?

我是否必须预先分配所有现有实体 ID 以防止我的实体被新实体覆盖?

编辑:

我的旧实体有这样的键:

datastore_types.Key.from_path(u'MyKind', 123456789, _app=u's~my-app')

我的新克隆实体具有这样的键(重用旧 ID): datastore_types.Key.from_path(u'ParentKind', 28882914L, u'MyKind', 123456789, _app=u's~my-app')

那么尽管父母不同,Datastore 是否仍会认为此 id 已用于此类?

【问题讨论】:

【参考方案1】:

Datastore 不会认为该 id 已被使用。当 Datastore 分配 ids 时,它从由 Kind 父级确定的序列进行分配(请参阅模型参数 here)。由于您的新模型具有不同的父模型,它们将根据自己的 id 序列进行分配,这可能会与您手动设置的 id 冲突。

仅保证自动创建的 id 不会与其他自动创建的 id 发生冲突(使用未设置 id 的 put 或使用 allocate_ids 方法)。

【讨论】:

如果自动创建的 id 与手动设置的 id 冲突会发生什么?实体似乎永远不会被覆盖,那么会发生什么?实体的创建会失败吗? 在这种情况下,put 调用将失败,id 将被标记为已使用。 它会永久失败还是会自动重试?当我尝试使用allocate_id_range 分配这些手动分配的ID 时,我在生产中收到错误Exceeded maximum allocated IDs。在 SDK 中,当我做同样的事情时,我得到了KEY_RANGE_COLLISION。我想如果可以选择 2**53 个 id 并且这些 id 由 Kind 和 parent 命名空间,那么任何 id 都不太可能发生冲突,但我仍然想消除这种可能性。关于我应该做什么的任何建议? put 本身将立即失败(取决于您使用的库可能重试)。但是,如果您再次调用put,它将使用新的 id 并成功。我建议(如果可能的话)重新放置您当前的实体并让它们获得新的 ID,而不是使用现有的 ID。如果这不是一个选项,我会添加您自己的重试逻辑。【参考方案2】:

如果我猜对了,旧实体将具有以前的 ID + 父 ID,对吗?并且新实体也将具有父 ID。在这种情况下,Datastore 不会覆盖任何实体,因为它从不分配重复的键。

【讨论】:

【参考方案3】:

allocate_id_range 的various possible return values 的描述来看,可以肯定地说,在使用自动ID 分配器时,数据存储永远不会用新实体覆盖现有实体。

From the SDK:

KEY_RANGE_EMPTY = "Empty"
"""Indicates the given key range is empty and the datastore's
automatic ID allocator will not assign keys in this range to new
entities.
"""

KEY_RANGE_CONTENTION = "Contention"
"""Indicates the given key range is empty but the datastore's
automatic ID allocator may assign new entities keys in this range.
However it is safe to manually assign keys in this range
if either of the following is true:

 - No other request will insert entities with the same kind and parent
   as the given key range until all entities with manually assigned
   keys from this range have been written.
 - Overwriting entities written by other requests with the same kind
   and parent as the given key range is acceptable.

The datastore's automatic ID allocator will not assign a key to a new
entity that will overwrite an existing entity, so once the range is
populated there will no longer be any contention.
"""

KEY_RANGE_COLLISION = "Collision"
"""Indicates that entities with keys inside the given key range
already exist and writing to this range will overwrite those entities.
Additionally the implications of KEY_RANGE_COLLISION apply. If
overwriting entities that exist in this range is acceptable it is safe
to use the given range.

The datastore's automatic ID allocator will never assign a key to
a new entity that will overwrite an existing entity so entities
written by the user to this range will never be overwritten by
an entity with an automatically assigned key.
"""

另一个 *** 答案同意:AppEngine allocateIdRange : clarification about CONTENTION state

【讨论】:

以上是关于数据存储区能否生成覆盖我的实体的 ID?的主要内容,如果未能解决你的问题,请参考以下文章

请帮助我了解 GAE 数据存储区中的实体层次结构

如何通过在 Google 数据存储中传递 ID 数组作为输入来检索实体?

从 Google App Engine 中的数据存储区获取实体以在 iOS 应用中使用

从数据存储区查询大量 ndb 实体的最佳实践

数据存储区 - 单个实体组中的资源争用 -

AppEngine 数据存储区查询具有给定属性的所有实体 (Java)