更新JPA实体中的所有对象

时间:2012-10-15 12:59:01

标签: java google-app-engine jpa

我正在尝试更新ProfileEntity中的所有4000个对象,但我收到以下异常:

javax.persistence.QueryTimeoutException: The datastore operation timed out, or the data was temporarily unavailable.

这是我的代码:

public synchronized static void  setX4all() 
{

    em = EMF.get().createEntityManager();

    Query query = em.createQuery("SELECT p FROM ProfileEntity p");
    List<ProfileEntity> usersList = query.getResultList();

    int a,b,x;
    for (ProfileEntity profileEntity : usersList) 
    {
        a = profileEntity.getA();
        b = profileEntity.getB();
        x = func(a,b);
        profileEntity.setX(x);

        em.getTransaction().begin();        
        em.persist(profileEntity);        
        em.getTransaction().commit();

    }

    em.close();

}

我猜我花了很长时间才查询ProfileEntity的所有记录。 我该怎么办?

  • 我正在使用Google App Engine,因此无法进行UPDATE查询。

编辑于18/10年
在这两天里我试过了:
使用后端作为Thanos Makris建议但是走到了尽头。你可以看到我的问题here 阅读关于Map-Reduce的DataNucleus建议,但确实迷路了。

我正在寻找一个不同的方向。由于我只会进行一次更新,也许我可以每200个对象手动更新一次 是否可以查询前200个对象,然后查询第二个200个对象,依此类推?

6 个答案:

答案 0 :(得分:3)

根据您的方案,我建议运行本机更新查询:

 Query query = em.createNativeQuery("update ProfileEntity pe set pe.X = 'x'");
 query.executeUpdate();

请注意:此处查询字符串为SQL,即update **table_name** set ....

这会更好。

答案 1 :(得分:1)

将更新过程更改为使用Map-Reduce之类的内容。这意味着所有操作都在数据存储区中完成。唯一的问题是appengine-mapreduce尚未完全发布(尽管你可以自己轻松地构建jar并在你的GAE应用程序中使用它 - 许多其他人已经这样做了。)

答案 2 :(得分:0)

如果要为所有对象设置(x),最好使用JPA实体管理器而不是获取所有对象并逐个更新用户更新语句(即本机SQL)。

答案 3 :(得分:0)

您的类表现不太好 - JPA不适合以这种方式进行批量更新 - 您只是以快速顺序启动大量事务并在数据库上产生大量负载。对于您的用例更好的解决方案是标量查询设置所有对象而不首先将它们加载到JVM中(取决于您的对象结构和懒惰,您可以按照您的想法加载更多数据)

请参阅hibernate参考: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html#batch-direct

答案 4 :(得分:0)

也许你应该考虑使用Task Queue API来使你能够执行长达10分钟的任务。如果您想更新任务队列不适合您的大量实体,您还可以考虑Backends的用户。

答案 5 :(得分:0)

将交易置于循环之外:

em.getTransaction().begin();        
for (ProfileEntity profileEntity : usersList) {
...
}
em.getTransaction().commit();