[Architecture] ์ผ๊ธฐ × ์นดํ…Œ๊ณ ๋ฆฌ N:M ๊ด€๊ณ„ ์„ค๊ณ„ (Enum vs DB, ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”, JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘๊นŒ์ง€)

2026. 3. 18. 22:41ยทDev Log โœ๏ธ/์šฐ์‚ฌ๊ธฐ ๊ฐœ๋ฐœ์ผ์ง€ ๐Ÿฐ

 

 

์ผ๊ธฐ ๋„๋ฉ”์ธ์— 'ํ™œ๋™ ์นดํ…Œ๊ณ ๋ฆฌ'  ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ฉด์„œ, ํ…Œ์ด๋ธ” ์„ค๊ณ„๋ถ€ํ„ฐ JPA ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘๊นŒ์ง€ ์ „์ฒด ๊ณผ์ •์„ ๊ธฐ๋กํ•ด ๋ณด๋ ค๊ณ  ํ•œ๋‹ค.

์ฒ˜์Œ์—๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ Enum์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋ ค ํ–ˆ๋Š”๋ฐ, ๊ณ ๋ฏผ์„ ๊ฑฐ๋“ญํ• ์ˆ˜๋ก ๊ตฌ์กฐ๊ฐ€ ์ ์  ์ปค์กŒ๋‹ค ...

 

 

๐Ÿšจ ๊ณ ๋ฏผ ๋ฐฐ๊ฒฝ

์ผ๊ธฐ์— 'ํ™œ๋™ ์นดํ…Œ๊ณ ๋ฆฌ'๋ฅผ ๋งคํ•‘ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ธฐํšํ–ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด ํ•˜๋‚˜์˜ ์ผ๊ธฐ์— "๋ฐ์ดํŠธ", "์—…๋ฌด", "์•ฝ์†" ๊ฐ™์€ ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ๋ถ™์ผ ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค.

 

1. ์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ•  ๊ฒƒ์ธ๊ฐ€?

2. ์ผ๊ธฐ์™€ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๊ด€๊ณ„๋ฅผ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•  ๊ฒƒ์ธ๊ฐ€?

3. JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์„ ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

 

โžก๏ธ ํ•˜๋‚˜ํ•˜๋‚˜ ํ’€์–ด๋ณด๋‹ˆ ์ƒ๊ฐ๋ณด๋‹ค ๊ณ ๋ คํ•  ๊ฒŒ ๋งŽ์•˜๋‹ค.

 

 

 

 

๐Ÿค” ๊ณ ๋ฏผํ–ˆ๋˜ ์„ ํƒ์ง€

 

1. ์นดํ…Œ๊ณ ๋ฆฌ ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ ๋ฐฉ๋ฒ• : Enum vs DB ํ…Œ์ด๋ธ”

A. Enum์œผ๋กœ ๊ด€๋ฆฌ

enum class ActivityCategory {
    FAMILY_EVENT, DATE, WORK, FRIENDS_MEETING, ALONE_TIME
}

 

์ƒ์ˆ˜๋กœ ๊ด€๋ฆฌํ•  ๊ฒฝ์šฐ ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ์ด ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ถ”ํ›„ ์œ ์ €๋ณ„ ์ปค์Šคํ…€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ๊ธฐ์กด ๋กœ์ง ์ˆ˜์ •์ด ๋งŽ์ด ๋ฐœ์ƒํ•œ๋‹ค

 

 

B. DB ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌ

์œ ์ €๋ณ„ ์ปค์Šคํ…€ ์นดํ…Œ๊ณ ๋ฆฌ ํ™•์žฅ์ด ์ž์œ ๋กญ์ง€๋งŒ, ํ…Œ์ด๋ธ” ์„ค๊ณ„๊ฐ€ ๋ณต์žกํ•ด์ง„๋‹ค๋Š” ๋‹จ์ ์ด ๋ฐœ์ƒํ•œ๋‹ค.

 

 

2. ๊ด€๊ณ„ ์„ค์ •: 1:N vs M:N

์ฒ˜์Œ์—๋Š” '์ผ๊ธฐ ํ•˜๋‚˜์— ์นดํ…Œ๊ณ ๋ฆฌ ํ•˜๋‚˜'๋ผ๊ณ  ๊ธฐํš์„ ํ–ˆ์—ˆ๋Š”๋ฐ,

์ƒ๊ฐํ•ด๋ณด๋‹ˆ ํ•˜๋ฃจ์— ์—ฌ๋Ÿฌ ํ™œ๋™๋“ค์„ ํ•  ๊ฒƒ์„ ๊ณ ๋ คํ•ด์„œ 'ํ•˜๋‚˜์˜ ์ผ๊ธฐ์— ์—ฌ๋Ÿฌ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ๋งคํ•‘'๋˜๋Š” ๊ฒƒ์œผ๋กœ  ๋ณ€๊ฒฝํ–ˆ๋‹ค.

 

