JPA OneToOne 관계를 게으르게 만들려면 어떻게 해야 합니까?
우리가 개발하고 있는 이 어플리케이션에서는 뷰가 특히 느리다는 것을 알 수 있었습니다.뷰 프로파일을 작성했더니 데이터베이스에 오브젝트가 2개만 있어도 하이버네이션에 의해 실행되는 쿼리가 1개 있었습니다. ★★★★★OneToMany
★★★★★★★★★★★★★★★★★」ManyToMany
관계가 게으르니까 그게 문제가 아니었던 것 같아요.실제 실행 중인 SQL을 검사했을 때 쿼리에 80개 이상의 조인(join)이 있는 것을 알 수 있었습니다.
, 이 은 '이러다', '이러다', '이러다'의 계층구조가 깊기 때문이라는 것을 알 수 있었습니다.OneToOne
★★★★★★★★★★★★★★★★★」ManyToOne
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★그래서 저는 그냥 게으름을 피우면 문제가 해결될 거라고 생각했어요. 주석을 것은 어느 쪽인가.@OneToOne(fetch=FetchType.LAZY)
★★★★★★★★★★★★★★★★★」@ManyToOne(fetch=FetchType.LAZY)
효과가 없는 것 같습니다.예외가 발생하거나 프록시 오브젝트로 대체되지 않아 게으릅니다.
이걸 어떻게 작동시킬지 생각나는 거 없어?, 저는 주:: 이는 the the the the the the the the the the the the the the the the the note note note라는 말을 하지 않습니다.persistence.xml
관계나 설정의 상세를 정의하기 위해서, 모든 것은 Java 코드로 행해집니다.
먼저 KLE의 답변에 대한 몇 가지 설명을 제시하겠습니다.
바이트 코드 인스트루먼테이션이 없으면 프록시를 할 수 없는 것은 구속되지 않은(늘이 없는) 일대일 어소시에이션뿐입니다.그 이유는 소유자 엔티티는 연결 속성이 프록시 개체를 포함해야 하는지 아니면 NULL을 포함해야 하는지 알아야 하며 일반적으로 공유 PK를 통해 매핑되기 때문에 기본 테이블의 열을 보고 결정할 수 없기 때문에 프록시를 열심히 가져와야 하기 때문에 프록시가 무의미하기 때문입니다.여기 좀 더 자세한 설명이 있습니다.
다대일 어소시에이션(및 1대 다)은 이 문제에 시달리지 않습니다.소유자 엔티티는 자신의 FK를 쉽게 확인할 수 있기 때문에(1대 다의 경우 빈 컬렉션 프록시가 처음에 생성되어 온 디맨드로 채워지기 때문에) 어소시에이션이 늦어질 수 있습니다.
1대1을 1대 다로 대체하는 것은 결코 좋은 생각이 아닙니다.독자적인 다대 1로 대체할 수 있지만 다른 옵션(아마도 더 나은 옵션)도 있습니다.
Rob H.의 주장은 유효하지만, 모델에 따라서는 실장할 수 없는 경우가 있습니다(예를 들면, 1 대 1의 어소시에이션이 무효인 경우).
자, 첫 번째 질문은 다음과 같습니다.
A)@ManyToOne(fetch=FetchType.LAZY)
잘 될 겁니다쿼리 자체에서 덮어쓰기가 아닌 것이 확실합니까?수 있습니다.join fetch
클래스 주석보다 우선하는 Criteria API를 통해 가져오기 모드를 명시적으로 설정합니다.그렇지 않은 경우에도 문제가 해결되지 않으면 수업, 질의 및 결과 SQL을 게시하여 자세한 내용을 상담해 주십시오.
B)@OneToOne
더 까다롭습니다.확실히 무효가 아닌 경우는, Rob H.의 제안에 따라서, 다음과 같이 지정합니다.
@OneToOne(optional = false, fetch = FetchType.LAZY)
그렇지 않으면 데이터베이스를 변경할 수 있는 경우(외부 키 열을 소유자 테이블에 추가), 데이터베이스를 변경하고 "joined"로 매핑합니다.
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
public OtherEntity getOther()
기타 엔티티:
@OneToOne(mappedBy = "other")
public OwnerEntity getOwner()
그렇게 할 수 없는 경우(또한 급하게 가져올 수 없는 경우) 바이트 코드 인스트루먼테이션이 유일한 옵션입니다.단, CPerkins에 동의해야 합니다.- 만약 당신이 80을 가지고 있다면!!!OneToOne의 어소시에이션이 활발하기 때문에, 이것보다 더 큰 문제가 있습니다:-)
null 가능한 일대일 매핑에 대한 로딩이 느리도록 하려면 최대 절전 모드로 컴파일 시간 계측을 수행하고,@LazyToOne(value = LazyToOneOption.NO_PROXY)
1시 1분
매핑 예:
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
@LazyToOne(value = LazyToOneOption.NO_PROXY)
public OtherEntity getOther()
Ant Build 파일 확장자의 예(Hibernate 컴파일 시간 계측의 경우):
<property name="src" value="/your/src/directory"/><!-- path of the source files -->
<property name="libs" value="/your/libs/directory"/><!-- path of your libraries -->
<property name="destination" value="/your/build/directory"/><!-- path of your build directory -->
<fileset id="applibs" dir="${libs}">
<include name="hibernate3.jar" />
<!-- include any other libraries you'll need here -->
</fileset>
<target name="compile">
<javac srcdir="${src}" destdir="${destination}" debug="yes">
<classpath>
<fileset refid="applibs"/>
</classpath>
</javac>
</target>
<target name="instrument" depends="compile">
<taskdef name="instrument" classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
<classpath>
<fileset refid="applibs"/>
</classpath>
</taskdef>
<instrument verbose="true">
<fileset dir="${destination}">
<!-- substitute the package where you keep your domain objs -->
<include name="/com/mycompany/domainobjects/*.class"/>
</fileset>
</instrument>
</target>
Enhancement를 한 가져올 수 .@OneToOne
★★★★★★ 。
대부분의@MapsId
「」는 다음과 같습니다.
@Entity(name = "PostDetails")
@Table(name = "post_details")
public class PostDetails {
@Id
private Long id;
@Column(name = "created_on")
private Date createdOn;
@Column(name = "created_by")
private String createdBy;
@OneToOne(fetch = FetchType.LAZY)
@MapsId
private Post post;
public PostDetails() {}
public PostDetails(String createdBy) {
createdOn = new Date();
this.createdBy = createdBy;
}
//Getters and setters omitted for brevity
}
★★★★★★★★★★★★★★★★ @MapsId
, . . . . . . . .id
자녀 테이블의 속성은 부모 테이블의 프라이머리 키와 외부 키 역할을 합니다.
부모에 Post
엔티티에서는 상위 엔티티 ID를 사용하여 하위 엔티티를 쉽게 가져올 수 있습니다.
PostDetails details = entityManager.find(
PostDetails.class,
post.getId()
);
하면 N+1 쿼리 발생할 수 1mappedBy
@OneToOne
어소시에이션이 표시됩니다.
(인스트루먼테이션 없이) 다음과 같은 작업을 수행할 수 있습니다.
「 」를 하는 대신에, 「 」를 사용합니다.@OneToOne
쪽쪽, 는 on를 합니다.@OneToMany
mappedBy
)이 됩니다.List
아래 예에서는) 단, getter 내의 항목으로 변환하여 클라이언트에 투명하게 합니다.
이 설정은 느긋하게 동작합니다.즉, 선택은 다음 경우에만 이루어집니다.getPrevious()
★★★★★★★★★★★★★★★★★」getNext()
호출됩니다.콜마다 1개만 선택됩니다.
테이블 구조:
CREATE TABLE `TB_ISSUE` (
`ID` INT(9) NOT NULL AUTO_INCREMENT,
`NAME` VARCHAR(255) NULL,
`PREVIOUS` DECIMAL(9,2) NULL
CONSTRAINT `PK_ISSUE` PRIMARY KEY (`ID`)
);
ALTER TABLE `TB_ISSUE` ADD CONSTRAINT `FK_ISSUE_ISSUE_PREVIOUS`
FOREIGN KEY (`PREVIOUS`) REFERENCES `TB_ISSUE` (`ID`);
클래스:
@Entity
@Table(name = "TB_ISSUE")
public class Issue {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Integer id;
@Column
private String name;
@OneToOne(fetch=FetchType.LAZY) // one to one, as expected
@JoinColumn(name="previous")
private Issue previous;
// use @OneToMany instead of @OneToOne to "fake" the lazy loading
@OneToMany(mappedBy="previous", fetch=FetchType.LAZY)
// notice the type isnt Issue, but a collection (that will have 0 or 1 items)
private List<Issue> next;
public Integer getId() { return id; }
public String getName() { return name; }
public Issue getPrevious() { return previous; }
// in the getter, transform the collection into an Issue for the clients
public Issue getNext() { return next.isEmpty() ? null : next.get(0); }
}
하이버네이트에서 XToOnes의 기본 개념은 대부분의 경우 게으르지 않다는 것입니다.
중 것을 할 그 이유는 다음과 같습니다.
어쨌든 다른 테이블을 들여다봐야 합류를 할 수 있어요.데이터베이스 내의 다른 테이블에 액세스하기 위한 비용은 매우 높기 때문에 같은 테이블에 대한 두 번째 액세스가 필요한 나중에 요청을 통해 데이터를 가져오는 것이 아니라 해당 테이블의 데이터를 해당 시점에서 가져오는 것이 좋습니다(느긋하지 않은 동작).
편집: 자세한 내용은 ChssPly76의 답변을 참조하십시오.이 제품은 정확도가 떨어지고 세부 사항도 적어서 제공할 것이 없습니다.ChssPly76 감사합니다.
네이티브 Hibernate XML 매핑에서는 true로 설정된 제약 Atribut을 사용하여 일대일 매핑을 선언함으로써 이를 실현할 수 있습니다.휴지 상태/J가 무엇인지 확실하지 않습니다.PA 주석은 이에 해당하며, 문서를 빠르게 검색해도 답이 없지만 계속 진행해야 할 단서를 얻을 수 있기를 바랍니다.
ChssPly76에서 이미 완벽하게 설명했듯이, Hibernate의 프록시는 제약이 없는(늘이 없는) 일대일 연관성에 도움이 되지 않지만, 여기에 계장을 설정하지 않기 위한 요령이 있습니다.사용하는 엔티티 클래스가 이미 인스톨 되어 있는 것을 Hibernate로 속이는 것입니다.소스코드에서 수동으로 인스톨 합니다.쉬워요!CGLib를 바이트 코드 공급자로 구현했는데, 작동됩니다(HBM에서 lazy="no-module" 및 fetch="select"를 구성해야 합니다).
1대 1로 게을러지고 싶은 무효 관계가 있는 경우, 이것은 실제(즉 자동) 계측의 좋은 대안이라고 생각합니다.가장 큰 결점은 사용하고 있는 바이트 코드 공급자에 따라 솔루션이 달라지기 때문에 나중에 바이트 코드 공급자를 변경해야 할 수 있으므로 클래스에 정확하게 코멘트를 추가해야 한다는 것입니다.물론 기술적인 이유로 모델 bean도 수정하고 있기 때문에 이는 적절하지 않습니다.
이 질문은 꽤 오래되었지만, Hibernate 5.1.10에서는 보다 편리한 새로운 솔루션이 몇 가지 있습니다.
느린 로드는 @One To One 어소시에이션의 부모측을 제외하고 동작합니다.이는 휴지 상태에서는 이 변수에 늘 또는 프록시를 할당할지 여부를 알 수 있는 다른 방법이 없기 때문입니다.상세한 것에 대하여는, 이 기사를 참조해 주세요.
- 느린 로드 바이트 코드 확장을 활성화할 수 있습니다.
- 또는 위 기사에서 설명한 바와 같이 부모측을 삭제하고 클라이언트측을 @MapsId로 사용할 수도 있습니다.이렇게 하면 자녀가 부모와 동일한 ID를 공유하기 때문에 부모 ID를 알면 아이를 쉽게 가져올 수 있기 때문에 부모 측이 실제로 필요하지 않다는 것을 알 수 있습니다.
1 대 1 어소시에이션의 가장 효율적인 매핑 양쪽 엔티티에 동일한 프라이머리 키 값을 사용함으로써 이러한 모든 문제를 회피하고 외부 키 열을 제거할 수 있습니다.이를 수행하려면 @MapsId와의 관련성을 소유하는 측에 주석을 붙입니다.
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
@OneToOne(mappedBy = "book", fetch = FetchType.LAZY, optional = false)
private Manuscript manuscript;
...
}
@Entity
public class Manuscript {
@Id
private Long id;
@OneToOne
@MapsId
@JoinColumn(name = "id")
private Book book;
...
}
Book b = em.find(Book.class, 100L);
Manuscript m = em.find(Manuscript.class, b.getId());
Kotlin dev: 할 수 하려면 상속 또는hibernate 로딩 가능해야 합니다.open
디폴트로는 Kotlin에는 없습니다.이 문제를 회피하기 위해 컴파일러 플러그인을 사용하여 이 문제를 JPA에 추가함으로써 JPA 주석도 처리하도록 지시할 수 있습니다.build.gradle
:
allOpen {
annotation("javax.persistence.Entity")
annotation("javax.persistence.MappedSuperclass")
annotation("javax.persistence.Embeddable")
}
저처럼 Kotlin과 Spring을 사용하고 있다면 아마 no-args
/ 및 all-open
/ 컴파일러 플러그인도 이미 사용하고 있을 것입니다.그러나 플러그인의 조합으로 클래스가 생성되지 않기 때문에 위의 행을 추가해야 합니다.open
.
자세한 설명은 Léo Millon의 훌륭한 기사를 읽어보십시오.
관계가 양방향일 필요가 없는 경우 @ElementCollection은 느린 One2Many 컬렉션을 사용하는 것보다 쉽습니다.
하위 엔티티가 읽기 전용으로 사용되는 경우 단순히 거짓말과 설정을 수행할 수 있습니다.optional=false
그런 다음 매핑된 엔티티의 모든 사용이 쿼리를 통해 미리 로드되어 있는지 확인합니다.
public class App {
...
@OneToOne(mappedBy = "app", fetch = FetchType.LAZY, optional = false)
private Attributes additional;
그리고.
String sql = " ... FROM App a LEFT JOIN FETCH a.additional aa ...";
...아마도 끈질기게 버틸 수 있을 거야...
언급URL : https://stackoverflow.com/questions/1444227/how-can-i-make-a-jpa-onetoone-relation-lazy
'programing' 카테고리의 다른 글
GDB에서 "Single-steping to exit . . that is no line number information" 이라는 메시지가 표시되는 이유는 무엇입니까? (0) | 2022.08.24 |
---|---|
vuejs 2.0의 재귀 구성 요소 통신 (0) | 2022.08.24 |
모듈 네임스페이스와 함께 Vuex 유형 상수를 사용하는 방법 (0) | 2022.08.24 |
C/C++의 정규 분포에 따라 난수 생성 (0) | 2022.08.24 |
C/C++ 소스 코드를 코딩 표준과 대조하여 검사하는 무료 툴? (0) | 2022.08.24 |