2011-11-13 131 views
3

我無法弄清楚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; 
    } 
} 

回答

3

嘗試在jdoconfig.xml添加此:

<property name="datanucleus.appengine.datastoreReadConsistency" value="STRONG" /> 

爲了提高性能;應用程序引擎數據存儲「最終一致」。這意味着當你製作新的物體或改變現有的物體時,它不會馬上顯示;可以在查找時間中提高性能。與此相反的是「強」的一致性,這意味着每個請求都使用數據存儲區中的最新數據進行。

現在,根據app engine documentation for this STRONG一致是默認的,你必須明確設置最終一致性。但是,從我觀察到的,你必須設置STRONG一致性,EVENTUAL是默認的(錯誤也許?)。因此,請嘗試將以上內容添加到您的jdoconfig xml中,如果您觀察到我做過的同樣的事情,那麼我可能會打開一個針對應用程序引擎的錯誤,假設此問題尚未打開。

你必須記住的一件事是,如果你設置STRONG一致性,你將會受到性能影響。我只是設置它,因爲我的界面有些部分被搞亂了,因爲我會用一些不太新鮮的數據來構建它的一部分,並且在同一個請求中,另一部分會用新的數據構建;使我的界面不一致。這可能是解決問題的一種廣泛方法;但它的作品:)。

+0

感謝您的回覆。我添加了該屬性,但沒有改變。我仍然需要循環幾次,試圖獲取數據,然後它成功:(非常奇怪。 –

+0

當我第一次發佈這個答案時,我不小心發佈了''但它應該是''(注意'STRONG'與'EVENTUAL'相對)這是我的錯;但是你確定你嘗試過'STRONG'設置嗎? – Dave

+0

嘿嘿,是的,我試着用STRONG設置。我也在我的查詢中嘗試了以下內容:query.addExtension(「datanucleus.appengine.datastoreReadConsistency」,「STRONG」); 同樣的問題 –

相關問題