์ผ๊ธฐ 1๊ฐœ → ์นดํ…Œ๊ณ ๋ฆฌ N๊ฐœ
์นดํ…Œ๊ณ ๋ฆฌ 1๊ฐœ → ์ผ๊ธฐ N๊ฐœ

 

โžก๏ธ `M:N(๋‹ค๋Œ€๋‹ค)` ๊ด€๊ณ„์—๋Š” ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”์ด ํ•„์š”ํ•˜๋ฏ€๋กœ, DiaryActivityCategory ํ…Œ์ด๋ธ”์„ ๋„์ž…ํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

 

 

๐Ÿ›  ์ตœ์ข… ํ…Œ์ด๋ธ” ์„ค๊ณ„

 

ํ™œ๋™ ์นดํ…Œ๊ณ ๋ฆฌ ํ…Œ์ด๋ธ”

ActivityCategory
โ”œโ”€โ”€ id (PK)
โ”œโ”€โ”€ name (์นดํ…Œ๊ณ ๋ฆฌ ์ด๋ฆ„)
โ”œโ”€โ”€ user_id (FK, nullable)

 

`user_id`๊ฐ€ null์ด๋ฉด ๊ธฐ๋ณธ ์นดํ…Œ๊ณ ๋ฆฌ null์ด ์•„๋‹ˆ๋ฉด ํ•ด๋‹น ์œ ์ €๊ฐ€ ์ถ”๊ฐ€ํ•œ ์ปค์Šคํ…€ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๊ตฌ๋ถ„ํ–ˆ๋‹ค.

MVP ๋‹จ๊ณ„์—์„œ๋Š” ๊ธฐ๋ณธ ์นดํ…Œ๊ณ ๋ฆฌ๋งŒ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ๋‚˜์ค‘์— ์ปค์Šคํ…€ ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋ผ๋„ ๊ตฌ์กฐ๋ฅผ ๋ฐ”๊ฟ€ ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

 

์ค‘๊ฐ„ ํ…Œ์ด๋ธ”

DiaryActivityCategory
โ”œโ”€โ”€ id (PK)
โ”œโ”€โ”€ diary_id (FK, NOT NULL)
โ”œโ”€โ”€ activity_category_id (FK, NOT NULL)
โ””โ”€โ”€ UNIQUE(diary_id, activity_category_id)  ← ๋ณตํ•ฉ ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด

 

โœ… ๋ณตํ•ฉ ์œ ๋‹ˆํฌ ์ œ์•ฝ์กฐ๊ฑด์„ ๊ฑธ์–ด์„œ, ๊ฐ™์€ ์ผ๊ธฐ์— ๊ฐ™์€ ์นดํ…Œ๊ณ ๋ฆฌ๊ฐ€ ์ค‘๋ณต ๋งคํ•‘๋˜๋Š” ๊ฒƒ์„ DB ๋ ˆ๋ฒจ์—์„œ ๋ฐฉ์ง€ํ–ˆ๋‹ค.

 

 

์ „์ฒด ๊ด€๊ณ„ ์š”์•ฝ

User ← ActivityCategory    (1:N ๋‹จ๋ฐฉํ–ฅ)
User ← Diary               (1:N ๋‹จ๋ฐฉํ–ฅ)
Diary ↔ DiaryActivityCategory ↔ ActivityCategory  (M:N, ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”)

 

 

 

๐Ÿ“š JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘

 

ActivityCategory → User

 

๋ฐฉํ–ฅ : ๋‹จ๋ฐฉํ–ฅ

FK ์œ„์น˜ : ActivityCategory์˜ user_id 

์ฃผ์ธ : ActivityCategory

๋งคํ•‘ : `@ManyToOne` + `@JoinColumn`

 

 

Diary → User

 

๋ฐฉํ–ฅ : ๋‹จ๋ฐฉํ–ฅ

FK ์œ„์น˜ : Diary์˜ user_id 

์ฃผ์ธ : Diary

๋งคํ•‘ : `@ManyToOne` + `@JoinColumn`

 

 

Diary ↔ DiaryActivityCategory

 

๋ฐฉํ–ฅ : ์–‘๋ฐฉํ–ฅ

FK :  DiaryActivityCategory์˜ diary_id 

์ฃผ์ธ : DiaryActivityCategory

๋งคํ•‘ : ์ฃผ์ธ์€ `@JoinColumn`, ๋ฐ˜๋Œ€๋Š” `mappedby`

 

 

 

 

ActivityCategory → DiaryActivityCategory

 

๋ฐฉํ–ฅ : ๋‹จ๋ฐฉํ–ฅ

FK : DiaryActivityCategory์˜ activity_category_id

์ฃผ์ธ : DiaryActivityCategory

๋งคํ•‘ : `@ManyToOne` + `@JoinColumn`

 

 

 

 

โžก๏ธ FK๋ฅผ ์‹ค์ œ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ชฝ์ด ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ(owning side)์ด๋‹ค.

 

 

 

 

๐Ÿ”‘ @JoinColumn์˜ ์˜๋ฏธ

