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 참조).FetchType
JPA를 사용하다.그래서 내 경우엔 참여하라고 분명히 말했다.
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
'IT' 카테고리의 다른 글
절차에서 테이블 이름을 쉽게 바꿀 수 있는 방법이 있습니까? (0) | 2022.11.08 |
---|---|
문자열의 첫 번째 문자가 숫자인지 확인하려면 어떻게 해야 하나요? (0) | 2022.11.08 |
Java의 split() 메서드는 닷()에서는 동작하지 않습니다. (0) | 2022.11.08 |
코드 실행 속도: ASP.NET-MVC 대 PHP (0) | 2022.11.08 |
jooq TIMESTAMP(6) 지원 (0) | 2022.11.08 |