2

我一直在尽可能地关注应用程序引擎 JDO 文档,但是在加载我的 Board 对象包含的持久集合时遇到了奇怪且不一致的问题。在我手动将“最终一致性”指定为不存在后,即使在本地开发 Web 服务器中也会出现不一致。

有时,当我使用我创建的加载辅助方法加载我的对象/集合时,它加载没有问题。其他时候会返回一个空集合(请注意,我正在使用 getter 方法“接触”该集合,以确保数据不仅仅是延迟加载到代理对象中)。

最初我认为这个问题只是由于高复制存储引擎的“最终一致性”缺陷而导致的,但在我自己制定了 LocalServiceTestHelper 中最终一致性为 0% 的策略之后,我相当确定情况并非如此。

我创建了一个 JUnit 测试来说明这个问题。基本上,我尝试在 testInsertUser 函数中创建并保存一个虚拟的 User 和 Board 对象。我将一个新创建的 PlayedTile 对象的 ArrayList 附加到此板,然后执行 DataMaster.saveUser 辅助方法,该方法使用 Google App Engine 的持久性管理器将用户(以及板和 PlayedTile 集合)保存到数据存储区。在下一个方法中,我们尝试加载该用户(及其 Board 和 PlayedTile 集合)并显示那些保存的结果。混乱随之而来。

这是 JUnit 代码:

package com.astar.wordswall.test.data;

import java.util.ArrayList;

import com.astar.wordswall.data.DataMaster;
import com.astar.wordswall.data.jdo.Board;
import com.astar.wordswall.data.jdo.User;
import com.astar.wordswall.data.jdo.PlayedTile;
import com.astar.wordswall.test.appengine.LocalCustomHighRepPolicy;
import com.google.appengine.api.datastore.Key;

import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
// import com.google.gwt.user.client.Random;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;


public class SaveUsersBoardWithTilesTest {

    Key userKey;

    private final LocalServiceTestHelper helper =
        new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
            .setAlternateHighRepJobPolicyClass(LocalCustomHighRepPolicy.class));

    @Before
    public void setUp() {
        helper.setUp();
    }

    @After
    public void tearDown() {
        helper.tearDown();
    }

    @Test
    public void testInsert1() {
        testInsertUser();
        testReadUser();
    }

    /**
     * Creation and insertion of a user, board, and linked set of tiles into BigTable.
     */
    private void testInsertUser() {
        User u = new User("Simon");
        Board b = new Board();
        ArrayList<PlayedTile> tiles = new ArrayList<PlayedTile>(7);

        u.setBoard(b);
        b.setPlayedTiles(tiles);

        for (int j = 0; j < 7; j++) tiles.add(new PlayedTile('T'));

        DataMaster.saveUser(u);
        // Retrieve the user's key so that we can read him from the database later
        userKey = u.getUserKey();

        // Display all of our saved tiles:
        System.out.println("Saved tiles:");
        // Note that "getTileString()" just iterates through each Played tile printing the letter
        System.out.println("\t" + u.getBoard().getTileString());
    }

    /**
     * A typical read of a user object from the Datastore.
     */
    private void testReadUser() {
        User u = DataMaster.getUserWithBoard(userKey);
        // Display all of our saved tiles:
        System.out.println("Loaded tiles:");
        System.out.println("\t" + u.getBoard().getTileString());
    }
}

这是实际执行 JDO 加载的相关 DataMaster.getUserWithBoard 静态函数:

/**
 * Loads a uniquely specified User and their associated board from 
 * the Datastore.  It also loads the board's complete list of PlayedTiles.
 * @param userKey the unique key assigned to this user
 */
public static User getUserWithBoard(Key userKey){
    User u = null;
    PersistenceManager pm = PMF.get().getPersistenceManager();
    try{
        u = pm.getObjectById(User.class, userKey);
        // In order for the board and tile collection to load, we must "touch" it while PM is active
        if (u.getBoard().getPlayedTiles().size() != 0) u.getBoard().getPlayedTiles().get(0);
        if (u.getBoard().getPlayedWords().size() != 0) u.getBoard().getPlayedWords().get(0);
    } finally{
        pm.close();
    }
    return u;
}

奇怪的是,这段代码有时会按预期工作:它会打印出与 testReadUser() 中的数据存储区加载后保存的完全相同的图块集。有时它只是加载一个空集合,尽管特别奇怪的是 u.getBoard().getPlayedWords().get(0) 调用不会引发空指针异常。

输出在之间振荡

正确的:

Saved tiles:
    T T T T T T T 
Loaded tiles:
    T T T T T T T 

并且不正确:

Saved tiles:
    T T T T T T T 
Loaded tiles:

完全随意。

那里的任何人都可以对此有所了解吗?这让我彻底疯了。:)

编辑:另一个奇怪的线索/事实是,如果我通过将 testSaveUser 和 testReadUser 方法调用都包含在 for 循环中来使整个测试迭代,则每个加载操作都可以正确执行,或者它们都不会正确执行。这是本地 Google App Engine 测试环境中的错误吗?

4

1 回答 1

1

只是检查一下:您是否将数据类标记为可拆卸?IE

@PersistenceCapable(detachable = "true")
public class Board { /* fun stuff here */ }

此外,查看数据存储查看器以查看是否真的有效可能会有所帮助: http://localhost:8888/_ah/admin/

于 2011-07-31T03:47:02.893 回答