Database/JPA / / 2024. 9. 13. 10:37

JPA의 단방향, 양방향 연관관계와 Cascade 이해하기

JPA에서의 연관관계: 단방향과 양방향

 

JPA에서 엔티티 간의 연관관계는 크게 단방향양방향으로 나뉘어. 이는 객체 간의 참조를 어떻게 설정하는지에 따라 구분돼. 또한, 연관관계는 일대일(1:1), 일대다(1:N), 다대일(N:1), **다대다(N:M)**로 나눌 수 있어. 각각의 경우를 단방향과 양방향으로 나누어 설명해줄게.

 

1. 단방향 연관관계

 

단방향 연관관계에서는 한쪽 엔티티만 다른 엔티티를 참조해. 즉, 객체 간의 관계가 한쪽으로만 연결돼 있는 경우야.

 

예시: 다대일(N:1) 단방향

 

상황: 여러 명의 학생이 한 명의 선생님에게 속해 있는 경우 (학생:선생님 = N:1).

설명: 학생(Student) 엔티티는 선생님(Teacher) 엔티티를 참조하지만, 선생님은 학생을 참조하지 않아.

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;
}

 

위 코드에서 StudentTeacher를 참조하지만, TeacherStudent를 참조하지 않기 때문에 단방향 관계야.

 

2. 양방향 연관관계

 

양방향 연관관계에서는 양쪽 엔티티가 서로를 참조해. 즉, 객체 간의 관계가 서로 연결되어 있어, 한쪽에서 다른 쪽을 조회할 수 있고, 반대쪽에서도 이를 조회할 수 있어.

 

예시: 다대일(N:1) 양방향

 

상황: 여러 명의 학생이 한 명의 선생님에게 속해 있고, 선생님은 자신의 학생들을 조회할 수 있음.

설명: 학생은 선생님을 참조하고, 선생님도 학생들을 참조하는 양방향 관계.

@Entity
public class Teacher {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @OneToMany(mappedBy = "teacher")
    private List<Student> students = new ArrayList<>();
}

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;
}

 

Teacher 엔티티는 students 리스트를 통해 학생들을 참조하고, Student 엔티티는 teacher를 참조해서 양방향 연관관계가 설정돼.

 

양방향 관계에서 중요한 점:

 

양방향 관계를 유지하려면, 편의 메서드를 통해 두 엔티티 간의 관계를 동기화해줘야 해.

예를 들어, StudentTeacher에 추가할 때, Teacher에서도 Student를 참조하도록 설정해야 데이터 일관성이 유지돼.

 

연관관계의 종류와 단방향/양방향 적용

 

1. 일대일(1:1)

 

단방향: 한쪽 엔티티에서만 다른 엔티티를 참조.

예시: 한 명의 사람이 하나의 여권을 가짐.

@Entity
public class Person {
    @OneToOne
    @JoinColumn(name = "passport_id")
    private Passport passport;
}

 

양방향: 양쪽 엔티티가 서로를 참조.

@Entity
public class Passport {
    @OneToOne(mappedBy = "passport")
    private Person person;
}

 

2. 일대다(1:N)

 

단방향: 한쪽 엔티티에서 여러 엔티티를 참조.

예시: 한 명의 선생님이 여러 명의 학생을 가르침.

@Entity
public class Teacher {
    @OneToMany
    @JoinColumn(name = "teacher_id")
    private List<Student> students;
}

 

양방향: 양쪽에서 서로 참조. (위 다대일 양방향 예시와 같음)

 

3. 다대일(N:1)

 

단방향: 다수의 엔티티가 하나의 엔티티를 참조. (위 단방향 다대일 예시와 같음)

양방향: 양쪽에서 서로 참조. (위 양방향 다대일 예시와 같음)

 

4. 다대다(N:M)

 

단방향: 양쪽 엔티티가 각각 서로를 참조.

예시: 학생이 여러 과목을 듣고, 과목도 여러 학생을 가짐.

