다대일 연관관계를 맺고 있는 두 엔티티가 있다고 하자.
<Member>
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "team_id")
private Team team;
public Member(Team team) {
this.team = team;
}
}
<Team>
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
일반적으로 어떤 Member를 save 한다 했을 때, 다음과 같이 코드를 짠다.
Team team = teamRepository.findById(teamId).get(); // team을 조회하는 작업
Member member = new Member(team);
memberRepository.save(member);
코드를 요약하자면 save하기 위한 Member를 생성하기 위해서는 Team이 필요하고,
Team을 생성하기 위해서는 Team을 조회하는 작업이 필요하다. 즉, select * from team where id=? 쿼리가 추가로 필요한 것이다.
비록 Team을 Member의 생성자에 직접 넣었지만 DB에는 다음과 같이 Team의 id 값으로 외래키를 갖게 된다.
그럼 애초부터 Member 생성자에 Team의 id 값을 넣으면 굳이 Team을 조회할 일이 없지 않을까 생각할 수 있다.
우선 일반적으로 객체지향 프로그래밍 관점에서 연관관계를 객체들끼리만 맺는 것이 좋은 방향이다. (객체에서 객체 조회, 지연 로딩 등)
따라서, 가벼운 API라면 그냥 현 상태를 유지하는 것이 옳바르다.
그러나 save() 작업히 1,000건, 10,000 건 이상되는 무거운 API에서는 이야기가 달라진다.
10,000건의 insert 쿼리를 날리기 위해 team을 조회하는 추가적인 10,000건의 select 쿼리가 필요하다면 이는 최적화 관점에서 코드를 수정할 필요가 있다. (물론 필수적인 것은 아니다)
따라서, DB의 관점에서 Member 생성자에 오로지 team_id만을 넣고 save하는 방법을 소개한다.
엔티티를 다음과 같이 수정하자.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(targetEntity = Team.class, fetch = FetchType.LAZY)
@JoinColumn(name = "team_id", insertable = false, updatable = false)
private Team team;
@Column(name = "team_id")
private Long teamId;
public Member(Long teamId) {
this.teamId = teamId;
}
}
Member member = new Member(teamId);
memberRepository.save(member);
이렇게 teamId라는 필드를 하나 더 추가한 뒤,
원래 있었던 team 필드에 insertable=false, updatable=false 설정을 추가하면, 하이버네이트에서 따로 에러를 발생시키지 않는다.
이제 두 번째 코드처럼 team에 대한 조회 없이 바로 teamId를 외래키처럼 추가함으로써 Member를 생성할 수 있다.
참고자료
https://stackoverflow.com/questions/27930449/jpa-many-to-one-relation-need-to-save-only-id
'java > jpa' 카테고리의 다른 글
[JPA] drop table if exists user cascade " via JDBC (0) | 2024.08.14 |
---|---|
[JPA] column default value 넣기 (0) | 2023.07.09 |
[JPA] DDL-AUTO 테이블 자동 생성 전략 - SQL Column 매칭 (0) | 2021.06.10 |
[JPA] CommandAcceptanceException: Error executing DDL (0) | 2021.06.10 |
[Spring Data JPA] 나머지 기능들 (0) | 2021.05.31 |