Hibernate n + 1问题

时间:2017-03-30 08:29:47

标签: java hibernate hibernate-criteria

我有这些课程:

订单

@Table(name = "ORDERS")
public class Order {

    @Id
    @Column(name = "order_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "user_id", nullable = false)
    private Long userId;

    @JsonManagedReference
    @OneToMany(mappedBy = "order", fetch = FetchType.EAGER)
    private Set<OrderDetail> orderDetails;

    @JsonManagedReference(value = "order-note")
    @OneToMany(mappedBy = "order", fetch = FetchType.EAGER)
    private Set<Note> notes;

}

详情

@Table(name = "ORDER_DETAILS")
public class OrderDetail {
    @Id
    @Column(name = "order_detail_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "order_id")
    private Order order;

    @JsonManagedReference
    @OneToMany(mappedBy = "orderDetail", fetch = FetchType.EAGER)
    private Set<OrderSize> orderSizes;

    @JsonManagedReference(value="order-detail-note")
    @OneToMany(mappedBy = "orderDetail", fetch = FetchType.EAGER)
    private Set<Note> notes;
}

尺寸

@Table(name = "ORDER_SIZES")
public class OrderSize {

    @Id
    @Column(name = "order_size_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonBackReference
    @ManyToOne
    @JoinColumn(name = "order_detail_id")
    private OrderDetail orderDetail;
}

备注

@Table(name = "NOTES")
public class Note {

    @Id
    @Column(name = "note_id")
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonBackReference(value="order-note")
    @ManyToOne
    @JoinColumn(name = "order_id", nullable = true)
    private Order order;