@Entity
public class Student {
    @ManyToMany
    @JoinTable(name = "student_subject",
               joinColumns = @JoinColumn(name = "student_id"),
               inverseJoinColumns = @JoinColumn(name = "subject_id"))
    private List<Subject> subjects = new ArrayList<>();
}

@Entity
public class Subject {
    @ManyToMany(mappedBy = "subjects")
    private List<Student> students = new ArrayList<>();
}

 

결론

 

단방향: 한쪽 엔티티만 참조.

양방향: 양쪽 엔티티가 서로 참조.

양방향 관계에서 편의 메서드를 사용해 관계를 동기화해야 데이터 일관성을 유지할 수 있어.

 

JPA에서의 Cascade는 엔티티 간의 연관관계에서 부모 엔티티의 상태 변화(저장, 삭제 등)가 자식 엔티티에 자동으로 전파되도록 하는 설정이야. 즉, 부모 엔티티를 저장하거나 삭제할 때, 연관된 자식 엔티티도 자동으로 처리되도록 할 수 있어. 이는 데이터 일관성을 유지하고, 수동으로 각각의 엔티티를 처리해야 하는 번거로움을 줄여줘.

 

Cascade의 종류

 

1. CascadeType.PERSIST: 부모 엔티티를 저장할 때, 연관된 자식 엔티티도 자동으로 저장돼.

예: 부모 엔티티 Team을 저장하면, 연관된 Member 엔티티들도 함께 저장됨.

2. CascadeType.REMOVE: 부모 엔티티를 삭제할 때, 연관된 자식 엔티티도 자동으로 삭제돼.

예: Team을 삭제하면, 해당 Team에 속한 모든 Member도 삭제됨.

3. CascadeType.MERGE: 부모 엔티티가 병합(업데이트)될 때, 연관된 자식 엔티티도 자동으로 병합돼.

예: Team 엔티티를 병합할 때, 자식 Member 엔티티들도 자동으로 병합됨.

4. CascadeType.REFRESH: 부모 엔티티가 새로 고침될 때, 연관된 자식 엔티티도 함께 새로 고침돼.

예: Team 엔티티가 새로고침될 때, 연관된 Member들도 새로 고침됨.

5. CascadeType.DETACH: 부모 엔티티가 영속성 컨텍스트에서 분리될 때, 자식 엔티티도 함께 분리돼.

예: Team이 영속성 컨텍스트에서 분리되면, 연관된 Member들도 영속성 컨텍스트에서 분리됨.

6. CascadeType.ALL: 위의 모든 Cascade 옵션을 한 번에 적용하는 설정. 즉, PERSIST, REMOVE, MERGE, REFRESH, DETACH 모두가 적용돼.

 

예시 코드

@Entity
public class Team {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "team", cascade = CascadeType.ALL)
    private List<Member> members = new ArrayList<>();

    // 연관관계 편의 메서드
    public void addMember(Member member) {
        members.add(member);
        member.setTeam(this);
    }
}

 

위 코드에서, TeamMember는 1:N 관계로, Team을 저장, 삭제, 병합할 때 모든 연관된 Member도 자동으로 처리돼.

 

Cascade의 장점

 

1. 코드 간소화: 연관된 엔티티들을 일일이 관리하지 않고, 한 번의 조작으로 자동으로 처리할 수 있어.

2. 일관성 유지: 부모 엔티티와 자식 엔티티 간의 상태를 항상 일관성 있게 유지할 수 있어.

 

주의할 점

 

Cascade 설정을 무분별하게 사용하면, 데이터 손실 등의 위험이 생길 수 있어. 특히 CascadeType.REMOVE처럼 부모 엔티티가 삭제될 때 자식 엔티티도 함께 삭제되기 때문에, 잘못된 설정으로 인한 데이터 손실에 주의해야 해.

 

정리하자면, Cascade는 연관된 엔티티들 간의 일관성을 유지하고, 코드를 간소화하기 위해 사용되지만, 상황에 맞게 올바르게 설정하는 것이 중요해.

  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유