【问题标题】:Hibernate N+1 SELECTs with DTO objects使用 DTO 对象休眠 N+1 SELECT
【发布时间】:2012-03-17 16:06:22
【问题描述】:

当使用 DTO 对象时,我遇到了休眠问题,它正在执行 N+1 SELECTS。

例如,这个 JPQL 查询:

SELECT com.acme.MyDto(t) FROM Thing t

MyDto 的构造函数类似于:

public MyDto(Thing t) {
   ...
}

这会导致如下查询:

SELECT t.id FROM thing t WHERE condition

接下来是每一行的所有单个查询,即:

SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 1
SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 2
SELECT t.id, t.column1, t.column2 FROM thing t WHERE t.id = 3
...

但是,如果构造函数不接受实体,而是接受每个单独的列,那么 hibernate 的行为就像您所期望的那样,即:

public MyDto(Integer id, String column1, String column2) {
   ...
}

那么生成的SQL是这样的:

SELECT t.id, t.column1, t.column2 FROM thing t WHERE condition

除了创建接受每一列的 DTO 构造函数之外,有没有办法让 hibernate 从一开始就一次选择所有列?

我们正在使用的表有 100 多列分布在可嵌入对象中,因此维护一个庞大的构造函数非常烦人。该表已高度规范化并且没有连接。

【问题讨论】:

    标签: java hibernate jpql dto


    【解决方案1】:

    第一次读错了你的问题......我不记得使用 DTO,如果他们只取整个实体而不只是一些特定的列,所以我不确定为什么当你使用一个整体时 Hibernate 会这样实体作为 DTO 构造函数中的参数。无论如何,您可以通过查询获取实际的Things 来解决它,然后在循环中构造 DTO,类似于:

    public List<ThingDTO> getThingDTOs( ... )
    {
        Query query = em().createQuery("FROM Thing t WHERE ...");
        query.setParameter( ... );
    
        List<Thing> things = query.getResultList();
    
        List<ThingDTO> thingDTOs = new ArrayList(things.size());
        for(Thing t : things)
        {
            thingDTOs.add(new ThingDTO(t));
        }
    
        return thingDTOs
    }
    

    它不是很漂亮,但是这样 Hibernate 应该一次性获取所有需要的行

    【讨论】:

    • 谢谢你,它完成了这项工作。
    【解决方案2】:

    您可能已经注意到,构造函数表达式方法有很多缺点。如果您需要嵌套关联,它会变得更糟。在这里使用实体对象的主要问题是您可能仍会遇到 N + 1 个查询问题。我不久前就该主题写了一个blog post,这证明了我创建Blaze-Persistence Entity Views 的原因,这是一个允许将DTO 映射为接口的库。

    【讨论】:

      猜你喜欢
      • 2011-03-24
      • 1970-01-01
      • 1970-01-01
      • 2011-02-26
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-30
      相关资源
      最近更新 更多