IT

JPA 빠른 가져오기가 가입되지 않음

itgroup 2022. 11. 8. 21:45
반응형

JPA 빠른 가져오기가 가입되지 않음

JPA의 가져오기 전략은 정확히 무엇을 제어합니까?나는 열정과 게으름의 차이를 전혀 느낄 수 없다.어느 경우든 JPA/Hibernate는 다대일 관계에 자동으로 가입하지 않습니다.

예: 개인은 단일 주소를 가집니다.주소는 여러 사람에게 속할 수 있습니다.JPA 주석이 달린 엔티티 클래스는 다음과 같습니다.

@Entity
public class Person {
    @Id
    public Integer id;

    public String name;

    @ManyToOne(fetch=FetchType.LAZY or EAGER)
    public Address address;
}

@Entity
public class Address {
    @Id
    public Integer id;

    public String name;
}

JPA 쿼리를 사용하는 경우:

select p from Person p where ...

JPA/Hibernate는 사용자 테이블에서 선택할 SQL 쿼리를 하나씩 생성한 후 각 사용자에 대해 고유한 주소 쿼리를 생성합니다.

select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3

이것은 큰 결과 세트에는 매우 좋지 않습니다.사용자가 1000명일 경우 1001개의 쿼리를 생성합니다(1명은 Person에서, 1000명은 Address에서 구별).MySQL의 쿼리 로그를 보고 있기 때문에 알 수 있습니다.주소의 fetch 타입을 eager로 설정하면 JPA/Hibernate가 join으로 자동 쿼리하는 것으로 알고 있습니다.그러나 가져오기 유형에 관계없이 관계에 대한 개별 쿼리를 생성합니다.

참여하도록 명시적으로 지시한 경우에만 실제로 참여합니다.

select p, a from Person p left join p.address a where ...

내가 뭘 빠트렸나요?이제 모든 쿼리를 손으로 코드화해서 다대일 관계에 참여시켜야 합니다.MySQL에서 Hibernate의 JPA 구현을 사용하고 있습니다.

편집: 다음과 같이 표시됩니다(여기와 여기의 휴지 상태 FAQ 참조).FetchTypeJPA를 사용하다.그래서 내 경우엔 참여하라고 분명히 말했다.

JPA에서는 가져오기 전략을 선택하기 위한 주석 매핑에 대한 규격을 제공하지 않습니다.일반적으로 관련 엔티티는 다음 중 하나의 방법으로 가져올 수 있습니다.

  • SELECT => 루트 엔티티에 대한 쿼리 1개 + 관련된 매핑 엔티티/각 루트 엔티티의 컬렉션에 대한 쿼리 1개 = (n+1)개
  • SUBSELECT => 루트 엔티티에 대한 쿼리 1개 + 관련 매핑엔티티에 대한 두 번째 쿼리 / 첫 번째 쿼리에서 검색된 모든 루트엔티티의 컬렉션 = 2개의 쿼리
  • JOIN => 루트 엔티티와 매핑된 엔티티/컬렉션 모두를 가져오기 위한 쿼리 1개 = 쿼리 1개

★★★★★★★★★★★★★★★★★.SELECT ★★★★★★★★★★★★★★★★★」JOIN과 극이다.SUBSELECT 모델에 적절한 할 수 .도메인 모델에 따라 적절한 전략을 선택할 수 있다.

로는 " " 입니다.SELECT는 JPA/EclipseLink와 휴지 상태 모두에서 사용됩니다.이것은, 다음의 방법으로 덮어쓸 수 있습니다.

@Fetch(FetchMode.JOIN) 
@Fetch(FetchMode.SUBSELECT)

하이버네이트로 합니다., ,, 음, 음, 다, 다, 다, 다를 설정할 수 있습니다.SELECT를 으로 사용하다@Fetch(FetchMode.SELECT)예를 들어, 배치 크기를 사용하여 조정할 수 있습니다. @BatchSize(size=10).

EclipseLink에서 대응하는 주석은 다음과 같습니다.

@JoinFetch
@BatchFetch

맞네요. fetchType관계 해결 시기를 지정합니다.

외부 결합을 사용하여 빠른 로드를 최적화하려면 다음을 추가해야 합니다.

@Fetch(FetchMode.JOIN)

당신의 분야로.이것은 휴지 상태 특유의 주석입니다.

fetchType 속성은 기본 엔티티를 가져올 때 주석 필드를 즉시 가져올지 여부를 제어합니다.반드시 fetch 문의 구성 방법을 지시하는 것은 아닙니다.실제 SQL 구현은 toplink/hibernate 등을 사용하는 공급자에 따라 달라집니다.

