“...删除操作是否有可能删除新的有缺陷的小部件?”
没有。
“将始终(最终)运行以下代码导致我们的数据存储区中有一个有缺陷的小部件”
也没有。以前有缺陷的小部件可能没有被删除。
Cloud Datastore 在查找(按键获取)和祖先查询方面高度一致。它最终在非祖先查询上是一致的。思考 Cloud Datastore 如何处理一致性的一种方式是:
- 实体写入被同步写入/删除
- 索引是异步更新的(大部分时间是立即更新,但并非总是如此)
- 实体组定义数据局部性,因此祖先查询强制实现强一致性
让我们看看你的例子
为了参数,让我们先设置一个示例数据集。一些代码添加了新的有缺陷的小部件:
WidgetA(defective=True).put()
WidgetB(defective=True).put()
WidgetC(defective=True).put()
现在我们有了:
WidgetA(defective: True)
WidgetB(defective: True)
WidgetC(defective: True)
进行查找(按键获取)将始终返回这 3 个实体,因为查找是高度一致的。
在这 3 个小部件被添加后,一些代码想要获取所有有缺陷的小部件的列表。
defective_widgets = Widget.query(Widget.defective == True).fetch(keys_only=True)
然后发出调用将它们全部删除:
ndb.delete_multi(defective_widgets)
我们现在在数据库中有哪些数据?答案是 WidgetA、B 和 C 的任意组合,或者它们都没有,甚至全部都没有。为什么?因为发出的查询最终是一致的,并且取决于是否应用了索引更新来确定defective_widgets 中的实体键列表是否。
因此,此时,在您最终执行 Widget(defective=True).put() 后,您的数据库中可能会有 1 到 4 个有缺陷的小部件。
如何避免这种情况?
选项 1(实体组):如果有缺陷的小部件总是以每秒 1 个事务或更低的速度写入/更新,那么您可以将它们全部放在一个实体组中,修改您的查询成为祖先查询 = 然后一切都将最终保持一致。注意:如果您可以在一个事务中一起批处理小部件写入/更新,则所有这些写入仅计为 1 个事务,例如,将 500 个小部件一起批处理允许您每秒执行 500 个小部件。
选项2(软删除):如果你的写入率很高,你可以实现一个软删除系统。单个实体(缓存,我们称之为“版本实体”)存储一个单调递增的版本号(整数)。任何新编写的有缺陷的小部件也会将此编号存储在名为“版本”的属性中。当您想要删除一组小部件时,将版本实体中的数字加一,并启动对版本低于新版本号的所有小部件的查询。对于处理小部件的任何查询,检查版本是否小于当前版本号,如果是,则从进程中丢弃(它被软删除)。您可以通过包含 version = current 过滤器对其进行优化,以便查询不会返回大多数软删除的项目。