App-Engine JDO一致阅读不起作用,也许是缓存?

时间:2011-12-17 18:35:40

标签: eclipse google-app-engine gwt jdo datanucleus

今天我第一次使用GWT和JDO。我在本地调试模式下使用Eclipse运行它。

我做了以下事情:

    public Collection<MyObject> add(MyObject o) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
    pm.makePersistent(o);
    Query query = pm.newQuery(MyObject.class);// fetch all objects incl. o. But o only sometimes comes...
List<MyObject> rs = (List<MyObject>) query.execute();
ArrayList<MyObject> list= new ArrayList<MyObject>();
for (MyObject r : rs) {
    list.add(r);
}
return list; 
} finally {
    pm.close();
}
}

我已在<property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" />中设置了jdoconfig.xml。我是否必须在配置中设置其他一些事务?有人找到了工作jdoconfig.xml吗?或者是其他地方的问题?中间有一些缓存?

编辑:我尝试过的事情:

  • 将NontransactionalRead / Write设置为false
  • 使用相同/不同的PersistenceManager,但多次调用PMF.get().getPersistenceManager()
  • 使用交易
  • PersistenceManager
  • 上的ignoreCache = true
  • 致电flushcheckConsistency

jdoconfig:

    <persistence-manager-factory name="transactions-optional">
<property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" />
    <property name="javax.jdo.PersistenceManagerFactoryClass"
        value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>
    <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"/>
</persistence-manager-factory>

我必须在这里遗漏一些东西,因为所有方法都失败了......

EDIT2:当我将作业拆分为两个事务时,日志表示写入事务已完成,然后读取事务开始。但它没有找到刚才持久的对象。它总是说Level 1 Cache of type "weak" initialised。周是坏还是好?

大约30%的请求出错了......我可能会遇到一些懒惰的查询加载问题吗?

3 个答案:

答案 0 :(得分:2)

调用makePersistent()方法不会写入数据存储区;关闭PersistenceManager或提交更改。由于在运行查询时尚未执行此操作,因此您将从数据存储区获取所有对象,但尚未包含刚刚调用makePersistent的对象。

在这里阅读对象状态: http://db.apache.org/jdo/state_transition.html

有两种解决方法,你可以把它放在一个事务中,因为提交写入数据存储区(记住事务中的GAE 5事务/实体类型限制)并在运行查询之前提交; 使用事务的示例...

public Collection<MyObject> add(MyObject o) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    ArrayList<MyObject> list = null;
    try {
        Transaction tx=pm.currentTransaction();
        try {
            tx.begin();
            pm.makePersistent(o);
            tx.commit(); 
        } finally {
            if (tx.isActive()) {
                tx.rollback();
            }
        }

        Query query = pm.newQuery(MyObject.class);
        List<MyObject> rs = (List<MyObject>) query.execute();
        ArrayList<MyObject> list = new ArrayList<MyObject>();
        for (MyObject r : rs) {
            list.add(r);
        }
    } finally {
        pm.close();
    }

    return list; 
}

或者你可以在o上调用makePersistent之后关闭持久性管理器,然后打开另一个来运行你的查询。

// Note that this only works assuming the makePersistent call is successful
public Collection<MyObject> add(MyObject o) {
    PersistenceManager pm = PMF.get().getPersistenceManager();
    try {
        pm.makePersistent(o);
    } finally {
        pm.close();
    }

    pm = PMF.get().getPersistenceManager();
    ArrayList<MyObject> list = null;
    try {

        Query query = pm.newQuery(MyObject.class);
        List<MyObject> rs = (List<MyObject>) query.execute();
        list= new ArrayList<MyObject>();
        for (MyObject r : rs) {
            list.add(r);
        }

    } finally {
        pm.close();
    }

    return list; 
}

注意:我原先说过你可以在返回之前将o添加到结果列表中;但是,如果将o写入数据存储区时出现问题,那么这不是一件明智的事情;然后返回的列表不会反映数据存储区中的实际数据。我现在所做的事情(提交事务或关闭pm然后再获得另一个事务)应该可以正常工作,因为你已将datastoreReadPolicy设置为STRONG。

答案 1 :(得分:2)

Franz,JDO Config中的默认读取一致性是STRONG。所以如果你试图在那个方向接近它,它就不会引导你到任何地方

检查一下,因为我认为它提到了与你遇到的场景类似的东西,提交的数据没有在查询中返回。如上所述它并不是并发的,但它解释了提交过程。

http://code.google.com/appengine/articles/transaction_isolation.html

另外,另一种方法是使用Extents进行查询,并查明是否解决了您正在查看的特定用例,因为我相信您正在提取表中的所有记录。

编辑:

因为在您提到的代码段中,它会查询整个表。如果这就是你所需要的,你可以使用一个范围...... 使用它的方法是通过调用

Extent ext = getExtent(<Entity Class name>)

在persistenceManager单例对象上。然后,您可以遍历范围

查看文档并在此处搜索范围。 http://code.google.com/appengine/docs/java/datastore/jdo/queries.html

答案 2 :(得分:1)

我遇到了同样的问题但这并没有帮助。因为它似乎是谷歌在eclipse&#34; jdo app引擎一致性方面的最佳结果。我想我会为我分享修复工具!

原来我使用PersistenceManagerFactory的多个实例导致了一些奇怪的行为。修复是每个代码访问一个单例。实际上这是GAE教程documented correctly,但我认为它的重要性是低估的。

  

获取PersistenceManager实例

     

应用程序使用PersistenceManager的实例与JDO交互   类。您可以通过实例化和调用方法来获取此实例   PersistenceManagerFactory类的一个实例。工厂使用   用于创建PersistenceManager实例的JDO配置。

     

因为PersistenceManagerFactory实例需要时间来初始化,   应用程序应该重用单个实例。一种简单的方法来管理   PersistenceManagerFactory实例是创建单例包装器   具有静态实例的类,如下所示:

     

<强> PMF.java

import javax.jdo.JDOHelper;
import javax.jdo.PersistenceManagerFactory;

    public final class PMF {
        private static final PersistenceManagerFactory pmfInstance =
            JDOHelper.getPersistenceManagerFactory("transactions-optional");

        private PMF() {}

        public static PersistenceManagerFactory get() {
            return pmfInstance;
        }
    }