연관관계 매핑(Association Mapping)은 JPA에서 객체 지향 프로그래밍과 데이터베이스의 관계형 모델을 매핑하는 핵심 개념 중 하나야. 객체 간의 관계를 데이터베이스 테이블 간의 외래 키(Foreign Key) 관계로 변환해, 테이블 간의 데이터를 쉽게 조작할 수 있어.
이 개념을 이해하려면, 객체 지향 세계와 데이터베이스 세계가 어떻게 서로 다른지를 알아야 해:
• 객체 지향 프로그래밍에서는 클래스 간의 관계를 직접 참조하고, 객체는 서로 다른 객체와 연결돼.
• 데이터베이스에서는 외래 키를 통해 테이블 간의 관계를 정의해.
이 두 세계가 어떻게 연관관계 매핑을 통해 연결되는지 자세히 설명해볼게.
1. 연관관계의 종류
연관관계는 크게 네 가지로 나눌 수 있어:
1. 일대일(One-to-One): 한 객체가 다른 객체와 하나의 관계를 가질 때.
2. 일대다(One-to-Many): 한 객체가 여러 객체와 관계를 가질 때.
3. 다대일(Many-to-One): 여러 객체가 하나의 객체와 관계를 가질 때.
4. 다대다(Many-to-Many): 여러 객체가 여러 객체와 관계를 가질 때.
2. 연관관계 매핑 어노테이션
연관관계 매핑을 위해 JPA는 다음과 같은 어노테이션을 제공해:
• @OneToOne: 일대일 관계를 정의할 때 사용.
• @OneToMany: 일대다 관계를 정의할 때 사용.
• @ManyToOne: 다대일 관계를 정의할 때 사용.
• @ManyToMany: 다대다 관계를 정의할 때 사용.
• @JoinColumn: 두 테이블 간의 외래 키를 명시적으로 정의할 때 사용.
3. 일대일(One-to-One) 연관관계
설명:
일대일(One-to-One) 관계는 두 객체가 1:1 대응을 가지는 상황이야. 예를 들어, **유저(User)**와 프로필(Profile) 관계를 생각해볼 수 있어. 한 유저는 하나의 프로필을 가지고, 하나의 프로필은 한 유저에게만 속해.
예시 코드:
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "profile_id")
private Profile profile;
}
@Entity
public class Profile {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String bio;
}
데이터베이스 설계:
User 테이블은 Profile 테이블과 1:1 관계를 가지며, 외래 키로 profile_id를 가짐. JPA에서 이를 @JoinColumn 어노테이션으로 명시해줘.
4. 다대일(Many-to-One) 연관관계
설명:
다대일(Many-to-One) 관계는 여러 개의 객체가 하나의 객체와 연결되는 상황이야. 예를 들어, 여러 **주문(Order)**이 하나의 **회원(Member)**에게 속하는 경우야.
예시 코드:
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
}
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
데이터베이스 설계:
Order 테이블은 여러 Order가 하나의 Member와 연결돼 있어. member_id가 외래 키로 사용되며, 이 외래 키를 통해 회원 정보와 연결돼.
5. 일대다(One-to-Many) 연관관계
설명:
일대다(One-to-Many) 관계는 하나의 객체가 여러 개의 객체와 관계를 가지는 상황이야. 예를 들어, 하나의 **회원(Member)**이 여러 개의 **주문(Order)**을 가질 수 있어.
일대다 관계는 다대일 관계의 반대라고 볼 수 있어. JPA에서는 일대다보다는 다대일이 더 자주 사용돼. 이유는 데이터베이스 테이블에서 다수의 관계를 효율적으로 표현하기가 어렵기 때문이야.
예시 코드:
@Entity
public class Member {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();
}
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
}
데이터베이스 설계:
이 경우, Member는 여러 개의 Order를 가질 수 있어. mappedBy는 반대쪽 엔티티에서 이미 관리되고 있는 연관관계를 가리키는 필드를 지정하는 거야.
6. 다대다(Many-to-Many) 연관관계
설명:
다대다(Many-to-Many) 관계는 두 객체가 서로 다수의 관계를 가지는 상황이야. 예를 들어, **학생(Student)**과 **수업(Course)**의 관계를 생각할 수 있어. 한 학생은 여러 수업을 들을 수 있고, 하나의 수업에는 여러 학생이 참여할 수 있어.
다대다 관계는 직접적으로 매핑하는 것이 아니라, **중간 테이블(Join Table)**을 통해 연결돼.
예시 코드:
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses = new ArrayList<>();
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany(mappedBy = "courses")
private List<Student> students = new ArrayList<>();
}
데이터베이스 설계:
이 경우, JPA는 **학생(Student)**과 수업(Course) 사이의 다대다 관계를 표현하기 위해 **중간 테이블(student_course)**을 자동으로 생성해. 이 중간 테이블은 두 테이블 간의 외래 키를 통해 서로 연결돼.
7. 연관관계의 방향성
JPA에서는 연관관계의 방향성을 설정할 수 있어. 즉, 두 엔티티 간의 관계가 단방향일지 양방향일지를 결정하는 거야.
• 단방향(Bidirectional): 한쪽 엔티티에서만 관계를 참조할 수 있는 경우. 예를 들어, Order가 Member를 참조하고 있지만, Member는 Order를 참조하지 않는 경우야.
• 양방향(Unidirectional): 양쪽 엔티티 모두에서 서로를 참조할 수 있는 경우. 예를 들어, Order가 Member를 참조하고, Member도 Order를 참조하는 경우야.
양방향 연관관계 주의 사항:
양방향 연관관계에서는 연관관계의 주인을 잘 설정해야 해. 주인은 외래 키를 관리하는 쪽이 되고, 이쪽에서만 데이터베이스에 영향을 미치게 돼. 반대쪽은 읽기 전용이야.
8. 연관관계 매핑 시 주의할 점
1. 무한 참조 문제: 양방향 연관관계에서 toString, equals, hashCode 메서드에 주의해야 해. 이를 제대로 처리하지 않으면, 무한 루프에 빠질 수 있어.
2. 지연 로딩과 즉시 로딩: 연관관계를 설정할 때, 지연 로딩(LAZY) 또는 즉시 로딩(EAGER) 방식을 지정할 수 있어. 지연 로딩은 실제로 데이터가 필요할 때만 로딩하고, 즉시 로딩은 연관된 엔티티를 즉시 가져오는 방식이야. 지연 로딩을 선호하는 이유는 성능 최적화 때문이야.
🎯 결론
JPA에서의 연관관계 매핑은 객체 지향 세계와 데이터베이스 세계 간의 관계를 조화롭게 연결하는 중요한 개념이야. 연관관계는 크게 일대일(One-to-One), 다대일(Many-to-One), 일대다(One-to-Many), **다대다(Many-to-Many)**로 나눌 수 있고, 각각의 관계는 JPA에서 제공하는 어노테이션을 통해 설정할 수 있어.
**연관관계의 방향성(단방향, 양방향)**과 지연 로딩/즉시 로딩 설정을 적절히 고려하면서 매핑을 수행하면, 객체 지향적인 코드와 관계형 데이터베이스 간의 매핑이 원활하게 이루어져. 이를 통해 데이터 일관성을 유지하면서도 성능 최적화와 유지보수를 용이하게 할 수 있어.
연관관계 매핑은 복잡해 보일 수 있지만, 각 상황에 맞는 매핑 방식을 잘 선택하고, 외래 키와 연관관계의 주인 개념을 명확하게 이해하면 데이터베이스와의 상호작용을 훨씬 더 유연하게 처리할 수 있어.
'Database > JPA' 카테고리의 다른 글
JPA 연관관계와 복합 키 (2) | 2024.09.13 |
---|---|
JPA의 단방향, 양방향 연관관계와 Cascade 이해하기 (0) | 2024.09.13 |
JPA 기본 키 생성 전략: IDENTITY, SEQUENCE, TABLE과 allocationSize의 이해 (1) | 2024.09.10 |
QueryDSL로 JPA 쿼리 쉽게 작성하기 (3) | 2024.09.10 |
JPA 엔티티 관리 메서드 (0) | 2024.09.10 |