我在针对 DB2 和 MySQL 使用 hibernate 时遇到了同样的问题。
这是一个测试:
EntityManager em = emf.createEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Customers> query = cb.createQuery(Customers.class);
Root<Customers> root = query.from(Customers.class);
ArrayList<String> strList = new ArrayList<String>();
strList.add("ADMIN");
strList.add("SYSADMIN");
strList.add("SALES");
ArrayList<Predicate> predicateList = new ArrayList<Predicate>();
Path<Groups> groups = root.get(Customers_.groups);
Path<String> groupName = groups.get(Groups_.name);
In<String> in = cb.in(groupName);
for (String s : strList) { //has a value
in = in.value(s);
}
predicateList.add(in);
Predicate[] predicates = new Predicate[predicateList.size()];
query.where(predicateList.toArray(predicates));
TypedQuery<Customers> typedQuery = em.createQuery(query);
this.outList = typedQuery.getResultList();
生成我需要的查询,然后是三个不需要的查询(另外一个用于 strList 中的多个值)。以下内容打印在日志中(我格式化了第一个查询以将其分开。)第一个查询完全符合我的要求,接下来的三个查询在生产中导致不需要的 IO,我对此表示反对。请注意,如果 in 表达式不在 FK 上,则不会发生此问题。
INFO: Hibernate:
select
customers0_.id as id0_, customers0_.fname as fname0_, customers0_.groups as groups0_, customers0_.lname as lname0_
from
test.customers customers0_
where
customers0_.groups in (? , ? , ?)
INFO: Hibernate: select groups0_.name as name1_0_ from test.groups groups0_ where groups0_.name=?
INFO: Hibernate: select groups0_.name as name1_0_ from test.groups groups0_ where groups0_.name=?
INFO: Hibernate: select groups0_.name as name1_0_ from test.groups groups0_ where groups0_.name=?
为什么要多出三个查询?我如何防止它们?我需要答案作为标准查询。
以下是实体对象:
@Entity
@Table(name = "customers", catalog = "test", schema = "")
public class Customers implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id", nullable = false)
private Integer id;
@Column(name = "fname", length = 45)
private String fname;
@Column(name = "lname", length = 45)
private String lname;
@JoinColumn(name = "groups", referencedColumnName = "name")
@ManyToOne
private Groups groups;
...getters and setters...
}
下一个实体
@Entity
@Table(name = "groups", catalog = "test", schema = "")
public class Groups implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Basic(optional = false)
@Column(name = "name", nullable = false, length = 45, unique = true)
private String name;
@OneToMany(mappedBy = "groups")
private Collection<Customers> customersCollection;
...getters and setters...
}
编辑 ~~~~~~~~~~~~~~~~~~~~~~~~~ 解决方案~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~:
将第二行添加到上述代码即可解决问题(谢谢 Clement):
Root<Customers> root = query.from(Customers.class);
root.fetch(Customers_.groups, JoinType.LEFT); //that's it that's all now it will not create the extra queries
最佳答案
附加查询的原因是因为您正在使用一个字段:private Groups groups;
用于从客户到组的关联。由于 hibernate 无法拦截直接字段访问,因此在获取 Customer 时它必须获取 Groups 对象。它以 N+1 选择方式对标准查询执行此操作(而不是,例如,弄清楚并自动执行连接或子选择)。
要解决此问题,您可以告诉 hibernate 也获取关联:
root.fetch(Customers_.groups, JoinType.LEFT); // LEFT join since your schema could have a customer with a null group.
关于hibernate - JPA 2 条件查询在 select 语句中的 FK 问题的表达式中,其中 n 是 #values,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4800200/