假设我们有一个简单的实体“客户”,它与一个实体“地址”具有一对一的关系。外键位于地址端。
如果您现在使用Hibernate加载所有客户实体并将生成的查询打印到控制台上,您会发现Hibernate内部仅触发了一个查询。
如果使用QueryDSL加载客户实体,它将运行一个计数查询(这是预期的并且可以接受的),一个选择查询用于客户实体以及结果集中每个客户的一个查询。这意味着,如果我想加载1000个客户,它将运行1002个SQL查询。这会产生大量的网络流量,并减缓应用程序的速度。
是否可以为QueryDSL查询设置类似全局的FetchMode。在Hibernate中,您可以使用@Fetch(FetchMode.JOIN)指定此内容,但不幸的是,QueryDSL会忽略它。
我的目标是使用QueryDSL加载1000个客户,并仅运行2个查询(计数+选择)。
我已经知道有一种方法可以指定这样的内容:
@Entity
public class Customer extends EntityBase {
@Column(name = "name", nullable = true)
private String name;
@OneToOne(mappedBy = "customer")
private Address address;
// getter, setter, ...
}
@Entity
public class Address extends EntityBase {
@OneToOne(optional = false)
private Customer customer;
@Column(nullable = true)
private String street;
@Column(nullable = true)
private String zip;
@Column(nullable = true)
private String city;
// getter, setter, ...
}
如果您现在使用Hibernate加载所有客户实体并将生成的查询打印到控制台上,您会发现Hibernate内部仅触发了一个查询。
session.createCriteria(Customer.class).list();
Hibernate的作用:
select
this_.id as id1_1_1_,
this_.name as name2_1_1_,
address2_.id as id1_0_0_,
address2_.city as city2_0_0_,
address2_.customer_id as customer5_0_0_,
address2_.street as street3_0_0_,
address2_.zip as zip4_0_0_
from
Customer this_
left outer join
Address address2_
on this_.id=address2_.customer_id
如果使用QueryDSL加载客户实体,它将运行一个计数查询(这是预期的并且可以接受的),一个选择查询用于客户实体以及结果集中每个客户的一个查询。这意味着,如果我想加载1000个客户,它将运行1002个SQL查询。这会产生大量的网络流量,并减缓应用程序的速度。
new HibernateQuery<Customer>(session).from(QCustomer.customer).fetchResults();
Hibernate与QueryDSL的作用:
select
count(customer0_.id) as col_0_0_
from
Customer customer0_
select
customer0_.id as id1_1_,
customer0_.name as name2_1_
from
Customer customer0_
select
address0_.id as id1_0_1_,
address0_.city as city2_0_1_,
address0_.customer_id as customer5_0_1_,
address0_.street as street3_0_1_,
address0_.zip as zip4_0_1_,
customer1_.id as id1_1_0_,
customer1_.name as name2_1_0_
from
Address address0_
inner join
Customer customer1_
on address0_.customer_id=customer1_.id
where
address0_.customer_id=?
问题:是否可以为QueryDSL查询设置类似全局的FetchMode。在Hibernate中,您可以使用@Fetch(FetchMode.JOIN)指定此内容,但不幸的是,QueryDSL会忽略它。
我的目标是使用QueryDSL加载1000个客户,并仅运行2个查询(计数+选择)。
我已经知道有一种方法可以指定这样的内容:
new HibernateQuery<Customer>(session)
.from(QCustomer.customer)
.leftJoin(QCustomer.customer.address).fetchJoin()
.fetchResults();
但这种方式容易出错,因为您必须在每个查询中都指定它,我不想自己声明每个连接。当使用谓词时,QueryDSL已经自动完成了它:
new HibernateQuery<Customer>(session)
.from(QCustomer.customer)
.where(QCustomer.customer.address.street.in("Musterstraße 12"))
.fetchResults();
我想使用上述表达式来加载我的客户,但我不想向我的数据库发送成千上万个请求,也不想自己声明每个联接。这可行吗?
我在这里推送了一个示例项目:https://github.com/MatWein/testproject