    @JsonBackReference(value="order-detail-note")
    @ManyToOne
    @JoinColumn(name = "order_detail_id", nullable = true)
    private OrderDetail orderDetail;
}

我想执行查询(使用Hibernate&#39;标准),并获取所有订单及其相关的详细信息,大小和注释。

public List<Order> findByUser(Long userId) {
    Criteria criteria = createEntityCriteria();
    criteria.add(Restrictions.eq("userId", userId));
    return (List<Order>) criteria.list();
}

目前Hibernate会生成如下的n个查询:

Hibernate:
    select
        notes0_.order_detail_id as order_de4_17_0_,
        notes0_.note_id as note_id1_15_0_,
        notes0_.note_id as note_id1_15_1_,
        notes0_.note_text as note_tex2_15_1_,
        notes0_.order_id as order_id3_15_1_,
        notes0_.order_detail_id as order_de4_15_1_,
        order1_.order_id as order_id1_16_2_,
        order1_.client_id as client_i2_16_2_,
        order1_.company_id as company_3_16_2_,
        order1_.delivery_id as delivery4_16_2_,
        order1_.discount as discount5_16_2_,
        order1_.order_date as order_da6_16_2_,
        order1_.order_name as order_na7_16_2_,
        order1_.signature as signatur8_16_2_,
        order1_.order_status as order_st9_16_2_,
        order1_.payment_method_id as payment10_16_2_,
        order1_.user_id as user_id11_16_2_
    from
        NOTES notes0_
    left outer join
        ORDERS order1_
            on notes0_.order_id=order1_.order_id
    where
        notes0_.order_detail_id=?

我还没有能够在一次查询中找到解决方案来获取我需要的所有内容。

1 个答案:

答案 0 :(得分:1)

插入后:

  • 2注意实体
  • 2个OrderDetail实体(每个包含2个Note实体)
  • 1订单实体(包含2个OrderDetail实体和2个Note实体)

在Order实体中使用以下注释:

@OneToMany(mappedBy = "order", fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<OrderDetail> orderDetails = new HashSet<>();

@OneToMany(mappedBy = "order", fetch = FetchType.EAGER)
@Fetch(FetchMode.JOIN)
private Set<Note> notes;

生成以下查询:

Hibernate: 
    select
        this_.order_id as order_id1_3_4_,
        this_.user_id as user_id2_3_4_,
        notes2_.order_id as order_id2_0_6_,
        notes2_.note_id as note_id1_0_6_,
        notes2_.note_id as note_id1_0_0_,
        notes2_.order_id as order_id2_0_0_,
        notes2_.order_detail_id as order_de3_0_0_,
        orderdetai3_.order_detail_id as order_de1_1_1_,
        orderdetai3_.order_id as order_id2_1_1_,
        order4_.order_id as order_id1_3_2_,
        order4_.user_id as user_id2_3_2_,
        ordersizes5_.order_detail_id as order_de2_2_7_,
        ordersizes5_.order_size_id as order_si1_2_7_,
        ordersizes5_.order_size_id as order_si1_2_3_,
        ordersizes5_.order_detail_id as order_de2_2_3_ 
    from
        orders this_ 
    left outer join
        notes notes2_ 
            on this_.order_id=notes2_.order_id 
    left outer join
        order_details orderdetai3_ 
            on notes2_.order_detail_id=orderdetai3_.order_detail_id 
    left outer join
        orders order4_ 
            on orderdetai3_.order_id=order4_.order_id 
    left outer join
        order_sizes ordersizes5_ 
            on orderdetai3_.order_detail_id=ordersizes5_.order_detail_id 
    where
        this_.user_id=?
Hibernate: 
    select
        orderdetai0_.order_id as order_id2_1_0_,
        orderdetai0_.order_detail_id as order_de1_1_0_,
        orderdetai0_.order_detail_id as order_de1_1_1_,
        orderdetai0_.order_id as order_id2_1_1_ 
    from
        order_details orderdetai0_ 
    where
        orderdetai0_.order_id=?

如果您仍然面临将查询数据作为一个查询的困难,我建议使用QueryDSL [1],其中包含示例和maven设置详细信息[2]。

<强> LE

在QueryDSL中创建查询的示例如下:

public List<Order> findByUserQueryDsl(Long userId) {
    System.out.println("Finding by User ID query dsl");

    EntityManager em = this.entityManagerFactory.createEntityManager();

    return new JPAQuery<>(em, HQLTemplates.DEFAULT)
            .select(QOrder.order)
            .from(QOrder.order)
            .leftJoin(QOrder.order.notes).fetchJoin()
            .leftJoin(QOrder.order.orderDetails, QOrderDetail.orderDetail).fetchJoin()
            .leftJoin(QOrderDetail.orderDetail.notes).fetchJoin()
            .where(QOrder.order.userId.eq(userId))
            .fetch();
}

哪会生成以下查询:

select
    order0_.order_id as order_id1_3_0_,
    notes1_.note_id as note_id1_0_1_,
    orderdetai2_.order_detail_id as order_de1_1_2_,
    notes3_.note_id as note_id1_0_3_,
    order0_.user_id as user_id2_3_0_,
    notes1_.order_id as order_id2_0_1_,
    notes1_.order_detail_id as order_de3_0_1_,
    notes1_.order_id as order_id2_0_0__,
    notes1_.note_id as note_id1_0_0__,
    orderdetai2_.order_id as order_id2_1_2_,
    orderdetai2_.order_id as order_id2_1_1__,
    orderdetai2_.order_detail_id as order_de1_1_1__,
    notes3_.order_id as order_id2_0_3_,
    notes3_.order_detail_id as order_de3_0_3_,
    notes3_.order_detail_id as order_de3_0_2__,
    notes3_.note_id as note_id1_0_2__ 
from
    orders order0_ 
left outer join
    notes notes1_ 
        on order0_.order_id=notes1_.order_id 
left outer join
    order_details orderdetai2_ 
        on order0_.order_id=orderdetai2_.order_id 
left outer join
    notes notes3_ 
        on orderdetai2_.order_detail_id=notes3_.order_detail_id 
where
    order0_.user_id=?

[1] http://www.querydsl.com/

[2] http://www.querydsl.com/static/querydsl/4.1.4/reference/html/ch02s02.html