๐ORM(Object Realational Mapping)
ORM์ ๊ฐ์ฒด ๊ด๊ณ ๋งคํ์ ์๋ฏธํ๋ค. Java์ ๊ฐ์ ๊ฐ์ฒด์งํฅ ์ธ์ด์์์ ๊ฐ์ฒด์ RDB์ ํ
์ด๋ธ์ ์๋์ผ๋ก ๋งคํํ๋ ๋ฐฉ๋ฒ์ด๋ค.
ํด๋์ค๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ
์ด๋ธ๊ณผ ๋งคํํ๊ธฐ ์ํด ๋ง๋ค์ด์ง ๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ์ RDB์ ํ
์ด๋ธ๊ณผ ๋ถ์ผ์น๊ฐ ์กด์ฌํ ์๋ฐ์ ์๋ค. ORM์ด ์ด๋ฌํ ๋ถ์ผ์น๋ฅผ ํด๊ฒฐํ๋ ์ญํ ์ ํด์ค๋ค.
ORM์ SQL ์์ฑ์ด ์๋ Java ์ฝ๋(๋ฉ์๋)๋ก ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ ์ ์๋๋ก ๋์์ค๋ค.
ORM ๊ธฐ๋ฅ
1. ๊ฐ์ฒด-๊ด๊ณ ๋งคํ
- ORM์ ๊ฐ์ฒด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ ๊ฐ์ ๋งคํ์ ์๋์ผ๋ก ์ฒ๋ฆฌํ๋ค. ์ฆ, ํด๋์ค์ ํ๋์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ์ ์ปฌ๋ผ์ ๋งคํํ์ฌ ๊ฐ์ฒด๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๊ณ ๊ฒ์ํ ์ ์๋ค.
2. SQL ์์ฑ ๋ฐ ์คํ
- ORM์ ๊ฐ๋ฐ์๊ฐ ์ง์ SQL ์ฟผ๋ฆฌ๋ฅผ ์์ฑํ๋ ๊ฒ์ ๋์ ํ์ฌ ๊ฐ์ฒด๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์์
์ ์ํํ๋ค. ORM์ ๊ฐ๋ฐ์๊ฐ ๊ฐ์ฒด ์งํฅ์ ์ธ ๋ฐฉ์์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ์ ์๋๋ก SQL์ ์๋์ผ๋ก ์์ฑํ๊ณ ์คํํ๋ค.
3. ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์
๊ด๋ฆฌ
- ORM์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํธ๋์ญ์
์ ๊ด๋ฆฌํ์ฌ ๋ฐ์ดํฐ์ ์ผ๊ด์ฑ๊ณผ ๋ฌด๊ฒฐ์ฑ์ ์ ์งํ๋ค. ๊ฐ๋ฐ์๋ ๋ณต์กํ ํธ๋์ญ์
๊ด๋ฆฌ๋ฅผ ์ ๊ฒฝ ์ฐ์ง ์๊ณ ๋ ์์ ํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃฐ ์ ์๋ค.
4. ์ฑ๋ฅ ์ต์ ํ
- ORM์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ํต์ ์ ์ต์ ํํ์ฌ ์ฑ๋ฅ์ ํฅ์์ํจ๋ค. ๋ฐ์ดํฐ๋ฅผ ๋ก๋ฉํ๋ ๋ฐฉ์์ด๋ ์ฟผ๋ฆฌ์ ์คํ ๊ณํ์ ์ต์ ํํ์ฌ ๋น ๋ฅธ ๋ฐ์ดํฐ ์ก์ธ์ค๋ฅผ ์ ๊ณตํ๋ค.
ORM ์ฅ์
1. ๊ฐ๋ฐ ์์ฐ์ฑ ํฅ์
- ORM์ ์ฌ์ฉํ๋ฉด SQL ์ฟผ๋ฆฌ๋ฅผ ์ง์ ์์ฑํ๋ ๋ฒ๊ฑฐ๋ก์์ ์ค์ผ ์ ์์ผ๋ฉฐ, ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด์ ํน์ง์ ํ์ฉํ์ฌ ๊ฐ๋ฐ์ ๋น ๋ฅด๊ฒ ์งํํ ์ ์๋ค.
2. ์ ์ง๋ณด์์ฑ ํฅ์
- ORM์ ์ฌ์ฉํ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์คํค๋ง์ ๋ณ๊ฒฝ์ ๋ํ ์ํฅ์ ์ต์ํํ ์ ์์ผ๋ฉฐ, ์ฝ๋์ ์ฌ์ฌ์ฉ์ฑ๊ณผ ์ ์ง๋ณด์์ฑ์ ๋์ผ ์ ์๋ค.
3. ํ๋ซํผ ๋
๋ฆฝ์ฑ
- ORM์ ๋ค์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ํ ์ง์์ ์ ๊ณตํ๋ฏ๋ก, ์ ํ๋ฆฌ์ผ์ด์
์ ํ๋ซํผ์ ๋ณ๊ฒฝํ๊ฑฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ต์ฒดํ ๋ ์ ์ฐ์ฑ์ ์ ๊ณตํ๋ค.
4. ๋ณด์ ๊ฐํ
- ORM์ ์ฌ์ฉํ๋ฉด SQL Injection๊ณผ ๊ฐ์ ๋ณด์ ์ทจ์ฝ์ ์ ๋ฐฉ์งํ ์ ์์ผ๋ฉฐ, ORM์ด ์ ๊ณตํ๋ ๋ณด์ ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ณด์์ ๊ฐํํ ์ ์๋ค.
๐JPA(Java Persistence API)
JPA๋ ์๋ฐ ORM ๊ธฐ์ ์ ๋ํ API ํ์ค ๋ช
์ธ๋ฅผ ์๋ฏธํฉ๋๋ค.
JPA๋ ORM์ ์ฌ์ฉํ๊ธฐ ์ํ ์ธํฐํ์ด์ค๋ฅผ ๋ชจ์๋ ๊ฒ์ด๋ฉฐ, JPA๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ JPA๋ฅผ ๊ตฌํํ Hibernate, EclipseLink, DataNucleus ๊ฐ์ ORM ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด์ผ ํฉ๋๋ค.
"์ธํฐํ์ด์ค"์ด๊ธฐ ๋๋ฌธ์ JPA๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ JPA๋ฅผ ๊ตฌํํ Hibernate, EclipseLink, DataNucleus์ ๊ฐ์ ORM ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.

