Java 从Google应用程序引擎数据存储获取不一致

Java 从Google应用程序引擎数据存储获取不一致,java,google-app-engine,google-cloud-datastore,jdo,datanucleus,Java,Google App Engine,Google Cloud Datastore,Jdo,Datanucleus,我在Google app engine中部署了一个应用程序。当我在更新实体后立即按id获取实体时,我得到的数据不一致。我正在使用JDO3.0访问应用程序引擎数据存储 我有一个实体雇员 @PersistenceCapable(detachable = "true") public class Employee implements Serializable { /** * */ private static final long serialVersionU

我在Google app engine中部署了一个应用程序。当我在更新实体后立即按id获取实体时,我得到的数据不一致。我正在使用JDO3.0访问应用程序引擎数据存储

我有一个实体雇员

@PersistenceCapable(detachable = "true")
public class Employee implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -8319851654750418424L;
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY, defaultFetchGroup = "true")
    @Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
    private String id;
    @Persistent(defaultFetchGroup = "true")
    private String name;
    @Persistent(defaultFetchGroup = "true")
    private String designation;    
    @Persistent(defaultFetchGroup = "true")
    private Date dateOfJoin;    
    @Persistent(defaultFetchGroup = "true")
    private String email;
    @Persistent(defaultFetchGroup = "true")
    private Integer age;
    @Persistent(defaultFetchGroup = "true")
    private Double salary;
    @Persistent(defaultFetchGroup = "true")
    private HashMap<String, String> experience;
    @Persistent(defaultFetchGroup = "true")
    private List<Address> address;


    /**
      * Setters and getters, toString() * */

}
我已经将空闲实例的数量设置为5,一次大约有8个实例在运行。当我检查各种实例的日志时,我发现了这一点。

当请求由某些实例提供服务时,为什么会得到过时的数据。我可以保证,如果fetch请求是由最初处理更新请求的实例处理的,那么我总是会得到更新的数据。但是,当其他实例处理提取请求时,可能会返回过时的数据。我已经在jdoconfig.xml中显式地将数据存储读取一致性设置为strong

<?xml version="1.0" encoding="utf-8"?>
<jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig_3_0.xsd"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig http://java.sun.com/xml/ns/jdo/jdoconfig_3_0.xsd">

   <persistence-manager-factory name="transactions-optional">
       <property name="javax.jdo.PersistenceManagerFactoryClass"
           value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
       <property name="javax.jdo.option.ConnectionURL" value="appengine"/>
       <property name="javax.jdo.option.NontransactionalRead" value="true"/>
       <property name="javax.jdo.option.NontransactionalWrite" value="true"/>
       <property name="javax.jdo.option.RetainValues" value="true"/>
       <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/>
       <property name="datanucleus.appengine.singletonPMFForName" value="true"/>
       <property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true"/>
       <property name="datanucleus.query.jdoql.allowAll" value="true"/>      
       <property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" />

   </persistence-manager-factory>
</jdoconfig>

如果您使用的是高复制数据存储,则设置读取策略并不能确保所有读取都是强一致的,这些读取仅适用于祖先查询。从文件中删除

API还允许显式设置强一致性策略,但此设置没有实际效果,因为不管策略如何,非祖先查询最终都是一致的

请看一下关于的文档,首选的方法是使用缓存层来服务数据


我注意到您使用的是get by ID,不确定,但是“get by key”即使对于HR datastore(),也应该是强一致的,您能尝试将其更改为基于key的查询吗?密钥是使用id、实体种类和祖先构建的。

我有一个建议,但是你不会喜欢:只使用低级API,在使用GAE时忘记JDO/JPA

正如@asp所说,getbyid应该是非常一致的,然而gaejdo插件在我看来似乎有缺陷。不幸的是,迁移到JPA对我的情况也没有帮助(更多信息:)。另外,如果我将任何类注释为@PersistenceAware,Eclipse会变得疯狂,并增强无限循环中的类。另外,在将@PersistenceCapable类与嵌入式类和缓存一起使用时,我遇到了很多问题(没有缓存的情况下,它工作得很好)

