有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java应用程序引擎在尝试批量插入多个实体时出错,条件是每次插入实体时属性“UserNo”增加1

我想批量插入许多用户实体。用户实体具有属性名称&UserNo。要求是每次插入用户实体时,UserNo属性将自动增加1

如果我尝试一次插入一条记录,那么下面的代码可以很好地工作

public void insertUser(String name){
    Entity userEntity=new Entity("User");
    long maxID=Utility.getPropertyMaxID("User", "UserNo")+1;
    userEntity.setProperty("Name",name);
    datastore.put(userEntity); 
}

public static long getPropertyMaxID(String entityName, String propertyName){
        // Order alphabetically by property name:
        Query q = new Query(entityName)
                        .addSort(propertyName, SortDirection.DESCENDING);

        List<Entity> results = datastore.prepare(q)
                .asList(FetchOptions.Builder.withDefaults());
        if(results.size()>0){
            Entity e=results.get(0);
            long maxID=(Long)e.getProperty(propertyName);
            return maxID;
        }
        else{
            return 0;
        }

}

但是,如果我尝试同时插入多个实体

for(int i=0; i<10; i++){
    insertUser(names[i]);
}

然后,当检查数据时,我可以看到正确插入的名称。然而,UserNo被弄乱了,因为它没有正确地增加1乘1

因此,我认为这可能是Google App Engine数据存储的“最终一致性”,因为插入数据需要时间,因此程序可能会错误地使用maxUserNo

那么,我该怎么办?不应该使用“UserNo

我确实尝试过这个交易,但无论如何都不起作用

public void insertUser(String name){
     Transaction tx=datastore.beginTransaction();
     try{
        Entity userEntity=new Entity("User");
        long maxID=Utility.getPropertyMaxID("User", "UserNo")+1;
        userEntity.setProperty("Name",name);
        datastore.put(userEntity); 
        tx.commit();}
     catch (Exception ex){ ex.printStackTrace()};
}

那么,什么是最好的解决方案呢

注意:我听说“非祖先查询最终总是一致的”。因此getPropertyMaxID方法内部的查询不是强一致的

Extra:如果我制造了一个假的人,并强迫所有用户都是那个人的孩子,那该怎么办;然后对所有用户进行祖先查询。例如,循环所有用户查看电子邮件?请参阅此代码:

Entity personEntity=new Entity("Person", "Tom");
Key personKey=personEntity.getKey();
Entity userEntity=new Entity("User", userName);
userEntity.setProperty("Email", email);
datastore.put(userEntity);

然后创建一个功能来检查唯一的电子邮件

public static boolean checkUniqueEmail(String email){
Entity personEntity = new Entity("Person", "Tom");
        Key personKey = personEntity.getKey();

        Query query = new Query("User")
        .setAncestor(personKey);  


        List<Entity> results = datastore.prepare(query)
                       .asList(FetchOptions.Builder.withDefaults());

        for(Entity e : results){

            String em=(String)e.getProperty("Email");
             if(e.equals(email)) return false;
        }
}

共 (1) 个答案

  1. # 1 楼答案

    我找到了答案

    勾选this link

    要了解如何构建数据以实现强一致性,请比较App Engine入门练习中的留言簿示例应用程序的两种不同方法。第一种方法为每个问候语创建一个新的根实体:

    import com.google.appengine.api.datastore.Entity;
    
    Entity greeting = new Entity("Greeting");
    // No parent key specified, so Greeting is a root entity.
    
    greeting.setProperty("user", user);
    greeting.setProperty("date", date);
    greeting.setProperty("content", content);
    

    然后,它在实体类问候语中查询最近的十个问候语

    import com.google.appengine.api.datastore.DatastoreService;
    import com.google.appengine.api.datastore.DatastoreServiceFactory;
    import com.google.appengine.api.datastore.Entity;
    
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    
    Query query = new Query("Greeting")
                        .addSort("date", Query.SortDirection.DESCENDING);
    
    List<Entity> greetings = datastore.prepare(query)
                                      .asList(FetchOptions.Builder.withLimit(10));
    

    但是,由于我们使用的是非祖先查询,因此在执行查询时,用于执行此方案中的查询的副本可能尚未看到新的问候语。尽管如此,在提交后几秒钟内,几乎所有写入操作都将可用于非祖先查询。对于许多应用程序,在当前用户自己的更改上下文中提供非祖先查询结果的解决方案通常足以使此类复制延迟完全可接受

    如果强一致性对应用程序很重要,另一种方法是使用祖先路径编写实体,该路径在所有实体中标识相同的根实体,这些实体必须在一个强一致的祖先查询中读取:

    import com.google.appengine.api.datastore.DatastoreService;
    import com.google.appengine.api.datastore.DatastoreServiceFactory;
    import com.google.appengine.api.datastore.Entity;
    
    String guestbookName = req.getParameter("guestbookName");
    Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
    String content = req.getParameter("content");
    Date date = new Date();
    
    // Place greeting in same entity group as guestbook
    Entity greeting = new Entity("Greeting", guestbookKey);
    greeting.setProperty("user", user);
    greeting.setProperty("date", date);
    greeting.setProperty("content", content);
    You will then be able to perform a strongly-consistent ancestor query within the entity group identified by the common root entity:
    
    import com.google.appengine.api.datastore.DatastoreService;
    import com.google.appengine.api.datastore.DatastoreServiceFactory;
    import com.google.appengine.api.datastore.Entity;
    
    DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
    
    Key guestbookKey = KeyFactory.createKey("Guestbook", guestbookName);
    Query query = new Query("Greeting", guestbookKey)
                        .setAncestor(guestbookKey)
                        .addSort("date", Query.SortDirection.DESCENDING);
    
    List<Entity> greetings = datastore.prepare(query)
                                      .asList(FetchOptions.Builder.withLimit(10));
    

    这种方法通过对每个留言簿的单个实体组进行写入来实现强一致性,但它也将对留言簿的更改限制为每秒不超过1次写入(实体组支持的限制)。如果您的应用程序可能遇到较重的写入使用,您可能需要考虑使用其他方法:例如,您可能会将最近的帖子放入到期的MyCache中,并显示MyCache和DATASORE中最近的帖子的组合,或者您可以将它们缓存在cookie中,在URL中放置一些状态,或者完全其他一些。我们的目标是找到一个缓存解决方案,为当前用户在发布到应用程序的时间段内提供数据。请记住,如果在事务中执行get、祖先查询或任何操作,都会看到最近写入的数据