JPA์ ์ฅ์
- ์์ฐ์ฑ์ด ๋ฐ์ด๋๊ณ ์ ์ง๋ณด์๊ฐ ์ฉ์ดํ๋ค. ๊ฐ์ฒด ์ค์ฌ ์ค๊ณ์ ๋ ์ง์คํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
- DBMS์ ๋ํ ์ข
์์ฑ์ด ์ค์ด๋ ๋ค.
โ DB์ฟผ๋ฆฌ๋ฌธ์ ์ฝ๋๋จ์์ ํด๊ฒฐ์ด ๊ฐ๋ฅํ๋ค. DBMS์์ DB๋ง ์์ฑํ๊ณ , ํ
์ด๋ธ ์์ฑ&๊ด๋ฆฌ๋ฑ ๋ง์ ๋ถ๋ถ๋ค์ ์ฝ๋๋จ์์ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
JPA์ ๋จ์
- JPA๋ฅผ ํ์ตํ๋ ค๋ฉด ๋ง์ ๋
ธ๋ ฅ์ด ๋ ๋ค.
- ๋ณต์กํ ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ๋ถ๋ฆฌํ๋ค.
โ ํ๋์ ํ
์ด๋ธ์์๋ ์ด ์ ๋ณด, ๋ค๋ฅธ ํ
์ด๋ธ์์๋ ์ด ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ ํ๋์ ๋ฐ์ดํฐ ๊ฐ์ฒด๋ก ๋ง๋ค๊ธฐ๊ฐ ์ด๋ ต๋ค. SQL๋ฌธ์์๋ joinํจ์๋ก ์ฟผ๋ฆฌ ํ ์ค์ด๋ฉด ๋๋๋ค.
- ์๋ชป ์ฌ์ฉํ๋ฉด ์ฑ๋ฅ์ด ๋จ์ด์ง ์๋ ์๋ค.
๐์์์ฑ ์ปจํ
์คํธ
JPA์์๋ ํ
์ด๋ธ๊ณผ ๋งคํ๋๋ ์ํฐํฐ ๊ฐ์ฒด ์ ๋ณด๋ฅผ ์์์ฑ ์ปจํ
์คํธ๋ฅผ ํตํด ์ ํ๋ฆฌ์ผ์ด์
๋ด์์ ์ค๋ ์ง์๋๋๋ก ๋ณด๊ดํ๋ค.
์์์ฑ ์ปจํ
์คํธ๋ JPA๋ฅผ ์ดํดํ๋๋ฐ ๊ฐ์ฅ ์ค์ํ ์ฉ์ด์ด๋ค.
- ์์์ฑ ์ปจํ
์คํธ๋ ๋
ผ๋ฆฌ์ ์ธ ๊ฐ๋
- ๋์ ๋ณด์ด์ง ์์
- ์ํฐํฐ ๋งค๋์ ๋ฅผ ํตํด ์์์ฑ ์ปจํ
์คํธ์ ์ ๊ทผ
์ํฐํฐ์ ์๋ช
์ฃผ๊ธฐ

