我一直在尽可能地关注app引擎JDO文档,但是我在加载Board对象包含的持久集合时遇到了困难和不一致的问题。在手动将“最终一致性”指定为不存在之后,即使在本地开发Web服务器中也会出现不一致。
有时当我使用我创建的加载助手方法加载我的对象/集合时,它没有加载任何问题。其他时候会返回一个空集合(请注意我 am “使用getter方法”触摸“该集合以确保数据不仅仅是一个延迟加载到代理对象中)。
最初我认为问题只是由于高复制存储引擎的“最终一致性”缺点而相关,但是在LocalServiceTestHelper中制定了我自己的0%最终一致性策略之后,我很确定情况并非如此。 / p>
我已经创建了一个JUnit测试来举例说明这个问题。基本上,我尝试在testInsertUser函数中创建并保存一个虚拟的User和Board对象。我将新创建的PlayedTile对象的ArrayList附加到此板,然后执行DataMaster.saveUser帮助器方法,该方法使用Google App Engine的持久性管理器将用户(以及Board和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;
}
奇怪的是,这个代码SOMETIMES按预期工作:它在testReadUser()中从数据存储区加载后,打印出它保存的完全相同的一组tile。有时它只是加载一个空集合,虽然特别令人讨厌的是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:
完全随意。
那里有人可以对此有所启发吗?这让我完全疯了。 :)
编辑:另一个奇怪的线索/事实是,如果我通过在for循环中包含testSaveUser和testReadUser方法调用来完成整个测试迭代,则每个加载操作都可以正确执行,或者没有他们这样做。这是本地Google App Engine测试环境中的错误吗?
答案 0 :(得分:1)
只是为了检查:您是否将数据类标记为可拆卸?即。
@PersistenceCapable(detachable = "true")
public class Board { /* fun stuff here */ }
此外,查看数据存储区查看器以查看是否真的有效可能会有所帮助:http://localhost:8888/_ah/admin/