๋‚ด๊ฐ€ ํ–ˆ๋˜ ์˜คํ•ด : `@JoinColumn(name = "...")` = ์ƒ๋Œ€ ํ…Œ์ด๋ธ”์˜ PK โŒ

์‹ค์ œ ์˜๋ฏธ: `@JoinColumn(name = "...")` = ๋‚ด ํ…Œ์ด๋ธ”์— ์žˆ๋Š” FK ์ปฌ๋Ÿผ์˜ ์ด๋ฆ„ โœ…

 

class DiaryActivityCategory(
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "diary_id", nullable = false) // โฌ…๏ธ DiaryActivityCategory ํ…Œ์ด๋ธ”์˜ diary_id ์ปฌ๋Ÿผ
    val diary: Diary,
 )

 

 

 

 

์–‘๋ฐฉํ–ฅ ๋งคํ•‘: ์ฃผ์ธ vs mappedBy

// DiaryActivityCategory (์ฃผ์ธ) - FK๋ฅผ ์ง์ ‘ ๊ด€๋ฆฌ
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "diary_id", nullable = false)
val diary: Diary,
// Diary (๋ฐ˜๋Œ€์ชฝ) — DiaryActivityCategory์˜ diary ํ•„๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ
@OneToMany(mappedBy = "diary", orphanRemoval = true, cascade = [CascadeType.ALL])
var diaryActivityCategories: MutableList<DiaryActivityCategory> = mutableListOf()
    protected set

 

โžก๏ธ `mappedBy = "diary"`๋Š” DiaryActivityCategory ์—”ํ‹ฐํ‹ฐ์˜ `diary` ํ•„๋“œ๋ช…์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์ปฌ๋Ÿผ๋ช…์ด ์•„๋‹ˆ๋‹ค!

์ €์ž‘์žํ‘œ์‹œ ๋น„์˜๋ฆฌ ๋ณ€๊ฒฝ๊ธˆ์ง€ (์ƒˆ์ฐฝ์—ด๋ฆผ)

'Dev Log โœ๏ธ > ์šฐ์‚ฌ๊ธฐ ๊ฐœ๋ฐœ์ผ์ง€ ๐Ÿฐ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

[Security] Nginx Basic Auth๋ฅผ ํ™œ์šฉํ•œ Swagger UI ์ ‘๊ทผ ์ œ์–ด ์„ค์ •  (0) 2026.01.28
[CI/CD] GitHub Actions์™€ jq๋ฅผ ํ™œ์šฉํ•œ ๋™์  ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ฃผ์ž…  (0) 2026.01.26
[Tech] OAuth 2.0 Playground๋กœ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๊ธฐ  (0) 2026.01.15
'Dev Log โœ๏ธ/์šฐ์‚ฌ๊ธฐ ๊ฐœ๋ฐœ์ผ์ง€ ๐Ÿฐ' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • [Security] Nginx Basic Auth๋ฅผ ํ™œ์šฉํ•œ Swagger UI ์ ‘๊ทผ ์ œ์–ด ์„ค์ •
  • [CI/CD] GitHub Actions์™€ jq๋ฅผ ํ™œ์šฉํ•œ ๋™์  ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ์ฃผ์ž…
  • [Tech] OAuth 2.0 Playground๋กœ ๊ตฌ๊ธ€ ์†Œ์…œ ๋กœ๊ทธ์ธ ํ…Œ์ŠคํŠธ ํ•ด๋ณด๊ธฐ
ํ•ด๋‹ˆ ๐ŸŒณ
ํ•ด๋‹ˆ ๐ŸŒณ
๐ŸŒฑ + โ˜€๏ธ = ๐ŸŒณ
  • ํ•ด๋‹ˆ ๐ŸŒณ
    haeni.dev
    ํ•ด๋‹ˆ ๐ŸŒณ
  • ๋งํฌ

    • github
    • velog
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (15)
      • Dev Log โœ๏ธ (6)
        • Tech (2)
        • ์šฐ์‚ฌ๊ธฐ ๊ฐœ๋ฐœ์ผ์ง€ ๐Ÿฐ (4)
      • Today I Learned ๐Ÿง (9)
        • Project (3)
        • Algorithm (0)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    backend
    ci/cd
    AWS
    JPA
    test
    ๊ฐœ๋ฐœ์ผ์ง€
    springboot
    ์ฝ”๋”ฉํ…Œ์ŠคํŠธ
    ์ฝ”ํ…Œ
    til
    Java
    kotlin
    IT
    postgresql
    ์•Œ๊ณ ๋ฆฌ์ฆ˜
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.5
ํ•ด๋‹ˆ ๐ŸŒณ
[Architecture] ์ผ๊ธฐ × ์นดํ…Œ๊ณ ๋ฆฌ N:M ๊ด€๊ณ„ ์„ค๊ณ„ (Enum vs DB, ์ค‘๊ฐ„ ํ…Œ์ด๋ธ”, JPA ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘๊นŒ์ง€)
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”