「 」를 설정했을 fetchType=EAGER즉, 주석 필드가 엔티티 내의 다른 필드와 동시에 해당 값으로 채워집니다.따라서 엔티티 매니저를 열어 개인 객체를 취득한 후 엔티티 매니저를 닫아도 person.address를 실행해도 지연 부하 예외가 느려지지 않습니다.

「 」를 설정했을 fetchType=LAZY필드에 액세스할 때만 필드가 채워집니다.엔티티 매니저를 종료한 경우 person.address를 실행하면 지연부하 예외가 느려집니다.필드를 로드하려면 em.merge()를 사용하여 엔티티 매니저 컨텍스트로 엔티티를 되돌리고 필드 액세스를 수행한 후 엔티티 매니저를 닫아야 합니다.

고객 주문에 대한 컬렉션을 사용하여 고객 클래스를 구성할 때 로딩이 느릴 수 있습니다.고객 리스트를 취득하고 싶을 때 고객의 모든 주문을 취득했을 경우, 고객명과 연락처의 상세만을 검색할 경우, 이 작업은 비용이 많이 드는 데이터베이스 조작이 될 수 있습니다.DB 액세스는 나중에 하는 것이 좋습니다.

질문의 두 번째 부분인 최적화된 SQL을 생성하기 위해 최대 절전 모드로 전환하는 방법

휴지 상태에서는 가장 효율적인 쿼리를 작성하는 방법에 대한 힌트를 얻을 수 있을 것입니다만, 테이블 구성에 문제가 있는 것 같습니다.표에 관계가 확립되어 있습니까?휴지 상태에서는 특히 인덱스 등이 없는 경우 단순 쿼리가 조인보다 빠를 수 있습니다.

사용 방법:

select p from Person p left join FETCH p.address a where...

JPA2/EclipseLink에서도 동일하게 동작합니다만, 이 기능은 JPA1에도 있는 것 같습니다.

휴지 상태 대신 EclipseLink를 사용하면 "쿼리 힌트"를 통해 쿼리를 최적화할 수 있습니다.Eclipse Wiki: Eclipse Link/Examples/J에서 이 기사를 참조하십시오.PA/QueryOptimization.

'조인트 리딩'에 관한 장도 있습니다.

참여하려면 여러 가지 작업을 수행할 수 있습니다(eclipselink 사용).

  • jpql에서 왼쪽 결합 가져오기를 수행할 수 있습니다.

  • 명명된 쿼리에서 쿼리 힌트를 지정할 수 있습니다.

  • TypedQuery에서 다음과 같은 말을 할 수 있습니다.

    query.setHint("eclipselink.join-fetch", "e.projects.milestones");

  • 배치 가져오기 힌트도 있습니다.

    query.setHint("eclipselink.batch", "e.address");

http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html

개인 클래스에 포함된 키 클래스가 있다는 것을 제외하고 정확히 이 문제가 있었습니다.저만의 해결책은 쿼리에 참여해서

@Fetch(FetchMode.JOIN)

내장 ID 클래스:

@Embeddable
public class MessageRecipientId implements Serializable {

    @ManyToOne(targetEntity = Message.class, fetch = FetchType.LAZY)
    @JoinColumn(name="messageId")
    private Message message;
    private String governmentId;

    public MessageRecipientId() {
    }

    public Message getMessage() {
        return message;
    }

    public void setMessage(Message message) {
        this.message = message;
    }

    public String getGovernmentId() {
        return governmentId;
    }

    public void setGovernmentId(String governmentId) {
        this.governmentId = governmentId;
    }

    public MessageRecipientId(Message message, GovernmentId governmentId) {
        this.message = message;
        this.governmentId = governmentId.getValue();
    }

}

두 가지가 생각난다.

먼저, 주소는 ManyToOne이 맞습니까?즉, 여러 사람이 같은 주소를 갖게 됩니다.한 분만 편집이 되면 다 편집이 됩니다.그게 너의 의도야?시간 주소의 99%는 "개인"입니다(단 한 사람에게만 속한다는 의미).

둘째, Person 엔티티에 대해 다른 열심인 관계가 있습니까?내 기억이 맞다면, 휴지 상태에서는 엔티티에서 하나의 열렬한 관계만 처리할 수 있지만 오래된 정보일 수 있습니다.

제가 이렇게 말하는 이유는 제가 앉아있는 곳에서 이 일이 어떻게 진행되어야 하는지에 대한 당신의 이해가 기본적으로 옳기 때문입니다.

언급URL : https://stackoverflow.com/questions/463349/jpa-eager-fetch-does-not-join

반응형