我正在研究一个Hibernate问题,该问题涉及在自己的类中分别定义的2个单独的Entity bean:

  • 商店
  • StoreServer

  • 请注意,一个商店将具有多个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
    

    StoreServer:
    @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
    

    由于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
    

    目前,我得到了正确的结果,但是性能太慢了。我已经打开了Hibernate的登录记录,可以看到正在为每个商店实体运行一个单独的SELECT查询,以获取关联的StoreServer记录。

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

    请问我如何使用JOIN告诉Hibernate运行单个查询,能帮我一些忙吗?

    谢谢

    最佳答案

    叫做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();
    

    如果您使用的是HQL,则应使用fetch关键字:
    select distinct st from Store st left join fetch st.storeServers
    

    最好使用H2JDBC Sniffer等内存数据库来验证Hibernate在单元测试中生成的查询数量

    09-05 09:48