FrameWork/Spring

연관관계

jheaon 2024. 6. 4. 05:24

 

오늘은 연관관계에 대해서 알아보고자 한다. 

 


 

연관관계

연관관계란 객체와 데이터베이스 테이블을 서로 매핑(매칭)시켜주는 것을 의미한다. 

 

방향

객체들이 연관관계를 맺을 때, 한쪽에서만 참조가 가능한지 양방향에서 참조가 가능한지에 대한 방향을 의미한다.

 

일반적으로 DB테이블간에는 어떤 테이블을 기준으로 하든 원하는 정보를 JOIN을 사용하여 조회가 가능하기 때문에 방향이라는 개념이 없지만, 객체 지향에서는 다른 객체에서 또 다른 객체를 조회하기 위해서 조회하고자 하는 객체의 정보를 가지고 있지 않으면 조회가 불가능하기 때문에 조회를 하기 위해서 방향을 설정해주는 것이 중요하다. 

 

  • 단방향 : 객체들이 연관관계를 맺을 때, 한쪽에서만 참조 가능한 경우 
  • 양방향 : 객체들이 연관관계를 맺을 때, 양쪽에서 참조 가능한 경우 

 

 

 

1 대 1관계

각 엔티티끼리의 관계가 1대 1관계 일때는 @OnetoOne에너테이션을 이용하여 관계를 맺는다. 

 

  • 단방향 관계

아래는 음식에 외래키가 주어주었을때의 예제이다. 

 

음식

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @OneToOne
    @JoinColumn(name = "user_id")
    private User user;
}

 

 

고객

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

 

 

  • 양방향 관계

만약 양방향 관계에서 외래 키의 주인을 지정해주려고 한다면, mappedBy 옵션을 사용한다.

 

해당 부분을 공부하면서 많이 헷갈렸는데 간단하게 이야기하자면 외래키의 주인일 때는 @JoinColumn()을 이용하여 외래 키의 속성을 설정하고, 이를 참조하는 엔티티는 mappedBy 옵션을 활용하여 어디를 참조하는지 알려주는 형식이다. 

 

 

음식

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @OneToOne
    @JoinColumn(name = "user_id")
    private User user;
}

 

고객

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToOne(mappedBy = "user")
    private Food food;
}

 

 

 

 

 

1 대 N, N대 1 관계

각 엔티티끼리의 관계가 1대 N관계 일때는 @OnetoMany와 @ManytoOne 에너테이션을 이용하여 관계를 맺는다.  외래키 주인의 설정은 N쪽에 해둔다. 다음 예제는 양방향 설정일때의 엔티티 코드이다. 

 

음식

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;
}

 

고객

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;

    @OneToMany(mappedBy = "user")
    private List<Food> foodList = new ArrayList<>();
}

 

 

 

 

 

 

N 대 N 관계

각 엔티티끼리의 관계가 N대 N관계 일때는 @ManytoMany 에너테이션을 이용하여 관계를 맺는다. N : M 관계를 풀어내기 위해서는 중간 테이블을 생성하여 처리한다.

 

음식

@Entity
@Table(name = "food")
public class Food {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @ManyToMany
    @JoinTable(name = "orders", // 중간 테이블 생성
    joinColumns = @JoinColumn(name = "food_id"), // 현재 위치인 Food Entity 에서 중간 테이블로 조인할 컬럼 설정
    inverseJoinColumns = @JoinColumn(name = "user_id")) // 반대 위치인 User Entity 에서 중간 테이블로 조인할 컬럼 설정
    private List<User> userList = new ArrayList<>();
}

 

고객

@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
}

 

하지만 생성되는 중간 테이블을 컨트롤하기 어렵기 때문에 주문이라는 엔티티를 직접 새로 만든뒤 1 : N, N : 1 관계로 다시 풀어 작성하는 것이 확장성에 용이하다. 

 

 

 

 

 

로딩

JPA에서는 연관관계가 설정된 엔티티의 정보를 바로 가져올지, 필요할 때 가져올지에 대해 정할 수 있는데 이를 Fetch Type이라고 하며 그 방법으로 2가지가 존재한다. 

  • Lazy (지연로딩) : 필요한 시점에 정보를 가져온다. 
  • Eager (즉시로딩) : 조회할 때 연관된 모든 엔티티의 정보를 즉시 가져온다. 

기본적으로 @OnetoMany 에너테이션은 Fetch Type이 Lazy로 설정되어 있고, 반대로 @ManytoOne에너테이션은 Eager로 설정되어 있다. 

 

'FrameWork > Spring' 카테고리의 다른 글

RestTemplate  (0) 2024.06.03
ComponentScan  (0) 2024.05.30
싱글톤 패턴과 컨테이너  (0) 2024.05.28
컨테이너에 빈 등록 및 조회  (0) 2024.05.27
IoC, DI 컨테이너  (0) 2024.05.27

'FrameWork/Spring'의 다른글

  • 현재글 연관관계

관련글