Hibernate @OneToMany 导致多个 select 语句

use*_*704 5 java hibernate

我正在解决一个 Hibernate 问题,其中涉及 2 个单独的实体 bean,它们在它们自己的类中分别定义:

  • 店铺
  • 商店服务器

请注意,一个 Store 将有多个 StoreServer - 因此使用 @OneToMany 注释。请看代码片段如下:

店铺:

@Entity
@Table(name="Store")
public class Store implements Serializable {
/**
* Serializable class - generated UID
*/
private static final long serialVersionUID = 5644190852867691168L;

@Id
@Column(name="STORE_NO", nullable=false)
private int storeNumber;

@Column(name="STORE_NAME", nullable=false)
private String storeName;

@Column(name="STORE_PHONE", nullable=false)
private String storePhone;

//other Store fields...

@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name="STORE_NO", insertable=false, updatable=false)
private List<StoreServer> storeServers = new ArrayList<StoreServer>();

//getters and setters
Run Code Online (Sandbox Code Playgroud)

商店服务器:

@Entity
@Table(name="Store_Server")
public class StoreServer implements Serializable {
/**
* Serializable class - generated UID
*/
private static final long serialVersionUID = -5410564578856243437L;

@Id
private StoreServerPK storeServerPK;

@Column(name="IP_ADDRESS", nullable=true)
private String ipAddress;

//other StoreServer fields...getters and setters
Run Code Online (Sandbox Code Playgroud)

由于 StoreServer 有一个复合主键,因此 StoreServerPK 如下:

@Embeddable
public class StoreServerPK implements Serializable {
/**
* Serializable class - generated UID
*/
private static final long serialVersionUID = -1401889029390423604L;

@Column(name="STORE_NO", nullable=false)
protected int storeNumber;

@Column(name="SERVER_NO", nullable=false)
protected String serverNumber;

//getters and setters
Run Code Online (Sandbox Code Playgroud)

目前,我得到了正确的结果,但性能慢得令人无法接受。我已经打开 Hibernate 中的日志记录,并且可以看到正在为每个 Store Entity 运行单独的 SELECT 查询,以便获取关联的 StoreServer 记录。

目前,在日志中,我看到一条 SELECT 语句来获取 Store 记录(返回了 200 多个结果)。然后对于每个商店,使用一个新的 SELECT 语句来获取 StoreServer 记录。我的问题是...为什么 Hibernate 不执行连接(运行一个查询)?

请问我可以获得一些有关如何告诉 Hibernate 使用 JOIN 运行单个查询的帮助吗?

谢谢

bed*_*rin 2

这就是所谓的N+1问题

该解决方案实际上取决于您如何进行查询 - 如果您使用 Criteria API,则应该使用Root.fetch方法:

CriteriaBuilder qb = em.getCriteriaBuilder();
CriteriaQuery<Store> cq = qb.createQuery(Store.class);

Root<Store> root = cq.from(Store.class);
root.fetch(App_.storeServers, JoinType.LEFT);

cq.select(root);

return em.createQuery(cq).getResultList();
Run Code Online (Sandbox Code Playgroud)

如果您使用 HQL,您应该使用fetch关键字:

select distinct st from Store st left join fetch st.storeServers
Run Code Online (Sandbox Code Playgroud)

使用内存数据库(如H2JDBC Sniffer)在单元测试中验证 Hibernate 生成的查询数量可能是个好主意