尝试使用Objectify加载给定类型的所有实体时遇到不一致。
设置
我在本地运行Cloud Endpoints后端,并使用以下方法填充数据存储区:
public static void dsUp() {
Store store1 = new Store("H&M", new GeoPt(new Float(56.157702), new Float(10.206938)));
Store store2 = new Store("Marc Jacobs", new GeoPt(new Float(56.158284), new Float(10.208618)));
Store store3 = new Store("Weekday", new GeoPt(new Float(56.158522), new Float(10.207547)));
ofy().save().entities(store1, store2, store3).now(); // Synchronous save to auto generate id
}
设置数据库后,数据存储查看器显示已创建的所有三个对象:
问题
我开始注意到我的客户端应用程序(iOS)有时只收到两个商店:
我在后端重新访问了我的getStores()方法,并对其进行了更改,以便将所有Stores加载4次,记录每次尝试,最后从第一次尝试返回结果。
该方法(在将其更改为多次加载尝试后),如下所示:
public static List<Store> getStores() {
List<Store> result = ofy().load().type(Store.class).list();
LOGGER.warning("Getting Stores, try 1: " + result.toString());
LOGGER.warning("Getting stores, try 2: " + ofy().load().type(Store.class).list());
LOGGER.warning("Getting stores, try 3: " + ofy().load().type(Store.class).list());
LOGGER.warning("Getting stores, try 4: " + ofy().load().type(Store.class).list());
return result; // Returning the results from try 1
}
通常,每次尝试都会返回所有三个商店。但是,有时第一次尝试,甚至第二次尝试将只返回两个商店。通过第三次和第四次尝试,返回所有商店。
其中一个方法调用的记录输出如下所示。请注意,这次尝试1和2只返回两个商店。
我看不到数据库重置之间遗漏了哪个Store的模式。有时它是一个,有时是另一个。但是,似乎在getStores()的同一个调用中,如果尝试1和2都失败,它似乎缺少相同的存储(如上图所示)。
我尝试了什么?
我最初的想法是我必须设置Objectify过滤器错误。但是,就我所知,它似乎是有序的。在我的webapp / WEB-INF / web.xml文件中,我有以下过滤器和过滤器映射:
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
我对Objectify的缓存还不太熟悉,但我尝试了以下内容:
在加载任何实体之前,在后端的getStores()方法中添加以下行作为第一行:
ofy().clear(); // Clear the cache
我在加载实体时也尝试使用STRONG一致性,如下所示:
List<Store> result = ofy().consistency(ReadPolicy.Consistency.STRONG).load().type(Store.class).list();
可能相关的其他信息
我可以重新创建不一致性,它发生约1/5次。但是,据我所知,只有在使用前面提到的dsUp()方法从头开始设置数据库之后才会发生这种情况。
在尝试之间,我使用以下方法清除数据库:
public static void dsDown() {
List<Key<Store>> allStoreKeys = ofy().load().type(Store.class).keys().list();
ofy().delete().keys(allStoreKeys).now();
}
就数据存储区查看器而言,dsDown()方法按预期工作,并使数据库为空。据我所知,直接在数据库查看器中删除实体可能会导致不删除缓存的问题。但是我已经读过在dsDown()方法中使用Objectify删除实体可以避免这个问题。
如果我有任何其他信息,请告知我们。
谢谢!
编辑(我实施@saiyr的解决方案):
正如@saiyr所说,数据存储区在本地运行时模拟最终的一致性,这导致了不一致。以下屏幕截图显示了我如何将标志添加到后端模块的build.gradle文件中。
注意:请注意,如果完全关闭模拟的最终一致性(将标志设置为0)可能会导致Objectify事务出错。这就是我将标志设置为1的原因。有关详细信息,请参阅this stack overflow post。
您希望将标志添加到后端项目的build.gradle文件中:
答案 0 :(得分:2)
开发服务器数据存储区emulates eventual consistency。您在Objectify中将一致性设置为STRONG
是一项无操作,因为您can't enforce strong consistency on non-ancestor queries。对于开发服务器,您可以尝试将datastore.default_high_rep_job_policy_unapplied_job_pct
值设置为零以绕过此行为,但请注意,这只会影响本地开发。