使用GAE上的游标进行JDO查询会返回不一致的结果

时间:2014-08-19 07:59:44

标签: java google-app-engine gwt jdo

我正在运行对GAE服务器的GWT RPC调用,查询使用JDO存储在数据存储区中的文章对象,并且我使用游标对结果进行分页。

我发送一个初始RPC调用,以10个结果的“范围”开始分页。我将查询光标存储在memcache中,并在用户请求下一页10个结果时检索它。实现此目的的代码如下所示。

范围总是相同的,10个结果。但是,某些后续RPC调用返回2个结果,或12个结果。这是非常不一致的。调用有时也会返回重复的结果。

我已阅读此Google开发人员文档:https://developers.google.com/appengine/docs/java/datastore/queries#Java_Limitations_of_cursors。它提到:“游标并不总是按预期工作,使用不等式过滤器或具有多个值的属性上的排序顺序。这种多值属性的重复数据删除逻辑在检索之间不会持续存在,可能导致相同的结果不止一次返回。“

正如您在代码中看到的那样,我正在对“date”属性进行排序。此属性只有一个值。

你能让我看看我在这里做错了吗?感谢。

这是在GAE服务器上执行RPC调用的代码:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.List;
import java.util.logging.Logger;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpSession;

import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.datanucleus.query.JDOCursorHelper;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

//...

private void getTagArticles(String tag, int range, boolean start) {

    PersistenceManager pm = PMF.getNonTxnPm();
    ArticleStreamItemSummaryDTO aDTO = null;
    ArticleStreamItem aDetached = null;
    summaryList = new ArrayList<ArticleStreamItemSummaryDTO>();
    String cursorString = null;
    session = getThreadLocalRequest().getSession();
    UserAccount currentUser = LoginHelper.getLoggedInUser(session, pm);
    String cursorID = currentUser.getId().toString() + tag;

    if (start) { // The start or restart of the query
        CacheSupport.cacheDelete(String.class.getName(), cursorID);
    }

    Object o = CacheSupport.cacheGet(String.class.getName(), cursorID);
    if (o != null && o instanceof String) {
        cursorString = (String) o;
    }

    Query q = null;
    try {
        q = pm.newQuery(ArticleStreamItem.class);

        if (cursorString != null) {
            Cursor cursor = Cursor.fromWebSafeString(cursorString);
            Map<String, Object> extensionMap = new HashMap<String, Object>();
            extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
            q.setExtensions(extensionMap);
        }   
        q.setFilter("tag == tagParam");
        q.declareParameters("String tagParam");
        q.setOrdering("date desc");
        q.setRange(0, range);

        @SuppressWarnings("unchecked")
        List<ArticleStreamItem> articleStreamList = (List<ArticleStreamItem>) q.execute(tag);

        if (articleStreamList.iterator().hasNext()) {
            Cursor cursor = JDOCursorHelper.getCursor(articleStreamList);
            cursorString = cursor.toWebSafeString();
            CacheSupport.cacheDelete(String.class.getName(), cursorID);
            CacheSupport.cachePutExp(String.class.getName(), cursorID, cursorString, CACHE_EXPIR);
            for (ArticleStreamItem a : articleStreamList) {
                aDetached = pm.detachCopy(a);
                aDTO = aDetached.buildSummaryItem();
                summaryList.add(aDTO);
            }
        }
    }
    catch (Exception e) {
        // e.printStackTrace();
        logger.warning(e.getMessage());
    }
    finally {
        q.closeAll();
        pm.close();
    }
}

1 个答案:

答案 0 :(得分:1)

我在上面的问题中提供的代码段实际上效果很好。问题来自客户端。 RPC调用有时会相隔几毫秒,这就是我在返回的结果中看到的不一致行为。

我更改了客户端代码,每5秒进行一次RPC调用,然后修复它。