들어가며
<Spring 숙련> 강의를 수강 중이다. 오늘까지 완강하는 것이 목표다.
시간이 허락되면 <Spring 심화> 강의도 시작해야겠다.
코드카타

처음 접근할 땐 단순히 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.
'내일배움캠프 > 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 |