【问题标题】:what is better: getSingleResult, or getResultList JPA什么更好:getSingleResult 或 getResultList JPA
【发布时间】:2012-01-19 23:09:26
【问题描述】:

我需要从表中检索单行,我很感兴趣哪种方法更好。 一方面getSingleResult 是为检索单个结果而设计的,但它会引发异常。这种方法是否对与getResultList 相关的性能有好处

query.setFirstResult(0);
query.setMaxResults(1); 

【问题讨论】:

  • "但它会引发异常。"它引发了什么异常? (实际上它们都可以引发异常)。我不知道性能(哪个性能更高,应该可以忽略不计)但认为getSingleResult 使您的代码更具可读性。
  • 是的,我同意 getSingleResult 更具可读性。我只是想找出哪种方法更有效。

标签: jpa


【解决方案1】:

fetch() 结合使用setMaxResults(1) 会导致对象部分初始化。例如,

CriteriaQuery<Individual> query = cb.createQuery(Individual.class);
Root<Individual> root = query.from(Individual.class);
root.fetch(Individual_.contacts);

query.where(cb.equal(root.get(Individual_.id), id));

Individual i = em.createQuery(query)
    .setMaxResults(1) // assertion fails if individual has 2 contacts
    .getResultList()
    .get(0);
assertEquals(2, i.getContacts().size());

所以,我无限制地使用getResultList()——有点不满意。

【讨论】:

    【解决方案2】:

    getSingleResult 抛出 NonUniqueResultException,如果有多行或没有 any rows 。它旨在在真正有单个结果时检索单个结果。

    【讨论】:

      【解决方案3】:

      根据 Joshua Bloch 的 Effective Java:

      对调用者可以使用的条件使用检查异常 合理预期会恢复。使用运行时异常来指示 编程错误。

      来源:Why you should never use getSingleResult() in JPA

      @Entity
      @NamedQuery(name = "Country.findByName", 
                  query = "SELECT c FROM Country c WHERE c.name = :name"
      public class Country {
        @PersistenceContext
        transient EntityManager entityManager;
      
        public static Country findByName(String name) {
            List<Country> results = entityManager
                  .createNamedQuery("Country.findByName", Country.class)
                  .setParameter("name", name).getResultList();
            return results.isEmpty() ? null : results.get(0);
        }
      }
      

      【讨论】:

      • 非常感谢,非常合理的解释
      • Java 中的绝对值非常少,本文所宣扬的绝对值并不适用于所有用例。例如,如果查询应始终返回一行以满足某些业务要求,为什么要花费周期来编组结果列表以检查计数以查看是否违反了业务条件,此时您可以调用 getSingleResult 并捕获 NoResultException/NoUniqueResultException 异常和采取适当的行动?它的代码更少,并且使用异常来强制执行异常的业务逻辑条件。
      • @NBW 简短回答,因为异常处理更耗费资源,并且在这种情况下通常被认为是反模式programmers.stackexchange.com/questions/107723/…programmers.stackexchange.com/questions/189222/…c2.com/cgi/wiki?DontUseExceptionsForFlowControl
      • 没有 getSingleOrNullResult 方法的任何原因?似乎这是一个相当普遍的需求。
      【解决方案4】:

      我会推荐一个替代方案:

      Query query = em.createQuery("your query");
      List<Element> elementList = query.getResultList();
      return CollectionUtils.isEmpty(elementList ) ? null : elementList.get(0);
      

      这可以防止空指针异常,保证只返回 1 个结果。

      【讨论】:

      • 为什么使用 CollectionUtils 而不仅仅是 elementList.isEmpty()?
      • @Tomasz 使用 [commons.apache.org/collections/apidocs/org/apache/commons/…,如果列表为空或为空,isEmpty() 返回 true。 CollectionUtils 提供了简单的代码可读性,而不必编写以下代码:(elementList != null) &amp;&amp; !elementList.isEmpty().
      • 您使用的是哪个提供商? EclipseLink 的EJBQueryImpl.getResultList() 返回一个空列表以从不为空
      • @Tomasz 在 EclipseLink 的情况下您是正确的,getResultList() 不返回 null 并且不需要 null 检查。我说的是一般情况下,对于不同的提供者实现,最好有一个空检查 IMO。
      • Hibernate 作为提供者也永远不会返回空列表。我很好奇提供者到底会是什么
      【解决方案5】:

      getSingleResult 抛出 NonUniqueResultException,如果有多行。它旨在在真正有单个结果时检索单个结果。

      您的做法很好,JPA 旨在正确处理此问题。同时,您不能以任何方式将其与getSingleResult 进行比较,因为它不起作用。

      但是,取决于您正在处理的代码,最好优化查询以返回单个结果,如果这就是您想要的 - 那么您可以调用getSingleResult

      【讨论】:

      • 但我需要处理 notFound 异常。这部分代码需要通过那里的电子邮件确认码获取用户帐户实体。我明白,为此使用 getSingleResult 更清楚,但我知道异常处理开销
      • fetch() 结合使用setMaxResults(1) 会导致部分初始化对象。请参阅下面的示例。
      猜你喜欢
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多