2011-11-13 129 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”); 同样的问题 –

相关问题