【问题标题】:Update all objects in JPA entity更新 JPA 实体中的所有对象
【发布时间】:2012-10-15 12:59:01
【问题描述】:

我正在尝试更新 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 日
在这 2 天里,我尝试了:
按照 Thanos Makris 的建议使用后端,但走到了死胡同。你可以看到我的问题here
阅读 DataNucleus 关于 Map-Reduce 的建议,但真的迷路了。

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

【问题讨论】:

  • 你能发布完整的堆栈跟踪吗?
  • 那么,我建议使用Task Queue API 来解决这个问题。在那里,通过使用游标,您将能够查询一批实体,更新它们并将它们存储回来。

标签: java google-app-engine jpa


【解决方案1】:

鉴于您的情况,我建议您运行本机更新查询:

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

请注意:这里的查询字符串是SQL,即update **table_name** set ....

这样会更好。

【讨论】:

  • 我的问题抽象得太多了。我编辑了我的问题,它仍然适用于这种情况吗?
  • 你是Java函数吗?如果是,在数据库中是否有相同的写法?如果你可以移动/复制数据库中的函数,你可以很好地做到这一点,查询是 -- update ProfileEntity pe set pe.X = func(pe.a,pe.b).
  • 是的,该函数在 java 中。你是什​​么意思移动/复制数据库中的功能?我试着按照你写的去做,现在我得到 javax.persistence.PersistenceException: Bulk Update statements are not supported.
  • 糟糕,方法名称是createSQLQuery(我更新了答案)。请确保您使用的是SQL 而不是HQL。通过移动/复制,我的意思是如果您可以将数据库中的函数定义为数据库函数。
  • 我认为是 JPQL(我不确定,我真的不知道有什么区别)。但是 EntityManager 没有 createSQLQuery。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      也许您应该考虑使用Task Queue API,它可以让您执行长达 10 分钟的任务。如果你想更新这么多任务队列不适合你的实体,你也可以考虑Backends的用户。

      【讨论】:

        【解决方案5】:

        将事务置于循环之外:

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

        【讨论】:

          【解决方案6】:

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

          查看休眠参考: http://docs.jboss.org/hibernate/orm/3.3/reference/en/html/batch.html#batch-direct

          【讨论】:

          • 我的问题抽象得太多了。我编辑了我的问题,它仍然适用于这种情况吗?
          • 您只是将太多数据加载到您的 EM 中 - 考虑将此更新完全移至后端,并可能发布完整的堆栈跟踪以查看哪个查询冒犯了 GAE
          • 它似乎在延迟加载所有数据时大吃一惊(第 3.5.3 行是什么)
          • System.out.println(usersList.size());就在 getResultList() 之后
          • 所以它在加载你所有的数据时被吐了 - 你的问题肯定是在 JPA 映射中尝试尽可能地懒惰,尤其是对于集合
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-02-10
          • 1970-01-01
          • 2019-02-09
          • 1970-01-01
          • 1970-01-01
          • 2023-02-24
          • 1970-01-01
          相关资源
          最近更新 更多