我试图减少应用程序引起的n + 1选择的数量,该应用程序使用EclipseLink作为ORM,并且在尽可能多的地方,我尝试将批处理读取提示添加到查询中。在应用程序的许多地方,我并不总是确切知道我将遍历什么关系(我的 View 根据用户的偏好显示字段)。那时,我想运行一个查询来填充对象的所有这些关系。

我的梦想是调用诸如ReadAllRelationshipsQuery(Collection,RelationshipName)之类的东西并填充所有这些项,以便以后调用:

Collection.get(0).getMyStuff已被填充,不会引起数据库查询。我该怎么做?我愿意编写任何我需要的代码,但是找不到与eclipselink框架一起工作的方法?



如何避免对已经引用的对象进行N + 1选择?

最佳答案

您可以通过三种基本方法将数据从基于JPA的解决方案加载到对象中。这些是:

  • 通过对象遍历动态加载(例如,myObject.getMyCollection()。get())。
  • 通过使用JPA QL动态预取来加载对象图(例如the Oracle JPA tutorial中描述的FETCH JOIN)
  • 通过设置获取模式(Is there a way to change the JPA fetch type on a method?)
  • 进行加载

    这些每个都有优点和缺点。
  • 通过对象横向动态加载将生成更多(目标明确的查询)。这些查询通常很小(不是大的SQL语句,但是可能会加载大量数据),并且往往可以很好地与二级缓存配合使用,但是您可以获得很多很多小的查询。
  • 使用JPA QL预取将为您提供所需的确切信息,但前提是您知道所需的信息。
  • 将获取模式设置为EAGER会自动为您加载大量数据,但是根据配置和使用情况,这实际上可能并没有多大帮助(或者可能使情况更糟),因为您可能会拖累大量数据从数据库到您意想不到的应用程序。

  • 无论如何,我强烈建议将p6spy(http://sourceforge.net/projects/p6spy/)与任何基于JPA的应用程序结合使用,以了解调整的效果。

    不幸的是,JPA使某些事情变得容易而有些困难-主要是您使用过程中的副作用。例如,您可以通过将获取模式设置为eager来解决一个问题,然后创建另一个问题,即eager fetch会提取过多的数据。 EclipseLink确实提供了有助于解决此问题的工具(EclipseLink Performance Tools)

    从理论上讲,如果愿意,您可以使用Apache BeanUtils之类的东西来编写通用的JavaBean属性walker。通常,仅在集合上调用诸如size()之类的方法就足以迫使它加载(尽管使用集合批处理获取大小可能会使事情复杂化)。

    要特别注意的一件事是 session 的范围和缓存的使用(EclipseLink cache)。

    您的帖子中尚不清楚的是 session 的范围。 session 是一次性的事情(例如,像网页请求)还是长时间运行的事情(例如,像经典的客户端/服务器GUI应用程序)?

    07-28 01:38
    查看更多