-
Spring boot: JPA 연관관계 살펴보기 - 1:1Spring Boot 🍃 2023. 12. 5. 00:01
1 대 1 연관관계
어느 엔티티 쪽에서 상대 엔티티와 반드시
단 하나
의 관계를 가지는 것을 말한다.1:1 연관관계는 생각보다 실무에서 많이 사용된다.
실습 1: 단방향
book 테이블과 bookReviewInfo 테이블이 1:1로 조인하는 경우에 대해 실습해본다.
bookReviewInfo 엔티티에 book 엔티티를 조인해서 데이터 확인
엔티티 작성
Book 엔티티
@ToString(callSuper = true) @Getter @Setter @SuperBuilder @NoArgsConstructor @AllArgsConstructor @Entity public class Book extends BaseEntity { private String name; private String category; private Long authorId; private Long publisherId; }
BookReviewInfo 엔티티
@ToString(callSuper = true) @Getter @Setter @SuperBuilder @AllArgsConstructor @NoArgsConstructor @Entity public class BookReviewInfo extends BaseEntity { @OneToOne(optional = false) private Book book; private float averageReviewScore; private int reviewCount; }
BookReviewInfo 엔티티를 작성할 때 Book 객체를 필드로 작성하고, Book 필드에 연관관계 어노테이션을 붙여주면 JPA가 아래와 같이 해석해준다.
create table book_review_info ( average_review_score float(24) not null, review_count integer not null, book_id bigint not null unique, -- 이 부분이 Book 객체를 해석한 부분 created_at timestamp(6), id bigint generated by default as identity, updated_at timestamp(6), primary key (id) )
test 코드 실행: 쿼리 확인
test 코드
@Test void showQuery() { // book 데이터 & bookReviewInfo 데이터 생성 givenBookReviewInfo(); // bookReviewInfo 조회 Book result = bookReviewInfoRepository .findById(1L) .orElseThrow(RuntimeException::new) .getBook(); }
JPA query
select b1_0.id, b1_0.average_review_score, b1_0.book_id, b2_0.id, b2_0.author_id, b2_0.category, b2_0.created_at, b2_0.name, b2_0.publisher_id, b2_0.updated_at, b1_0.created_at, b1_0.review_count, b1_0.updated_at from book_review_info b1_0 join book b2_0 on b2_0.id=b1_0.book_id where b1_0.id=?
실습 2: 양방향
1:1 연관관계를 맺는 경우,
양방향으로 관계를 설정하는 경우는 극히 드물다.
양방향 관계는 1:N , N:N의 관계에서 주로 맺게 된다.
하지만 학습을 위해 실습!
엔티티 작성
Book 엔티티 수정
book 엔티티에도 bookReviewInfo 엔티티 필드를 1:1관계로 추가해준다.
이떄, 연관관계 어노테이션에
mappedBy="엔티티이름"
설정을 추가해주어, 연관키를 해당 엔티티에서 가지지 않도록 설정을 해주고 optional 설정을 기본값인 true 로 변경해주어야 한다.또한, ToString을 사용하는 엔티티라면, 순환참조가 발생하여 StackOverFlow 에러를 만나게 되므로
@ToString.exclude
설정을 주어야 한다.public class Book extends BaseEntity { @OneToOne(mappedBy = "book") @ToString.Exclude private BookReviewInfo bookReviewInfo; private String name; private String category; private Long authorId; private Long publisherId; }
변환 된 sql 쿼리
Hibernate: create table book ( author_id bigint, created_at timestamp(6), id bigint generated by default as identity, publisher_id bigint, updated_at timestamp(6), category varchar(255), name varchar(255), primary key (id) )
mappedBy 설정으로 인해 create 쿼리에서는 BookReviewInfo_id 필드가 작성되어있지 않다.
BookReviewInfo 엔티티는 그대로!
public class BookReviewInfo extends BaseEntity { @OneToOne(optional = false) private Book book; private float averageReviewScore; private int reviewCount; }
test 코드 실행: 쿼리 확인
양방향 확인을 위해 Book 정보를 BookReviewInfoRepository에서 가져오고, BookReviewInfo 정보를 BookRepository에서 가져온다.
test 코드
@Test void crud() { givenBookReviewInfo(); Book result = bookReviewInfoRepository .findById(1L) .orElseThrow(RuntimeException::new) .getBook(); System.out.println("[ review id=1 인 book 정보 ]___________🚩 " + result); BookReviewInfo result2 = bookRepository .findById(1L) .orElseThrow(RuntimeException::new) .getBookReviewInfo(); System.out.println("[ book id=1 인 bookReviewInfo 정보 ]___________🚩 " + result2); }
jpa 작성 쿼리!
Hibernate: select b1_0.id, b1_0.average_review_score, b1_0.book_id, b2_0.id, b2_0.author_id, b2_0.category, b2_0.created_at, b2_0.name, b2_0.publisher_id, b2_0.updated_at, b1_0.created_at, b1_0.review_count, b1_0.updated_at from book_review_info b1_0 join book b2_0 on b2_0.id=b1_0.book_id where b1_0.id=? [ review id=1 인 book 정보 ]___________🚩 Hibernate: select b1_0.id, b1_0.author_id, b2_0.id, b2_0.average_review_score, b2_0.book_id, b2_0.created_at, b2_0.review_count, b2_0.updated_at, b1_0.category, b1_0.created_at, b1_0.name, b1_0.publisher_id, b1_0.updated_at from book b1_0 left join book_review_info b2_0 on b1_0.id=b2_0.book_id where b1_0.id=? [ book id=1 인 bookReviewInfo 정보 ]___________🚩
Book 엔티티의 테이블 생성문에서 BookReviewInfo_id 필드가 생성되지 않았지만,
OneToOne 관계 설정을 해두었기 때문에, 두 엔티티의 공통 필드인 book_id로 Join이 가능해진다.
'Spring Boot 🍃' 카테고리의 다른 글
Thymeleaf 와 Enum 클래스를 사용해서, html radio 태그 제어 (0) 2023.12.06 Spring boot: JPA 연관관계 살펴보기 - 1:N (0) 2023.12.06 Spring Boot: Entity Listener (0) 2023.12.05 Spring boot: H2 DB 인텔리제이에서 확인하기 (0) 2023.12.05 Spring boot : sql dummy data 만들기 (0) 2023.12.05