1

我有一个在 GAE for Java 上运行并使用应用引擎 Datastore 和 Objectify 4 的 Web 应用程序。

当用户从 web 提交一个包含多个字段的表单时,应用程序的逻辑应该将这些值发布到数据存储区,读取数据列表(包括这些最后的值)并返回到 web,显示这些最后提交的更改以及其余数据。大多数时候它工作正常。

但是,有时(实际上很少发生),新值被保存,但是当返回网络时,它们不会出现在网络上。但是只是在几秒钟后刷新浏览器(因此刷新了阅读过程),值就在那里,因为它们应该是第一次。

在我的本地环境中进行测试,这也发生在我身上几次,我收到一个错误,说用于模拟数据存储的文本文件(称为 local_db.bin)在“保存”或“阅读”的过程,可能是因为这个过程太快了,而且新的值还不可用(不过这是我的看法)。所以我想类似的事情可能会发生在真正的数据存储上。

你知道如何以简单的方式避免这个问题吗?(如果可能,避免同步块等)

4

1 回答 1

4

由于使用没有祖先查询的高复制数据存储,听起来您遇到了最终一致性问题。为强一致性构建数据(强调添加):

Google App Engine 的 High Replication Datastore (HRD) 通过在多个数据中心同步存储数据,为您的读写提供高可用性。但是,从提交写入到它在所有数据中心中可见的延迟意味着跨多个实体组的查询(非祖先查询)只能保证最终一致的结果。因此,此类查询的结果有时可能无法反映基础数据的最新更改

要获得高度一致的查询结果,您需要使用祖先查询将结果限制为单个实体组。这是有效的,因为实体组是一致性和事务性的单位。所有数据操作都应用于整个组;在整个实体组更新之前,祖先查询不会返回其结果。如果您的应用程序依赖于某些查询的高度一致的结果,您可能需要在设计数据模型时考虑到这一点。本页讨论了构建数据以支持强一致性的最佳实践。

这是使用该文档中的祖先查询进行编写的示例:

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;

String guestbookName = req.getParameter("guestbookName");
Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
String content = req.getParameter("content");
Date date = new Date();

// Place greeting in same entity group as guestbook
Entity greeting = new Entity("Greeting", guestbookKey);
greeting.setProperty("user", user);
greeting.setProperty("date", date);
greeting.setProperty("content", content);

并阅读:

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;

DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();

Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
Query query = new Query("Greeting", guestbookKey)
                    .setAncestor(guestbookKey)
                    .addSort("date", Query.SortDirection.DESCENDING);

List<Entity> greetings = datastore.prepare(query)
                                  .asList(FetchOptions.Builder.withLimit(10));

文档中更详细地讨论了使用祖先查询的注意事项。

于 2013-01-23T20:18:35.377 回答