好的,重点是,我认为使用低级别API会快得多-您确切地知道正在发生什么,并且它似乎按照预期工作。您可以像对待地图一样对待实体,使用一点自行编写的包装代码,这似乎是一个非常有趣的选择。我运行了一些测试,使用低级API我没有问题地通过了测试,而使用JDO/JPA传递测试是不可能的。我正在将整个应用程序从JDO迁移到低级API。这很耗时,但比无限期地等待GAE团队的神奇解决方案或错误修复要少

而且,在写GAE JDO的时候我觉得。。。单独地如果你在java,甚至android上遇到问题,那么有上千人已经遇到了这个问题,在stackoverflow上询问了这个问题,并得到了大量有效的解决方案。在这里,您只需一个人,所以尽可能使用低级API,您就可以确定发生了什么。尽管迁移看起来非常可怕和耗时,但我认为迁移到低级API比处理GAE JDO/JPA花费的时间要少。我写这篇文章并不是为了扼杀开发GAE JDO/JPA的团队,也不是为了冒犯他们,我相信他们会竭尽全力。但是:

  • 与Android或Java相比,使用GAE的人并不多

  • 在多个服务器实例中使用GAE JDO/JPA并不像您想象的那么简单和直接。像我这样的开发人员希望尽快完成他的工作,看一些示例,阅读一些文档-不要详细研究,阅读一个简短的教程,如果开发人员有问题,他希望在stackoverflow上分享,并获得快速帮助。如果你在Android上做错了什么,很容易得到帮助,不管是复杂还是容易出错。使用GAE JDO/JPA并不是那么容易。我花在GAE JDO文章、教程和文档上的时间比我想的要多得多,我没能完成我想做的事情,尽管它看起来很基本。如果我只是使用低级API,而不尝试用JDO走捷径(是的,我认为JDO会节省我的时间),它会快得多

  • 谷歌更关注Python GAE,而不是Java。在许多面向所有读者的文章中,都有专门的Python代码和提示,这里有一些快速示例:或这里:。我甚至在开始开发之前就注意到了这一点,但我想与我的Android客户端共享一些代码,所以我选择了Java。即使我有坚实的Java背景,即使我现在分享了一些代码,如果我能回到过去再次选择,我现在也会选择Python

  • 这就是为什么我认为最好只使用最基本的方法来访问和操作数据

    祝你好运,祝你一切顺利。

    在实体类中添加
    @Cacheable(value=“false”)
    。这个问题将得到解决

    上述问题主要是由于JDO缓存。因此,如果我们禁用缓存,JDO将从数据存储中读取数据

    或者可以在jdoconfig.xml中禁用二级缓存。


    参考链接:

    查看“最终一致性”,因为这听起来像是这样。@PaulCollingwood我已将数据存储读取一致性设置为“强”。看到最后一个了吗comment@ichathan例如我已经试过了。不工作。我尝试使用低级API获取操作。它很好用。其余的操作仍然使用JDO。不确定这是否会导致进一步的问题。我也有同样的问题,我按照你的建议做了一个“按键获取”。所以我用query.execute(KeyFactory.createKey(…)替换了pm.getObjectById(…)。到目前为止,我无法重现这个问题。还有其他人尝试过这个改变吗?我想,但无法撤消我的否决票,但我认为这可能是一个正确的answ
    <?xml version="1.0" encoding="utf-8"?>
    <jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig_3_0.xsd"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig http://java.sun.com/xml/ns/jdo/jdoconfig_3_0.xsd">
    
       <persistence-manager-factory name="transactions-optional">
           <property name="javax.jdo.PersistenceManagerFactoryClass"
               value="org.datanucleus.api.jdo.JDOPersistenceManagerFactory"/>
           <property name="javax.jdo.option.ConnectionURL" value="appengine"/>
           <property name="javax.jdo.option.NontransactionalRead" value="true"/>
           <property name="javax.jdo.option.NontransactionalWrite" value="true"/>
           <property name="javax.jdo.option.RetainValues" value="true"/>
           <property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/>
           <property name="datanucleus.appengine.singletonPMFForName" value="true"/>
           <property name="datanucleus.appengine.datastoreEnableXGTransactions" value="true"/>
           <property name="datanucleus.query.jdoql.allowAll" value="true"/>      
           <property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" />
    
       </persistence-manager-factory>
    </jdoconfig>