JPA获取和N + 1问题

时间:2019-04-02 15:59:42

标签: hibernate jpa spring-data

我使用Spring Boot 2,JPA和Hibernate。

我的实体

@Entity
public class Samples {

    @EmbeddedId
    private SampleId id;

    @MapsId("samplingId")
    @ManyToOne(optional = false)
    private Samplings sampling;

    @OneToOne(mappedBy = "sample", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
    private TestSamples testSamples;
    ...
}

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Samplings {
    @OneToOne
    private Products product;

    @OneToOne
    private Machines machine;

    @OneToOne(fetch = FetchType.LAZY)
    private Dimensions dimension;

    @OneToOne(fetch = FetchType.LAZY)
    private Colors color;

    @OneToMany(mappedBy = "sampling", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Samples> samples = new ArrayList<>();
    ...
}

@Entity
public class TestSamples {

    @Id
    @SequenceGenerator(name = "test_samples_id_seq", sequenceName = "test_samples_id_seq", allocationSize = 1)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "test_samples_id_seq")
    private Integer id;

    @OneToOne(fetch = FetchType.LAZY)
    private Samples sample;
    ... 

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private Absorptions absorptionTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private Compressions compressionTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private BnqDurabilities bnqDurabilityTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private CsaDurabilities csaDurabilityTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private BnqScallings bnqScallingTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private CsaScallings csaScallingTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private Flexions flexionTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private Granulometries granulometryTest;

    @OneToOne(mappedBy = "testSample", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private ExternalLabs externalLabTest;

}

@Entity
public class Absorptions extends BaseEntity {
    @OneToOne(fetch = FetchType.LAZY)
    private TestSamples testSample;
    ...
}

我有很多加入的庞大查询

        "select s from Samples s "
        + "Join Fetch s.testSamples ts "
        + "Join Fetch s.sampling sp "
        + "Left Join fetch sp.machine m "
        + "Join Fetch m.factory f "
        + "Join Fetch sp.product p "
        + "Join Fetch p.productType pt "
        + "Left Join fetch sp.color c "
        + "Left Join fetch sp.dimension d "
        + "Left Join fetch ts.compressionTest ct "
        + "Left Join Fetch ts.flexionTest as ft "
        + "Left Join Fetch ts.csaDurabilityTest as csaDt "
        + "Left Join Fetch ts.bnqDurabilityTest as bqnDt "
        + "Left Join Fetch ts.csaScallingTest as csaSt "
        + "Left Join Fetch ts.bnqScallingTest as bnqSt "
        + "Left Join fetch ts.absorptionTest at "
        + "where sp.externalLaboratoryResults=false "
        + "and sp.buildDate between :startDate and :endDate "
        + "and ts.granulometry=false "
        + "and ("
        + "ct.completed=true   "
        + "or ft.completed=true "
        + "or csaDt.completed=true "
        + "or bqnDt.completed=true "
        + "or csaSt.completed=true "
        + "or bnqSt.completed=true "
        + "or at.completed=true"
        + ") "
        + "order by s.id.samplingId,s.id.sampleLetter")

休眠将其翻译为

https://paste.ee/p/vrP5V

Hibernate会生成一个很大的查询,但是很多要用于CompressionTest,flexionTest。...不明白为什么要提取

2 个答案:

答案 0 :(得分:1)

在Hibernate中,对于没有可选= false的OneToOne关系,即使使用FetchType.LAZY,也始终会有一个Join。

这是因为例如在TestSamples.flexionTest字段中,Hibernate需要知道它是否需要提供代理对象或null。因此,无论如何,它都需要查询flexionTest表,甚至对于FetchType.LAZY。

答案 1 :(得分:0)

如果我理解正确,那么您的问题就是很多查询。

在翻译后的SQL中,有许多对external_labsgranulometries表的查询。

为避免这些单独的查询,请同时加入granulometryTestexternalLabTest