我無法弄清楚Google App Engine JDO的實現有問題。該文檔(http://code.google.com/intl/sv-SE/appengine/docs/java/datastore/jdo/creatinggettinganddeletingdata.html)指出「對makePersistent()的調用是同步的,直到保存對象並更新索引時纔會返回。」但我的經歷不同。Google App Engine JDO makePersistent延遲
我想將(makePersistent)對象保存到數據存儲中。保存完成後,我希望能夠立即從數據存儲中讀取(查詢執行)。我知道我不必獲取它(因爲我已經在內存中擁有該對象),但重點是我希望下一個請求能夠從數據存儲中檢索數據。如果第二個請求足夠快,那麼這與當前實現無關。
我注意到的一件奇怪的事情是,如果我試圖在數據存儲中從數據存儲中取回對象幾次(下面的代碼),對象返回非常快(通常爲< 10ms)。但是如果我跳過循環,而是在makePersistent和查詢執行之間運行Thread.sleep(..)5000毫秒,則不確定是否找到該對象。這些解決方案都不是我想要的。我希望能夠在沒有睡眠或循環之間立即獲取數據。
下面的代碼和訪問DataStoreTestServlet的結果如您所見,包括「等待」數據的循環。再次,我不想要循環。
有誰知道我錯過了什麼?我想它必須是某種東西。這個實現不適合我:)。
我使用的是appengine-java-sdk-1.6.0。這是本地(開發服務器)和部署在Google服務器上的問題。
下面是訪問該servlet的結果。
Created users:
User [password=password, userName=user1321190966416] took 18ms, 2 loop(s)
User [password=password, userName=user1321190966438] took 15ms, 6 loop(s)
User [password=password, userName=user1321190966456] took 2ms, 1 loop(s)
User [password=password, userName=user1321190966460] took 10ms, 5 loop(s)
User [password=password, userName=user1321190966472] took 0ms, 1 loop(s)
User [password=password, userName=user1321190966472] took 0ms, 1 loop(s)
User [password=password, userName=user1321190966472] took 16ms, 1 loop(s)
User [password=password, userName=user1321190966488] took 0ms, 2 loop(s)
User [password=password, userName=user1321190966488] took 0ms, 1 loop(s)
User [password=password, userName=user1321190966488] took 16ms, 1 loop(s)
代碼和配置。
jdoconfig.xml
<?xml version="1.0" encoding="utf-8"?>
<jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">
<persistence-manager-factory name="transactions-optional">
<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"/>
<property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" />
</persistence-manager-factory>
</jdoconfig>
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;
}
}
User.java
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class User {
@PrimaryKey
@Persistent
private String userName;
@Persistent
private String password;
public User(String userName, String password) {
super();
this.setUserName(userName);
this.setPassword(password);
}
public String getUserName() {
return userName;
}
public String getPassword() {
return password;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setPassword(String password) {
this.password = password;
}
public String toString() {
return "User [password=" + password + ", userName=" + userName + "]";
}
}
DataStoreTestServlet.java
import java.io.IOException;
import java.util.List;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@SuppressWarnings("serial")
public class DataStoreTestServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
StringBuffer sb = new StringBuffer();
sb.append("Created users:\n");
for (int i = 0; i < 10; i++) {
String uniqueName = "user" + System.currentTimeMillis();
User user = new User(uniqueName, "password");
save(user);
User userFromDS = null;
long startTime = System.currentTimeMillis();
long loop = 0;
while (userFromDS == null) {
userFromDS = get(uniqueName);
loop++;
if (userFromDS != null) {
long endTime = System.currentTimeMillis();
sb.append(userFromDS.toString() + " took " + (endTime - startTime) + "ms, " + loop + " loop(s)\n");
}
}
}
resp.setContentType("text/plain");
resp.getWriter().println(sb.toString());
}
public Object save(Object obj) {
PersistenceManager pm = PMF.get().getPersistenceManager();
Object savedObject = null;
try {
savedObject = pm.makePersistent(obj);
} finally {
pm.close();
}
return savedObject;
}
public User get(String userName) {
User user = null;
List<User> users = null;
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery(User.class);
query.setFilter("userName == nameParam");
query.declareParameters("String nameParam");
try {
users = (List<User>) query.execute(userName);
if (users != null && users.size() > 0) {
user = users.get(0);
}
} finally {
query.closeAll();
pm.close();
}
return user;
}
}
感謝您的回覆。我添加了該屬性,但沒有改變。我仍然需要循環幾次,試圖獲取數據,然後它成功:(非常奇怪。 –
當我第一次發佈這個答案時,我不小心發佈了' '但它應該是' '(注意'STRONG'與'EVENTUAL'相對)這是我的錯;但是你確定你嘗試過'STRONG'設置嗎? –
Dave
嘿嘿,是的,我試着用STRONG設置。我也在我的查詢中嘗試了以下內容:query.addExtension(「datanucleus.appengine.datastoreReadConsistency」,「STRONG」); 同樣的問題 –