Spring Data JPA와 JPA 양방향 연관관계를 세팅하고 사용 시 주의할 점에 대해서 정리하였다. 밑은 간단한 예제 코드를 준비하였다.
User
는 다양한 Knowledge
을 등록할 수 있다. 정리하면 User
는 N
개의 Knowledge
를 등록할 수 있다고 가정한다. 두 엔티티 간의 관계는 1:N
이다.
User.java
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(length = 60)
private String email;
@Builder
public User(String email) {
this.email = email;
}
}
Knowledge.java
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Knowledge {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "knowledge_id")
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Column(length = 20)
private String title;
@Column(columnDefinition = "TEXT")
private String content;
@Builder
public Knowledge(User user, String title, String content) {
this.user = user;
this.title = title;
this.content = content;
}
}
현재 @ManyToOne
을 활용하여 단방향 연관관계를 세팅해주었다.
연관관계의 주인은 외래키가 있는 곳이다. User
와 Knowledge
중 user_id
를 외래키로 가지고 있는 곧은 N
쪽의 Knowledge
가 된다. 그렇기 때문에 외래키는 Knowledge
테이블에 세팅되어 있다.
이제 User 쪽에서 자신이 등록한 knowledge 목록에 접근할 수 있도록 추가적인 연관관계를 세팅해준다.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Long id;
@Column(length = 60)
private String email;
@OneToMany(mappedBy = "user")
private List<Knowledge> knowledges = new ArrayList<>();
@Builder
public User(String email) {
this.email = email;
}
}
MappedBy
는 주인이 아님을 설정한다. 속성의 값은 연관관계의 주인이 Knowledge.user 라는 것을 암시한다.
User.Knowledges와 Knowledge.User 중 연관관계의 주인은 Knowledge.user이 된다.
연관관계의 주인
이라는 의미는 두 엔티티 관계에서 주인으로서 역할은 하는 것이 아니다. 단순히 데이터베이스에서 외래키
를 가지고 있기 때문에 외래키를 관리하는 주인이 된다. 그렇기 때문에 주인이 아닌 User.knowledges
를 통해서는 단순히 데이터베이스의 값을 읽기
만 가능하다.
가장 치명적인 실수는 연관관계의 주인이 아닌 곳
에서 데이터를 삽입하는 것이다. 오직 연관관계의 주인
만이 외래키의 값을 변경
할 수 있다.