有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java一对一映射正在触发N+1查询

我试图在https://vladmihalcea.com/the-best-way-to-map-a-onetoone-relationship-with-jpa-and-hibernate/之后创建一个@OneToOne映射,映射本身可以工作,但它会触发一个N+1查询问题

正在对父实体服务及其触发的N+1查询进行查询。 如何改进此代码,使其只进行一次查询在这种情况下,我们不需要访问ParentDetails

编辑:我尝试过使用JPQL和LEFT JOIN FETCH ParentDetails,但也没有成功

编辑2:只是想添加更多信息。我在getParentDetails上设置了一个断点,只是为了确保我没有在任何地方调用getter,也没有调用和重复检查,而且在repo调用上似乎存在连接问题

让我们转到代码:

家长

@Entity
@DynamicUpdate
public class Parent {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Long id;
   @OneToOne(fetch = FetchType.LAZY,
        cascade = CascadeType.ALL,
        mappedBy = "parent")
   private ParentDetails parentDetails;

 // Getters, setters, etc omitted for brevity
}

家长详细信息

@Entity
public class ParentDetails {

    @Id
    private Long id;
    @OneToOne(fetch = FetchType.LAZY)
    @MapsId
    private Parent parent;

    // Getters, setters, etc omitted for brevity

ParentDetailsRepository

@Repository
public interface ParentRepository extends JpaRepository<Parent, Long> {

    Page<Parent>findByNameOrderByName(@Param("name") final String name,final Pageable pageable);
}

共 (1) 个答案

  1. # 1 楼答案

    Hibernate执行附加查询,因为父实体不映射外键列。Hibernate不支持该关联端的延迟抓取。当Hibernate实例化父对象时,它需要检查是否需要初始化与代理或空对象的关联。在某个时刻,团队决定,如果强制执行查询,他们将获取关联的实体。我在这里更详细地解释了这一点:https://thorben-janssen.com/hibernate-tip-lazy-loading-one-to-one

    如果希望避免额外的查询,则需要在ParentDetails和Parent之间建立单向关联模型。在您的示例中,这意味着您需要从父实体中删除parentDetails属性

    @Entity
    @DynamicUpdate
    public class Parent {
    
       @Id
       @GeneratedValue(strategy = GenerationType.AUTO)
       private Long id;
    
     // Getters, setters, etc omitted for brevity
    }
    

    由于ParentDetails实体使用与父实体相同的id值,因此不需要双向关联。如果要获取父实体的ParentDetails实体,可以调用em.find(…)方法

    Parent p = // fetch the parent object ... 
    ParentDetails pd = em.find(p.getId(), ParentDetails.class);