- ๋น์์(new/transient) : ์์์ฑ ์ปจํ
์คํธ์ ์ ํ ๊ด๊ณ๊ฐ ์๋ ์๋ก์ด ์ํ
- ์์(managed) : ์์์ฑ ์ปจํ
์คํธ์ ๊ด๋ฆฌ๋๋ ์ํ
- ์ค์์(detached) : ์์์ฑ ์ปจํ
์คํธ์ ์ ์ฅ๋์๋ค๊ฐ ๋ถ๋ฆฌ๋ ์ํ
- ์ญ์ (remove) : ์ญ์ ๋ ์ํ
EntityManager์ ์ฃผ์ ์ญํ
- persist(): ์ํฐํฐ๋ฅผ ์์์ฑ ์ปจํ
์คํธ์ ์ ์ฅ
- find(): ์์์ฑ ์ปจํ
์คํธ ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ํฐํฐ ์กฐํ
- remove(): ์ํฐํฐ๋ฅผ ์์์ฑ ์ปจํ
์คํธ์์ ์ ๊ฑฐ
- merge(): ์ค์์ ์ํ์ ์ํฐํฐ๋ฅผ ๋ค์ ์์ ์ํ๋ก ๋ณ๊ฒฝ
- detach(): ์ํฐํฐ๋ฅผ ์ค์์ ์ํ๋ก ์ ํ
JPA์ ๋ฐ์ดํฐ ๋ณ๊ฒฝ ๊ฐ์ง
- ์์์ฑ ์ปจํ
์คํธ๋ ์ํฐํฐ ๊ฐ์ฒด์ ์ํ๋ฅผ ์ถ์ ํฉ๋๋ค.
- ํธ๋์ญ์
์ด ์ปค๋ฐ๋๋ฉด, JPA๋ ์์์ฑ ์ปจํ
์คํธ์์ ๋ณ๊ฒฝ๋ ์ํฐํฐ๋ฅผ ์ฐพ์ SQL์ ์์ฑํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋๊ธฐํํฉ๋๋ค.
Member member = em.find(Member.class, 1L);
member.setName("Alice");
em.getTransaction().commit();
์์์ฑ ์ปจํ
์คํธ๋ JPA์ ์ฑ๋ฅ ์ต์ ํ ๊ธฐ๋ฒ์ ๊ธฐ์ฌ
- 1์ฐจ ์บ์: ๋์ผ ํธ๋์ญ์
๋ด์์ ์กฐํ๋ ์ํฐํฐ๋ฅผ ์บ์ฑํด, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ ๋น์ฉ์ ์ค์.
- ์ฐ๊ธฐ ์ง์ฐ: ํธ๋์ญ์
์ปค๋ฐ ์์ ์ ํ ๋ฒ์ SQL ์คํ.
- ์ง์ฐ ๋ก๋ฉ (Lazy Loading): ์ค์ ๋ก ํ์ํ ์์ ์๋ง ๋ฐ์ดํฐ๋ฅผ ์กฐํ.
๐N+1 ๋ฌธ์ ๋?
์ฐ๊ด ๊ด๊ณ์์ ๋ฐ์ํ๋ ์ด์๋ก ์ฐ๊ด ๊ด๊ณ๊ฐ ์ค์ ๋ ์ํฐํฐ๋ฅผ ์กฐํํ ๊ฒฝ์ฐ์ ์กฐํ๋ ๋ฐ์ดํฐ ๊ฐฏ์(n) ๋งํผ ์ฐ๊ด๊ด๊ณ์ ์กฐํ ์ฟผ๋ฆฌ๊ฐ ์ถ๊ฐ๋ก ๋ฐ์ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๊ฒ ๋๋ค. ์ฆ, 1๋ฒ์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ ธ์ ๋ ์๋ํ์ง ์์ N๋ฒ์ ์ฟผ๋ฆฌ๊ฐ ์ถ๊ฐ์ ์ผ๋ก ์คํ๋๋ ๊ฒ์ด๋ค. ์ด๋ฅผ N+1 ๋ฌธ์ ๋ผ๊ณ ํ๋ค.
When ์ธ์ ๋ฐ์ํ๋๊ฐ?
- JPA Repository๋ฅผ ํ์ฉํด ์ธํฐํ์ด์ค ๋ฉ์๋๋ฅผ ํธ์ถํ ๋(Read ์)
Who ๋๊ฐ ๋ฐ์์ํค๋๊ฐ?
- 1:N ๋๋ N:1 ๊ด๊ณ๋ฅผ ๊ฐ์ง ์ํฐํฐ๋ฅผ ์กฐํํ ๋ ๋ฐ์
How ์ด๋ค ์ํฉ์ ๋ฐ์๋๋๊ฐ?
- JPA Fetch ์ ๋ต์ด EAGER ์ ๋ต์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ๊ฒฝ์ฐ
- JPA Fetch ์ ๋ต์ด LAZY ์ ๋ต์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์จ ์ดํ์ ์ฐ๊ด ๊ด๊ณ์ธ ํ์ ์ํฐํฐ๋ฅผ ๋ค์ ์กฐํํ๋ ๊ฒฝ์ฐ
Why ์ ๋ฐ์ํ๋๊ฐ?
- JPA Repository๋ก find ์ ์คํํ๋ ์ฒซ ์ฟผ๋ฆฌ์์ ํ์ ์ํฐํฐ๊น์ง ํ ๋ฒ์ ๊ฐ์ ธ์ค์ง ์๊ณ , ํ์ ์ํฐํฐ๋ฅผ ์ฌ์ฉํ ๋ ์ถ๊ฐ๋ก ์กฐํํ๊ธฐ ๋๋ฌธ์.
- JPQL์ ๊ธฐ๋ณธ์ ์ผ๋ก ๊ธ๋ก๋ฒ Fetch ์ ๋ต์ ๋ฌด์ํ๊ณ JPQL๋ง ๊ฐ์ง๊ณ SQL์ ์์ฑํ๊ธฐ ๋๋ฌธ์.
EAGER(์ฆ์ ๋ก๋ฉ)์ธ ๊ฒฝ์ฐ
- JPQL์์ ๋ง๋ SQL์ ํตํด ๋ฐ์ดํฐ๋ฅผ ์กฐํ
- ์ดํ JPA์์ Fetch ์ ๋ต์ ๊ฐ์ง๊ณ ํด๋น ๋ฐ์ดํฐ์ ์ฐ๊ด ๊ด๊ณ์ธ ํ์ ์ํฐํฐ๋ค์ ์ถ๊ฐ ์กฐํ
- 2๋ฒ ๊ณผ์ ์ผ๋ก N + 1 ๋ฌธ์ ๋ฐ์
User(์ฌ์ฉ์)์ Order(์ฃผ๋ฌธ)์ ํ์ฌ ์ผ๋๋ค ๊ด๊ณ๋ก ์ฐ๊ด๊ด๊ณ๊ฐ ์กด์ฌํ๋ค. User ์ํฐํฐ๋ฅผ findAll()๋ฅผ ์ด์ฉํด ๋ชจ๋ ์ฌ์ฉ์๋ค์ ์กฐํํ๋ ค๊ณ ํ ๋, ์๋๋ ์ฌ์ฉ์๋ค์ ๊ดํ ๋ด์ฉ๋ง ์กฐํ๋์ด์ผ ํ๋๋ฐ User์ ์ฐ๊ด๊ด๊ณ ์ํฐํฐ๋ ํจ๊ป ์กฐํ๋๊ธฐ ๋๋ฌธ์ ๊ฐ ์ฌ์ฉ์๋ง๋ค ์ฐ๊ด๋ Order ์ํฐํฐ๋ ์กฐํ๊ฐ ํจ๊ป ๋๋ ๊ฒ์ด๋ค.
์ฆ, ์ฌ์ฉ์๊ฐ 5๋ช
์ผ๋, ์ฌ์ฉ์ ์กฐํ์ ๋ํ ๋ด์ฉ(1) + ๊ฐ 5๋ช
์ ์ฌ์ฉ์๊ฐ ๊ฐ์ง๊ณ ์๋ ์ฃผ๋ฌธ Entity์ ๋ํ ๋ด์ฉ(5)์ผ๋ก 1+5 ๋ก ์กฐํ๊ฐ ๋์ด 1+N์ด ๋ฐ์ํ๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์, ์ฐ๊ด๊ด๊ณ๊น์ง ๋ฐ์ดํฐ๋ฅผ ๋ชจ๋ ์กฐํํ๋ ์ฆ์๋ก๋ฉ์ผ ๊ฒฝ์ฐ N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๋ค.
- findAll()์ ํ ์๊ฐ select u from User u์ด๋ผ๋ JPQL ๊ตฌ๋ฌธ์ด ์์ฑ๋๊ณ ํด๋น ๊ตฌ๋ฌธ์ ๋ถ์ํ select * from user ์ด๋ผ๋ SQL์ด ์์ฑ๋์ด ์คํ๋๋ค.
- DB์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ User ์ํฐํฐ์ ์ธ์คํด์ค๋ค์ ์์ฑํ๋ค.
- User์ ์ฐ๊ด๋์ด ์๋ Order ๋ ๋ก๋ฉ์ ํด์ผ ํ๋ค.
- ์์์ฑ ์ปจํ
์คํธ์์ ์ฐ๊ด๋ User๊ฐ ์๋์ง ํ์ธํ๋ค.
- ์์์ฑ ์ปจํ
์คํธ์ ์๋ค๋ฉด 2์์ ๋ง๋ค์ด์ง User ์ธ์คํด์ค๋ค ๊ฐ์์ ๋ง๊ฒ select * from order where User_id = ? ์ด๋ผ๋ SQL ๊ตฌ๋ฌธ์ด ์์ฑ๋๋ค. ( N+1 ๋ฐ์ )
LAZY(์ง์ฐ ๋ก๋ฉ)์ธ ๊ฒฝ์ฐ
- JPQL์์ ๋ง๋ SQL์ ํตํด ๋ฐ์ดํฐ๋ฅผ ์กฐํ
- JPA์์ Fetch ์ ๋ต์ ๊ฐ์ง์ง๋ง, ์ง์ฐ ๋ก๋ฉ์ด๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ ์กฐํ๋ ํ์ง ์์
- ํ์ง๋ง, ํ์ ์ํฐํฐ๋ฅผ ๊ฐ์ง๊ณ ์์
ํ๊ฒ ๋๋ฉด ์ถ๊ฐ ์กฐํ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๊ฒฐ๊ตญ N + 1 ๋ฌธ์ ๋ฐ์
ํ์ํ ๋๋ง ์ฐ๊ด๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์ ๋จ์ํ User ์ํฐํฐ๋ฅผ ์กฐํํ ๋๋ N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์์ง๋ง, ํ์ ์ํฐํฐ์ธ Order๋ฅผ ์กฐํํ๋ ๊ฒฝ์ฐ, Order์ํฐํฐ๋ ํ๋ก์ ๊ฐ์ฒด์ด๊ธฐ ๋๋ฌธ์ User๋ฅผ ์กฐํํ๊ณ ๋์ Order๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๊ธฐ ๋๋ฌธ์ ์ฆ์๋ก๋ฉ๊ณผ ๊ฐ์ด N+1๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
- findAll()์ ํ ์๊ฐselect u from User u ์ด๋ผ๋ JPQL ๊ตฌ๋ฌธ์ด ์์ฑ๋๊ณ ํด๋น ๊ตฌ๋ฌธ์ ๋ถ์ํ select * from user ์ด๋ผ๋ SQL์ด ์์ฑ๋์ด ์คํ๋๋ค.
- DB์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์ User ์ํฐํฐ์ ์ธ์คํด์ค๋ค์ ์์ฑํ๋ค.
- ์ฝ๋ ์ค์์ User ์ Order ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ๋ ์์ ์ ์์์ฑ ์ปจํ
์คํธ์์ ์ฐ๊ด๋ Order๊ฐ ์๋์ง ํ์ธํ๋ค
- ์์์ฑ ์ปจํ
์คํธ์ ์๋ค๋ฉด 2์์ ๋ง๋ค์ด์ง User ์ธ์คํด์ค๋ค ๊ฐ์์ ๋ง๊ฒ select * from order where User_id = ? ์ด๋ผ๋ SQL ๊ตฌ๋ฌธ์ด ์์ฑ๋๋ค. ( N+1 ๋ฐ์ )
๐N+1 ํด๊ฒฐ ๋ฐฉ๋ฒ
1. Fetch join
N+1 ์์ฒด๊ฐ ๋ฐ์ํ๋ ์ด์ ๋ ํ์ชฝ ํ
์ด๋ธ๋ง ์กฐํํ๊ณ ์ฐ๊ฒฐ๋ ๋ค๋ฅธ ํ
์ด๋ธ์ ๋ฐ๋ก ์กฐํํ๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฏธ๋ฆฌ ๋ ํ
์ด๋ธ์ JOIN ํ์ฌ ํ ๋ฒ์ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค๋ฉด ์ ์ด์ N+1 ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์์ ๊ฒ์ด๋ค.
ex) select * from owner left join cat on cat.owner_id = owner.id
๊ทธ๋ ๊ฒ ๋์จ ํด๊ฒฐ ๋ฐฉ๋ฒ์ด FetchJoin ๋ฐฉ๋ฒ์ด๋ค. ํ์ง๋ง ์ด๋ jpaRepository์์ ์ ๊ณตํด์ฃผ๋ ๊ฒ์ ์๋๊ณ JPQL๋ก ์์ฑํด์ผ ํ๋ค.
@Query("select o from Owner o join fetch o.cats")
List<Owner> findAllJoinFetch();

๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ฟผ๋ฆฌ๊ฐ 1๋ฒ๋ง ๋ฐ์ํ๊ณ ๋ฏธ๋ฆฌ owner์ pet ๋ฐ์ดํฐ๋ฅผ ์กฐ์ธ(Inner Join)ํด์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
Fetch Join(ํจ์น ์กฐ์ธ)์ ๋จ์
- ์ฐ๊ด๊ด๊ณ ์ค์ ํด๋์ FetchType์ ์ฌ์ฉํ ์ ์๋ค. Fetch Join์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ๋ฐ์ดํฐ ํธ์ถ ์์ ์ ๋ชจ๋ ์ฐ๊ด ๊ด๊ณ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ๋๋ฌธ์ FetchType์ Lazy๋ก ํด๋๋๊ฒ์ด ๋ฌด์๋ฏธํ๋ค.
- ํ์ด์ง ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ํ๋์ ์ฟผ๋ฆฌ๋ฌธ์ผ๋ก ๊ฐ์ ธ์ค๋ค ๋ณด๋ ํ์ด์ง ๋จ์๋ก ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋๊ฒ์ด ๋ถ๊ฐ๋ฅํ๋ค.
2. @Entity Graph
@EntityGraph ์ attributePaths์ ์ฟผ๋ฆฌ ์ํ์ ๋ฐ๋ก ๊ฐ์ ธ์ฌ ํ๋๋ช
์ ์ง์ ํ๋ฉด Lazy๊ฐ ์๋ Eager ์กฐํ๋ก ๊ฐ์ ธ์ค๊ฒ ๋๋ค. Fetch join๊ณผ ๋์ผํ๊ฒ JPQL์ ์ฌ์ฉํ์ฌ query ๋ฌธ์ ์์ฑํ๊ณ ํ์ํ ์ฐ๊ด๊ด๊ณ๋ฅผ EntityGraph์ ์ค์ ํ๋ฉด ๋๋ค. ๊ทธ๋ฆฌ๊ณ Fetch join๊ณผ๋ ๋ค๋ฅด๊ฒ join ๋ฌธ์ด outer join์ผ๋ก ์คํ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
@EntityGraph(attributePaths = "cats")
@Query("select o from Owner o")
List<Owner> findAllEntityGraph();

๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด ์ฟผ๋ฆฌ๊ฐ 1๋ฒ๋ง ๋ฐ์ํ๊ณ ๋ฏธ๋ฆฌ owner์ pet ๋ฐ์ดํฐ๋ฅผ ์กฐ์ธ(outerJoin)ํด์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
3. Fetch Join๊ณผ EntityGraph ์ฌ์ฉ์ ์ฃผ์ํ ์
Fetch Join๊ณผ EntityGraph๋ JPQL์ ์ฌ์ฉํ์ฌ JOIN๋ฌธ์ ํธ์ถํ๋ค๋ ๊ณตํต์ ์ด ์๋ค. ๋ํ, ๊ณตํต์ ์ผ๋ก ์นดํ
์์ ๊ณฑ(Cartesian Product)์ด ๋ฐ์ํ์ฌ Owner์ ์๋งํผ Cat์ด ์ค๋ณต ๋ฐ์ดํฐ๊ฐ ์กด์ฌํ ์ ์๋ค. ๊ทธ๋ฌ๋ฏ๋ก ์ค๋ณต๋ ๋ฐ์ดํฐ๊ฐ ์ปฌ๋ ์
์ ์กด์ฌํ์ง ์๋๋ก ์ฃผ์ํด์ผ ํ๋ค.
โป ์นดํ
์์ ๊ณฑ
๋ ํ
์ด๋ธ ์ฌ์ด์ ์ ํจ join ์กฐ๊ฑด์ ์ ์ง ์์์ ๋ ํด๋น ํ
์ด๋ธ์ ๋ํ ๋ชจ๋ ๋ฐ์ดํฐ๋ฅผ ์ ๋ถ ๊ฒฐํฉํ์ฌ ํ
์ด๋ธ์ ์กด์ฌํ๋ ํ ๊ฐฏ์๋ฅผ ๊ณฑํ๋งํผ์ ๊ฒฐ๊ณผ ๊ฐ์ด ๋ฐํ๋๋ ๊ฒ
์ถ์ฒ
https://velog.io/@tmdwns1521/DAO%EC%99%80-ORM-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0
https://velog.io/@jeong-god/ORM%EA%B3%BC-JPA%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C
https://victorydntmd.tistory.com/195
https://ittrue.tistory.com/254
https://s-y-130.tistory.com/184
https://jh2021.tistory.com/21
https://velog.io/@pdy000726/fetch-join-vs-EntityGraph