【问题标题】:Google App Engine Datastore too slow persistenceGoogle App Engine Datastore 持久性太慢
【发布时间】:2013-05-02 17:24:42
【问题描述】:

我正在开发一个 GAE/J 应用,使用 JDO 来管理数据存储区。它提供了许多端点来与数据等进行交互。我还在为这些端点开发一个 Javascript 客户端。

情况:

首先我有一个端点方法Token getSessionToken(User usr),它生成一个会话令牌,将其分配给用户并将用户和会话令牌存储在数据存储中。

然后我有另一个端点方法Info getInfo(Token token) 接收会话令牌,检查该会话令牌是否对应于用户,如果是,则返回一些信息。

问题

从我的 Javascript 客户端,我调用了第一个方法,一切都很好。然后我使用先前检索的会话令牌调用第二种方法,我收到一条错误消息,指出会话令牌不对应于任何用户...

我检查了一下,发现这个错误只是因为新的会话令牌还没有被持久化!

问题

我目前的解决方案是让Javascript客户端调用第二个方法一次,如果收到错误,稍等片刻再调用...有没有更好的解决方案?


编辑:

这是第一个方法调用中涉及的代码,用于了解为什么需要这么长时间...

端点:

@ApiMethod(
    name = "getSessionToken",
    path = "get_session_token",
    httpMethod = HttpMethod.GET
)
public SessionToken getSessionToken (@Named("email") String email, @Named("password") String password) 
        throws InternalServerErrorException {       
    SessionToken sessionToken = new UsersController().getSessionToken(email, password);
    return sessionToken;
}

控制:

public SessionToken getSessionToken(String email, String password) throws InternalServerErrorException {        
    SessionToken sessionToken = null;
    
    PersistenceManager pm = PMF.get().getPersistenceManager();      
    Transaction txn = DatastoreServiceFactory.getDatastoreService().beginTransaction();
    try {
        DAO dao = new DAO(pm);
        
        User user = dao.getUserByLogin(email, password);
        
        dao.deleteSessionToken(user.getSessionToken());
        sessionToken = SessionTokenManager.generateToken(user.getEmail(), user.getPassword());
        user.setSessionToken(sessionToken);
        
        user = dao.insertUser(user);    
    
        txn.commit();   
    
    } catch (Exception e) {
        throw new InternalServerErrorException();
    } finally {
        if (txn.isActive()) {
            txn.rollback();
        }
        pm.close();
    }       
    return sessionToken;
}

道:

public User getUserByLogin(String email, String password) throws InternalServerErrorException {
    User user = null;
    Query query = null;
    try {
        query = this.pm.newQuery(User.class);
        query.setFilter("email == emailParam && password == passwordParam");
        query.declareParameters("String emailParam, String passwordParam");     
        List<User> results = (List<User>) query.execute(email, password);
        user = results.get(0);
    } catch (Exception e) {
        e.printStackTrace();
        throw new InternalServerErrorException("Error in DAO.getUserByLogin()");
    } finally {
        query.closeAll();
    }
    return user;
}

/////

public void deleteSessionToken(SessionToken sessionToken) throws InternalServerErrorException {
    try {
        this.pm.deletePersistent(sessionToken);
    } catch (Exception e) {
        e.printStackTrace();
        throw new InternalServerErrorException("Error in DAO.deleteSessionToken()");
    }
}

/////

public User insertUser(User user) throws InternalServerErrorException {     
    try {
        this.pm.makePersistent(user);
    } catch (Exception e) {
        e.printStackTrace();
        throw new InternalServerErrorException("Error in DAO.insertUser()", e);
    }                
    return user;
}

型号:

@PersistenceCapable
public class User { 
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;    
    @Persistent
    private String name;
    @Persistent
    private String email;
    @Persistent
    private String password;    
    @Persistent
    private Folder rootFolder;  
    @Persistent
    private SessionToken sessionToken;  
    @Persistent(defaultFetchGroup = "true")
    private AccountContainer accountContainer;
    //getters & setters
}

/////

@PersistenceCapable
public class SessionToken {         
    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Key key;
    @Persistent
    private String token;
    @Persistent
    private Long created;
    @Persistent
    private String sha1;
    //getters & setters
}

【问题讨论】:

标签: java google-app-engine jdo datanucleus google-cloud-endpoints


【解决方案1】:

也许以下之一是可能的并且适合您的需求

  • 您能否将这两个调用组合成一个“getSessionTokenAndInfo”调用?您将令牌和信息一起返回的位置。根据您的代码的工作方式,令牌和用户对象可能已经可用并且不需要加载?

  • 使用某种形式的缓存,以便第一个端点在 memcache 中留下一些东西,这样就不需要在第二次调用中尝试从数据存储中检索它(至少在 memcache 应该可靠的大多数情况下)足以应付这种情况)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-02
    • 1970-01-01
    • 2015-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-03
    • 2015-07-25
    相关资源
    最近更新 更多