[내일배움캠프] 260409 TIL #4 엔티티 연관관계

2026. 4. 9. 16:54·내일배움캠프/TIL

들어가며

<Spring 숙련> 강의를 수강 중이다. 오늘까지 완강하는 것이 목표다.

시간이 허락되면 <Spring 심화> 강의도 시작해야겠다.

 

 

코드카타

프로그래머스 70128번 - 내적

 

처음 접근할 땐 단순히 for문을 사용해서 index를 하나씩 늘려가면서 a[index] * b[index] 를 반복하는 코드를 작성했다.

// 일부 발췌
for (int i = 0; i < a.length; i++) {
	answer += a[i] * b[i];
}

 

 

다른 풀이를 봤는데, IntStream을 사용해서 단 한 줄만으로 이 문제를 푼 사람이 있었다.

 

조금 더 자세한 풀이를 위해 아래 블로그에 따로 정리해두었다.

 

[프로그래머스] 70128번 - 내적 [Java]

프로그래머스SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프programmers.co.kr 문제 제출한 코드1. for문 사용class Solution { public int solution(int[] a, int[] b) { int answer

sxxlx.tistory.com

 

 

최종적으로 제출한 답

import java.util.stream.IntStream;

class Solution {
    public int solution(int[] a, int[] b) {
        return IntStream.range(0, a.length).map(index -> a[index] * b[index]).sum();
    }
}

 

 

Today I Learned!

오늘도 많은 강의들을 들었지만, 그 중 가장 핵심적이었던 주제는 "Entity 연관 관계" 이다.

JPA에서 다루는 Entity의 연관관계는 크게 4가지로 나눌 수 있다.

 

1. 1 대 1 관계

@OneToOne 애너테이션을 통해 각 엔티티간의 관계를 1 대 1로 설정할 수 있다.

예를 들어, Food라는 엔티티와 User라는 엔티티가 있다고 가정하고 1:1 단방향 관계로 매핑해주려면 아래와 같이 할 수 있다.

@Entity
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;
}

 

이때 @JoinColumn 애너테이션은 외래키의 주인이 활용하는 애너테이션으로, 1:1 관계에서는 외래키의 주인이 없기 때문에 직접 지정해야 한다. 외래키의 주인만이 이를 등록, 수정, 삭제할 수 있으며, 주인이 아닌 쪽은 외래키를 읽기만 가능하다.

위의 코드에서는 Food 엔티티가 외래키의 주인이다. 그렇다면 User 엔티티쪽에서도 등록, 수정, 삭제하고 싶다면 어떻게 해야 할까?

 

바로 양방향 관계로 설정해주면 이를 해결할 수 있다.

 

User 엔티티에도 @OneToOne 애너테이션으로 Food로의 관계를 맺어준 후 mappedBy 옵션으로 외래키의 주인을 지정해주면 된다.

@Entity
@Table(name = "users")
public class User {

	...

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

 

2. N 대 1 관계

@ManyToOne 애너테이션을 통해 각 엔티티간의 관계를 N 대 1로 설정할 수 있다.

예를 들어, 배달 서비스를 개발한다고 가정할 때, Food와 User의 관계를 1:1로 맺어버리면 한 고객은 음식을 하나만 시킬 수 있고 마찬가지로 해당 음식은 무조건 그 고객에 의해서만 주문되어야 한다. 하지만 현실에서는 한 고객이 여러 개의 음식을 시킬 수 있다. 그렇기 때문에 Food 엔티티에 @ManyToOne 을 통해 N:1 관계를 맺어주어야 한다.

@Entity
public class Food {

	...

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

 

위와 같이 Food에만 @ManyToOne 을 걸어주게 되면 Food에서 User로의 단방향으로만 등록, 수정, 삭제가 가능하다. 고객에서도 이를 관리하고 싶다면 마찬가지로 양방향 관계를 걸어주면 되는데, 이때 사용되는 애너테이션은 @OneToMany 이다.

@Entity
@Table(name = "users")
public class User {

	...

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

 

3. 1 대 N 관계

@OneToMany 애너테이션을 통해 각 엔티티간의 관계를 1 대 N으로 설정할 수 있다.

예를 들어, 한 음식은 여러 고객에 의해 시켜질 수 있다. 그렇기 때문에 이번에는 @OneToMany 를 통해 Food 엔티티와 User 엔티티의 관계를 1:N으로 설정해보자.

@Entity
public class Food {

	...

    @OneToMany
    @JoinColumn(name = "food_id") 
    private List<User> userList = new ArrayList<>();
}

 

위와 같이 외래키를 Food 엔티티가 직접 가지게 된다면 INSERT 발생 시 한번에 처리할 수 있다는 장점이 있지만, 실제 DB에서는 외래키를 고객 테이블이 가지고 있기 때문에 추가적인 UPDATE 가 발생된다는 단점이 존재한다.

 

그럼 이걸 해결하기 위해서 양방향으로 매핑하면 되려나..?

 

그렇지 않다. 1:N 관계에서는 양방향 관계가 존재하지 않기 때문이다.

양방향 매핑을 하게 되면 User 엔티티에서 @ManyToOne 애너테이션을 통해 Food 엔티티로 매핑해야 하는데, 해당 애너테이션은 mappedBy 옵션을 제공하지 않는다.

물론, @JoinColumn 의 insertable과 updatable 옵션을 false로 설정하여 양쪽으로 JOIN 설정을 하면 양방향처럼 설정할 수는 있다.

 

4. N 대 M 관계

@ManyToMany 애너테이션을 통해 각 엔티티간의 관계를 N 대 M 으로 설정할 수 있다.

예를 들어, A라는 고객이 치킨과 피자를 주문한다고 가정하자. B라는 고객은 치킨만 주문했다고 가정하자.

A라는 고객 입장에서 봤을 땐 User 엔티티와 Food 엔티티가 1:N으로 매핑되어 있으면 이 주문은 가능한 주문이다. 하지만 치킨의 입장에서 봤을 땐 A와 B 고객 둘 다 주문하고 있으므로 User 엔티티와 Food 엔티티가 N:1 관계가 되어야 한다.

즉, User 엔티티도 여러 개의 음식을 가질 수 있고, Food 엔티티도 여러 명의 고객을 가질 수 있다. 이때 N:M 관계로 엔티티를 매핑함으로써 이를 해결할 수 있다.

 

하지만 실제 JPA 환경에서는 N:M 관계를 풀어내기 위해 "중간 테이블"을 생성하게 된다. 

@Entity
public class Food {

	...
    
    @ManyToMany
    @JoinTable(name = "orders", // 중간 테이블 생성
    joinColumns = @JoinColumn(name = "food_id"), 
    inverseJoinColumns = @JoinColumn(name = "user_id"))
    private List<User> userList = new ArrayList<>();
}

 

양방향 매핑을 해주려면 User 엔티티 쪽에도 @ManyToMany 로 매핑시켜줘야 한다.

@Entity
@Table(name = "users")
public class User {

	...

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

 

하지만 이처럼 자동으로 생성되는 중간 테이블을 우리가 직접 관리하기 어렵기 때문에 Order 라는 엔티티를 새로 만들어서 중간 테이블의 역할을 해주는 것처럼 설정해주는 것이 좋다.

@Entity
@Table(name = "orders")
public class Order {

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

    @ManyToOne
    @JoinColumn(name = "food_id")
    private Food food;

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

 

 

 

마무리

프로젝트를 진행할 때에도 각 테이블마다 어떻게 관계를 풀어나가야 할지 고민했었다. 특히, 단방향 매핑을 주로 하되, 특정 상황에서는 어쩔 수 없이 양방향 매핑을 해야 하는 경우에는 어떻게 이를 풀어나가야 할지 고민이 많았다. 양방향 매핑으로 인해 야기될 수 있는 오류나 상황들이 많기 때문이다. 앞으로도 겪게 되는 고민들이겠지만, 점점 문제를 해결하는 능력이 향상되고 있다고 생각한다.

 

 

ref.

https://data04190.tistory.com/59

'내일배움캠프 > TIL' 카테고리의 다른 글

[내일배움캠프] 260413 TIL #6 MSA  (0) 2026.04.13
[내일배움캠프] 260410 TIL #5  (0) 2026.04.10
[내일배움캠프] 260408 TIL #3 스프링 시큐리티  (0) 2026.04.08
[내일배움캠프] 260407 TIL #2  (0) 2026.04.07
[내일배움캠프] 260406 TIL #1 오랜만에 스프링  (0) 2026.04.06
'내일배움캠프/TIL' 카테고리의 다른 글
  • [내일배움캠프] 260413 TIL #6 MSA
  • [내일배움캠프] 260410 TIL #5
  • [내일배움캠프] 260408 TIL #3 스프링 시큐리티
  • [내일배움캠프] 260407 TIL #2
이서라다
이서라다
  • 이서라다
    개발일지
    이서라다
  • 전체
    오늘
    어제
    • 전체 보기 (79)
      • 내일배움캠프 (21)
        • TIL (21)
      • 프로그래머스 (23)
      • Algorithm (2)
      • BackEnd (0)
        • Spring (0)
      • Language (4)
        • JAVA (4)
      • Git (2)
      • 백준 - Java (25)
        • 입출력과 사칙연산 (6)
        • 반복문 (8)
        • 1차원 배열 (1)
        • 문자열 (7)
        • 2차원 배열 (1)
        • 조합론 (1)
        • 정렬 (1)
      • IDE (1)
        • IntelliJ (1)
      • 티스토리 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    til
    jdk삭제
    티스토리스킨
    내일배움캠프
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
이서라다
[내일배움캠프] 260409 TIL #4 엔티티 연관관계
상단으로

티스토리툴바