Published on

๐Ÿคฟ ์ˆจ ๊พน ์ฐธ๊ณ  ๋”ฅ๋‹ค์ด๋ธŒ 4 : ์ˆจ ๊พน์ฐธ๊ณ  ๋”ฅ๋‹ค์ด๋ธŒ - JPA ์›๋ฆฌํŽธ

Authors
  • avatar
    Name
    Woojin Son
    Twitter

์ˆจ ๊พน์ฐธ๊ณ  ๋”ฅ๋‹ค์ด๋ธŒ - JPA ์›๋ฆฌํŽธ

Intro

๋‹ค์‹œ ๋Œ์•„์™”์Šต๋‹ˆ๋‹ค. ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” JPA ์˜ ์›๋ฆฌ๋ฅผ ํ•œ๋ฒˆ ๋”ฅํ•˜๊ฒŒ ํŒŒ ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค JPA ์˜ ์›๋ฆฌ๋ฅผ ๋”ฅํ•˜๊ฒŒ ํŒ๋‹ค๋Š” ๋ง ์ž์ฒด๊ฐ€ ์กฐ๊ธˆ์€ ์ด์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. JPA ๊ทธ ์ž์ฒด๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๋ช…์„ธ์ผ ๋ฟ์ด๋‹ˆ๊นŒ์š”.

์—ฌ๊ธฐ์„œ ๋งํ•˜๋Š” ์›๋ฆฌ๋Š” Spring Data JPA ์˜ ๋™์ž‘ ์›๋ฆฌ, ์„ค๊ณ„ ์ฒ ํ•™์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋ผ๊ณ  ์ดํ•ดํ•ด์ฃผ์‹œ๋ฉด ๊ฐ์‚ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. 'Spring Data JPA ์™€ Hibernate ๊ตฌํ˜„์ฒด๊ฐ€ ์–ด๋–ป๊ฒŒ ๋งž ๋ฌผ๋ฆฌ๋Š”์ง€?' ๋ผ๋Š” ์ฃผ์ œ๋กœ ์ƒ๊ฐ ํ•ด ์ฃผ์‹œ๋ฉด ๋  ๊ฒƒ ๊ฐ™์•„์š”.

Spring ์— ์ž…๋ฌธํ•œ ์‹œ์ ์—์„œ ์ •๋ง ์ดํ•ด๊ฐ€ ์–ด๋ ต๊ณ  ์ ์‘์ด ์–ด๋ ค์› ๋˜ ๊ฒƒ ์ค‘ ํ•˜๋‚˜๊ฐ€ JpaRepository ์˜€์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ปจํŠธ๋กคํ•˜์ง€ ์•Š๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์˜์—ญ์œผ๋กœ CRUD ์ž‘์—…์ด ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒŒ ํŽธํ•˜๊ธด ํ•˜์ง€๋งŒ...๋ง‰์ƒ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋ฌธ์ œ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋ ค๋ฉด ๋™์ž‘ ์›๋ฆฌ๋ฅผ ์ž˜ ์•Œ์•„์•ผ ํ–ˆ์ฃ .

Spring ์œผ๋กœ ์•ฑ์„ ๊ฐœ๋ฐœํ•˜๊ณ  ์šด์˜ํ•˜๋Š” ๋‹จ๊ณ„์—์„œ๋Š” ๋”์ด์ƒ ์ž…๋ฌธ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ํŠนํžˆ ์›๋ฆฌ ์ดํ•ด๋„๊ฐ€ ์ค‘์š”ํ•ด์ง‘๋‹ˆ๋‹ค.

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” JPA ์—์„œ ์›๋ฆฌ๋ผ๊ณ  ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ๋“ค์€ ์ตœ๋Œ€ํ•œ ๋‹ค๋ค„๋ณด๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

โ˜• ์ปคํ”ผ ํ•œ์ž”๊ณผ ํ•จ๊ป˜ ์ฆ๊ฒจ์ฃผ์„ธ์š”. ์ด๋ฒˆ์—๋„ ๊นŠ๊ฒŒ ๋”ฅ๋‹ค์ด๋ธŒ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

JPA ์™€ Hibernate ์˜ ๊ด€๊ณ„ ๋‹ค์‹œ ๋ฆฌ๋งˆ์ธ๋“œ ํ•˜๊ธฐ

JPA (Java Persistence API) ๋Š” ORM (Object Relational Mapping) ์„ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ๋ช…์„ธ๊ณ , Hibernate ๋Š” JPA ๋ช…์„ธ๋ฅผ ๊ตฌํ˜„ํ•œ ๋Œ€ํ‘œ์ ์ธ ๊ตฌํ˜„์ฒด (Implementation) ์ž…๋‹ˆ๋‹ค.

Spring Data JPA ๋Š” Hibernate ๋ฅผ JPA ๋กœ ๊ฐ์‹ผ ์ถ”์ƒํ™” ๊ณ„์ธต + Repository ์ž๋™ ๊ตฌํ˜„ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.

Application
   โ†“
Spring Data JPA (Repository Layer)
   โ†“
JPA Interface (EntityManager, EntityTransaction ๋“ฑ)
   โ†“
Hibernate (์‹ค์ œ ๊ตฌํ˜„์ฒด)
   โ†“
JDBC Driver โ†’ Database

Spring Data JPA (Spring Boot Starter) ๋ฅผ ์…‹์—…ํ•˜๋ฉด ์œ„์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” Spring Data JPA ๋ฅผ ํ†ตํ•ด์„œ DB ์ปค๋„ฅ์…˜์„ ์…‹์—…ํ•˜๊ณ , ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ •์˜ํ•˜์ฃ .

ํ•˜์ง€๋งŒ ๋งŒ์•ฝ ์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ฐ™์ด ์—ฐ๋™ํ•ด์•ผํ•œ๋‹ค๋ฉด? JPA ์˜ EntityManager์™€ EntityTransaction ์„ ์…‹์—…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์กฐ๊ธˆ ๋” ๊นŠ๊ฒŒ ํŒŒ๊ณ ๋“ค์–ด์•ผ ํ•˜๋Š” ์‹œ์ ์ด ์˜ค๊ฒŒ ๋˜์ฃ .

์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € (EntityManager) - JPA ์˜ ์‹ฌ์žฅ

์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € (EntityManager) ๋Š” JPA ์˜ ํ•ต์‹ฌ ์ธํ„ฐํŽ˜์ด์Šค์ž…๋‹ˆ๋‹ค. ๋ชจ๋“  DB ์กฐ์ž‘์ด ์—ฌ๊ธฐ์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ ๋˜์ฃ .
Spring Boot ์—์„œ๋Š” @PersistenceContext ๋˜๋Š” EntityManagerFactory ๋ฅผ ํ†ตํ•ด ์ฃผ์ž…๋ฉ๋‹ˆ๋‹ค.

@Service
class MemberService(
    private val em: EntityManager
) {
    fun save(member: Member) {
        em.persist(member)
    }
}

์•„๋งˆ JpaRepository ๋ฅผ ๋ถˆ๋Ÿฌ์™€์„œ CRUD ๋ฅผ ํ•˜๋Š” ๊ฒŒ ๋Œ€๋ถ€๋ถ„ ์ต์ˆ™ํ•˜์‹ค๊ฒ๋‹ˆ๋‹ค. ์›๋ฆฌ๋ฅผ ์•„๋Š” ๊ฒŒ ๋ชฉ์ ์ด๋‹ˆ ์ด๋ฒˆ์—” ์ง์ ‘ EntityManager ๋ฅผ ๋ถˆ๋Ÿฌ ์™€ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

persist ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐ ์žˆ์–ด์„œ ๋„ค ๊ฐ€์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ๋™์ž‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

  • ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก (1์ฐจ ์บ์‹œ ์ €์žฅ)
  • ์Šค๋ƒ…์ƒท ์ƒ์„ฑ (๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ์œ„ํ•œ ์›๋ณธ ๋ณต์‚ฌ๋ณธ ์ €์žฅ)
  • ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— flush() ์‹คํ–‰
  • JDBC batch insert ์‹คํ–‰ ํ›„ DB ๋ฐ˜์˜

JPA ๋Š” ์ฆ‰์‹œ ๋ฐ์ดํ„ฐ๋ฅผ DB ์— ๋ฐ˜์˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. JDBC ๋กœ call ์„ ํ•˜๊ธฐ ์ „์— ๋ฐ์ดํ„ฐ๋ฅผ ๊ฒ€์ฆํ•˜๋Š” ๊ณผ์ •์„ ๊ฑฐ์น˜์ฃ . ์ด๋ฅผ ์“ฐ๊ธฐ ์ง€์—ฐ (Write-behind) ์ „๋žต์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

์™œ ์ด๋Ÿฐ ์ „๋žต์„ ์“ฐ๊ฒŒ ๋˜์—ˆ์„๊นŒ์š”? ์šฐ๋ฆฌ๊ฐ€ ํ•„์š” ํ•  ๋•Œ ๋งˆ๋‹ค JDBC ์— CRUD ๋ฅผ ๋ชจ๋‘ ํƒœ์šฐ๊ฒŒ ๋œ๋‹ค๋ฉด ํ•˜๋‚˜์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์—์„œ ์—ฐ์†์ ์œผ๋กœ DB ์„œ๋ฒ„์— Query ๊ฐ€ ์š”์ฒญ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” DB ์„œ๋ฒ„์— ๋ถ€ํ•˜๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์ฃ .

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ (Persistence Context)

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์—”ํ‹ฐํ‹ฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ€์ƒ์˜ 1์ฐจ ์บ์‹œ์ž…๋‹ˆ๋‹ค.

์—”ํ‹ฐํ‹ฐ์˜ ์ƒํƒœ๋Š” ์•„๋ž˜์˜ 4๊ฐ€์ง€ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์นฉ๋‹ˆ๋‹ค.

์ƒํƒœ์„ค๋ช…
๋น„์˜์† (Transient)new๋กœ ์ƒ์„ฑํ–ˆ์ง€๋งŒ ์•„์ง ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก๋˜์ง€ ์•Š์Œ
์˜์† (Persistent)em.persist()๋ฅผ ํ†ตํ•ด ๋“ฑ๋ก๋จ (1์ฐจ ์บ์‹œ์— ์ €์žฅ)
์ค€์˜์† (Detached)em.detach(), em.clear(), em.close()๋กœ ๋ถ„๋ฆฌ๋จ
์‚ญ์ œ (Removed)em.remove() ํ˜ธ์ถœ ์‹œ ์‚ญ์ œ ์˜ˆ์•ฝ ์ƒํƒœ

๋งŒ์•ฝ์— ํ•˜๋‚˜์˜ ์ •ํ•ด์ง„ ํŠธ๋žœ์žญ์…˜ ๋‚ด์—์„œ ์กฐํšŒ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ์ง„ํ–‰ํ•˜๋Š” ์ƒํ™ฉ์ด ์ƒ๊ธด๋‹ค๊ณ  ๊ฐ€์ • ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ 1์ฐจ ์บ์‹œ๊ฐ€ ์—†๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” DB ์— ๊ฐ™์€ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ๋ฅผ ์—ฌ๋Ÿฌ๋ฒˆ ๋ณด๋‚ด์•ผํ•˜๋Š” ์ƒํ™ฉ์— ๋†“์ž…๋‹ˆ๋‹ค.

์•ž์„œ ๋ง์”€๋“œ๋ ธ๋‹ค์‹œํ”ผ JPA ๋Š” ์“ฐ๊ธฐ ์ง€์—ฐ ์ „๋žต์„ ์ฑ„ํƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋Šฅํ•˜๋ฉด ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์ด ํ™•์‹คํžˆ ๋๋‚œ ์‹œ์ ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์—…๋ฐ์ดํŠธ ํ•˜๋Š” ๊ฒŒ ์ข‹๊ฒ ์ฃ .

๊ทธ๋ ‡๋‹ค๋ฉด ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ 1์ฐจ ์บ์‹œ์— ๋‘๋Š” ๊ฒŒ ์—ฌ๋Ÿฌ๋ชจ๋กœ ์œ ๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ์˜ ๋ณ€๊ฒฝ์ด ๊ฐ์ง€๋˜๋ฉด ๋”ํ‹ฐ ์ฒดํ‚น (Dirty Checking) ๊ธฐ๋Šฅ์ด ๋™์ž‘ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ flush() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ์‹œ์ ์— update SQL ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜์ฃ .

val member = em.find(Member::class.java, 1L)
member.name = "Woojin"
tx.commit() // flush() -> dirty checking -> update SQL ๋ฐœ์ƒ

๋”ํ‹ฐ ์ฒดํ‚น (Dirty Checking) ์— ๋Œ€ํ•ด์„œ๋Š” ์ถ”ํ›„ ์ข€ ๋” ์ž์„ธํžˆ ๋‹ค๋ค„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

flush - SQL ์ด ์‹ค์ œ๋กœ ๋‚˜๊ฐ€๋Š” ์ˆœ๊ฐ„

flush ๋Š” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ DB ์— ์ง์ ‘ ๋ฐ˜์˜ํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

flush ๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ํŠธ๋ฆฌ๊ฑฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ”Œ๋Ÿฌ์‹œ ํŠธ๋ฆฌ๊ฑฐ์„ค๋ช…
์ˆ˜๋™ flush() ํ˜ธ์ถœ ์‹œ๋ช…์‹œ์ ์œผ๋กœ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋ฐ˜์˜
JPQL ์‹คํ–‰ ์‹œJPQL์€ DB ์ƒํƒœ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋ฏ€๋กœ flush ๋จผ์ € ์‹คํ–‰
ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œSpring์ด ๋‚ด๋ถ€์ ์œผ๋กœ flush ํ›„ commit ์ˆ˜ํ–‰

commit ๊ณผ flush ๋Š” ๋‹ค๋ฆ…๋‹ˆ๋‹ค. flush ๋Š” DB ๋ฐ˜์˜ ์˜ˆ์•ฝ, commit ์€ ํŠธ๋žœ์žญ์…˜ ์™„๋ฃŒ๋ผ๊ณ  ์ดํ•ดํ•˜์‹œ๋ฉด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

Dirty Checking - Hibernate ์˜ ๊ทธ๋ฆผ์ž

Hibernate ์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ persist() ํ•  ๋•Œ ์Šค๋ƒ…์ƒท (์ดˆ๊ธฐ์ƒํƒœ) ๋ฅผ ํ•จ๊ป˜ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.

์ด ํ›„ ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๋Š” ์‹œ์ ์—์„œ ์Šค๋ƒ…์ƒท๊ณผ ํ˜„์žฌ ๊ฐ์ฒด๋ฅผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ์ ์„ ์ฐพ์ฃ .

val member = em.find(Member::class.java, 1L)
member.name = "DevCow"  // update SQL? โŒ ์•„์ง ์•„๋‹˜
tx.commit()             // flush() ์‹คํ–‰ ์‹œ update SQL ์ƒ์„ฑ โœ…

์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์˜ ํ•„๋“œ ๊ฐ’์ด ๋ณ€๊ฒฝ ๋œ ๊ฒฝ์šฐ ์šฐ๋ฆฌ๋Š” JPA ๊ฐ€ ์•Œ์•„์„œ Update ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฐ๋‹ค๊ณ  ์ดํ•ดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์‹ค์€ JPA ๋Š” update ๋ฉ”์†Œ๋“œ๊ฐ€ ๋”ฐ๋กœ ์กด์žฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋‚ ์•„๊ฐ€๋Š” ์ฟผ๋ฆฌ์—์„œ๋Š” UPDATE ๋กœ ๋‚ ์•„๊ฐˆ ์ง€๋„ ๋ชจ๋ฅด์ง€๋งŒ์š”...

JPQL ๊ณผ SQL ์˜ ๋งŒ๋‚จ

์•„๋งˆ JPA ๋ฅผ ํ†ตํ•ด ๋™์  ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋‹ค๋ณด๋ฉด ํ•œ๋ฒˆ ์ฏค์€ ๋งŒ๋‚ฌ์„ ์ง€๋„ ๋ชจ๋ฅด๋Š” ๊ธฐ๋Šฅ์ด ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ JPQL ์ž…๋‹ˆ๋‹ค.

JPQL (Java Persistence Query Language) ๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•œ ์ฟผ๋ฆฌ์ž…๋‹ˆ๋‹ค. Hibernate ๊ฐ€ ์ด๋ฅผ SQL ๋กœ ๋ฐ˜ํ™˜ํ•ด์„œ JDBC ๋กœ ์‹คํ–‰ํ•˜์ฃ .

val members = em.createQuery(
    "select m from Member m where m.name = :name", Member::class.java
)
.setParameter("name", "Woojin")
.resultList
select member_id, name
from member
where name = ?

์ด๋กœ์จ ๊ตฌ์กฐ๊ฐ€ ์™„์„ฑ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

JPA - Hibernate - JDBC ๊ฐ„์˜ ์—ฐ๊ฒฐ๊ด€๊ณ„์—์„œ Spring Data JPA ๋ฅผ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜์—ญ์˜ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ž‘์„ฑ, Hibernate ๋ฅผ ํ†ตํ•œ ์—”ํ‹ฐํ‹ฐ ๋ฐ ํŠธ๋žœ์žญ์…˜ ๊ด€๋ฆฌ, ์ตœ์ข… JDBC ๋ฅผ ํ†ตํ•œ ์ฟผ๋ฆฌ ์ „๋‹ฌ ๊ตฌ์กฐ๋ฅผ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด์•˜์Šต๋‹ˆ๋‹ค.

Tip! N+1 ๋ฌธ์ œ

JPA ๋ฅผ ์“ฐ๋‹ค๋ณด๋ฉด ํ•œ๋ฒˆ ์ฏค์€ ํ•˜๊ฒŒ ๋˜๋Š” ์‹ค์ˆ˜์ฃ . N+1 ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

JPA ์—”ํ‹ฐํ‹ฐ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์„ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ์ฃ . ์™ธ๋ž˜ํ‚ค๋ฅผ ํ†ตํ•ด JOIN ํ•ด ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์ง€๋งŒ...์ž์นซ ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋‹ค๊ฐ„ N+1 ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ N + 1 ๋ฌธ์ œ๋ฅผ ํ•œ๋ฒˆ ์„ค๋ช…ํ•˜๊ณ  ๋„˜์–ด๊ฐ€์ž๋ฉด, ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์ด ๋˜์–ด์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ 1๋ฒˆ์˜ ์ดˆ๊ธฐ ์ฟผ๋ฆฌ ์™ธ์— ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ ๊ฐฏ์ˆ˜ (N) ๋งŒํผ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.

val teams = em.createQuery("select t from Team t", Team::class.java).resultList
teams.forEach { println(it.members.size) } // N+1 ๋ฐœ์ƒ

์˜ˆ๋ฅผ ๋“ค์–ด ํŒ€์— ์†Œ์†๋œ ๋ฉค๋ฒ„๋ฅผ ์กฐํšŒํ•˜๊ณ ์ž ํ•  ๋•Œ, select t form Team t ์™ธ์— select m from Member m ์„ N ๋ฒˆ ํ•˜๊ฒŒ ๋˜๋Š” ์ƒ˜์ด์ฃ .

์‚ฌ์‹ค ์ผ๋ฐ˜์ ์œผ๋กœ SQL ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•ด์˜ค๋Š” ์ƒํ™ฉ์—์„œ๋Š” ๋ณดํ†ต JOIN ์ฟผ๋ฆฌ ํ•˜๋‚˜๋กœ ํ•ด๊ฒฐ์ด ๋˜์–ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์ด์ฃ .

์ด ๋ฌธ์ œ๋Š” fetchJoin ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

select t from Team t join fetch t.members

BatchSize ์˜ต์…˜์„ ํ†ตํ•ด ์ด ๋ฌธ์ œ๋ฅผ ํšŒํ”ผํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ...๊ฐœ์ธ์ ์œผ๋ก  fetchJoin ๋งŒ ์ž˜ ์จ๋„ ์‹ค๋ฌด์—์„œ N+1 ์„ ํšŒํ”ผํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์•„๋‹ˆ๋ฉด ๊ทธ๋ƒฅ ์—ฐ๊ด€๊ด€๊ณ„ ๋งคํ•‘์„ ์“ฐ์ง€ ์•Š๊ณ  ๋ชจ๋“  ์ฟผ๋ฆฌ๋ฅผ QueryDSL ๋กœ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฉ๋ฒ•์ด๊ธด ํ•ฉ๋‹ˆ๋‹ค...

Spring Data JPA - EntityManager ์˜ ์ž๋™ํ™”

Spring Data JPA ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

interface MemberRepository : JpaRepository<Member, Long>

์•ž์„œ ์˜ˆ์‹œ์—์„œ๋Š” EntityManager ๋ฅผ ์ง์ ‘ ๊ฐ€์ ธ์™”์ฃ . ํ•˜์ง€๋งŒ Spring Data JPA ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ตณ์ด ๊ทธ๋Ÿด ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•„์š”ํ•œ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ Repository interface ๋งŒ ์„ ์–ธ ํ•ด ์ฃผ๋ฉด ๋˜์ฃ .

Spring Data JPA ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ ์ด๋Ÿฐ ์—”ํ‹ฐํ‹ฐ Repository ์— ๋Œ€ํ•ด SimpleJpaRepository๋กœ ํ”„๋ก์‹œ๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ EntityManager๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ๋ชจ๋“  CRUD ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด ํ”„๋ก์‹œ๋ฅผ ํ†ตํ•ด ์šฐ๋ฆฌ๋Š” findByXXX ์™€ ๊ฐ™์€ ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋™์  ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์“ฐ๋Š” Specification ๊ธฐ๋Šฅ๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ฃ .

๊ฐœ์ธ์ ์œผ๋ก ...Specification ๋ณด๋‹ค๋Š” QueryDSL ์„ ์ข€ ๋” ์„ ํ˜ธํ•˜๊ธฐ๋Š” ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ QueryDSL ์€ ๊ทธ ๋งŒํผ QClass ์ƒ์„ฑ์œผ๋กœ ์ธํ•ด ๋ฐ”์ด๋„ˆ๋ฆฌ๊ฐ€ ๋ฌด๊ฑฐ์›Œ์งˆ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ์šฐ๋ฆฌ๊ฐ€ ์ง์ ‘ EntityManager๋ฅผ ๋‹ค๋ฃจ์ง€ ์•Š์•„๋„ Spring์ด ํŠธ๋žœ์žญ์…˜ ๊ฒฝ๊ณ„ ๋‚ด์—์„œ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ์ž๋™ ๊ด€๋ฆฌํ•ด์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์š”์•ฝ : JPA ๋ฅผ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•œ ํ•ต์‹ฌ ์ •๋ฆฌ

์ง€๊ธˆ๊นŒ์ง€ Spring Data JPA - Hibernate - JDBC ๊ฐ„์˜ ์—ฐ๊ด€์„ฑ, ๊ทธ๋ฆฌ๊ณ  ์—”ํ‹ฐํ‹ฐ ํด๋ž˜์Šค๋ฅผ ์กฐํšŒ ํ•ด ์˜ค๋Š” ๊ณผ์ •์„ ํ†ตํ•ด JPA ์˜ ๋™์ž‘ ์›๋ฆฌ๋ฅผ ์‚ดํŽด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ๊นŒ์ง€์˜ ๋‚ด์šฉ์„ ๋‹ค์„ฏ์ค„๋กœ ์š”์•ฝ ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  1. JPA๋Š” ORM ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค, Hibernate๋Š” ๊ทธ ๊ตฌํ˜„์ฒด ์ž…๋‹ˆ๋‹ค.
  2. EntityManager๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  3. flush๋Š” ์ปค๋ฐ‹ ์ „์— ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ DB์— ๋ฐ˜์˜ํ•˜๋Š” ์˜ˆ์•ฝ ๋ช…๋ น ์ž…๋‹ˆ๋‹ค.
  4. ๋”ํ‹ฐ ์ฒดํ‚น์€ ์Šค๋ƒ…์ƒท ๊ธฐ๋ฐ˜ ๊ฐ์ฒด ๋ณ€๊ฒฝ ํƒ์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ž…๋‹ˆ๋‹ค.
  5. JPQL์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋Œ€์ƒ์œผ๋กœ ํ•˜๋Š” SQL ์ถ”์ƒํ™” ์–ธ์–ด ์ž…๋‹ˆ๋‹ค.

๋งˆ์น˜๋ฉฐ

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” JPA ์˜ ์ž‘๋™ ์›๋ฆฌ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์•˜์Šต๋‹ˆ๋‹ค.

JPA ๋Š” ๋‹จ์ˆœํžˆ DB ์— ์ฟผ๋ฆฌ๋ฅผ ๋Œ€์‹  ๋‚ ๋ ค์ฃผ๋Š” ๋„๊ตฌ๋ผ๊ณ  ๋ณด๊ธด ์–ด๋ ต์Šต๋‹ˆ๋‹ค.

DB ์— ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๊ธฐ ์ „, ๋‚ด๋ถ€ ๋กœ์ง์„ ํ†ตํ•ด ์ตœ์ข… ์ „๋‹ฌํ•  ์ฟผ๋ฆฌ๋ฅผ ์ตœ์ ํ™” ํ•ด์ฃผ๋Š” ๋„๊ตฌ์ฃ . ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜์—์„œ ๋ถˆํ•„์š”ํ•œ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ง‰์•„์ฃผ๊ธฐ๋„ ํ•˜์ฃ .

JDBC ๋งŒ ๊ฐ€์ง€๊ณ  ๊ฐœ๋ฐœํ•  ๋•Œ์— ๋น„ํ•ด ๊ฐœ๋ฐœ์ž๋“ค์ด ์ „๋‹ฌํ•˜๋Š” ์ฟผ๋ฆฌ๋“ค์„ ์–ด๋А์ •๋„๋Š” ์ตœ์ ํ™”์‹œ์ผœ์ฃผ๊ธฐ๋Š” ํ•˜์ง€๋งŒ SQL ์ฟผ๋ฆฌ ์ž์ฒด๋ฅผ ํŠœ๋‹์‹œ์ผœ์ฃผ๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ถˆํ•„์š”ํ•˜๊ฒŒ ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋„๋ก ๋„์™€์ฃผ๋Š” ์—ญํ• ์„ ํ•˜์ฃ .

๋‹ค๋งŒ, ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค๋ฌด๋ฅผ ํ•˜๋‹ค๋ณด๋ฉด ๋‹จ์ˆœ ์—”ํ‹ฐํ‹ฐ SELECT ๋ฅผ ํ–ˆ๋‹ค๊ณ  ์ƒ๊ฐํ•˜์ง€๋งŒ, DBA ์ž…์žฅ์—์„œ๋Š” ์ด๋Ÿฐ ์ด์•ผ๊ธฐ๋ฅผ ํ•  ์ˆ˜๋„ ์žˆ์–ด์š”.

์•„๋‹ˆ ์™œ ์ž๊พธ SELECT * ๋ฅผ ๋•Œ๋ฆฌ๋Š”๊ฑฐ์•ผ! JPA ๋Š” ์ด๋ž˜์„œ ์•ˆ๋ผ!

๊ผญ ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋“ค๋งŒ ์กฐํšŒํ•˜๋Š”๊ฒŒ ์‚ฌ์‹ค์€ ๋งž๊ธฐ๋Š” ํ•ฉ๋‹ˆ๋‹ค. ๋ฌผ๋ก  ํ…Œ์ด๋ธ”์„ ๋ฏธ๋‹ˆ๋ฉ€ํ•˜๊ฒŒ ์ž˜ ์„ค๊ณ„ํ•ด๋’€๋‹ค๋ฉด ๊ดœ์ฐฎ๊ฒ ์ง€๋งŒ, ๋งค๋ฒˆ ๊ทธ๋ ‡์ง€๋Š” ๋ชปํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๊ฐ์•ˆํ•˜๊ณ  ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๋Š˜ ์‹ ๊ทœ ์„œ๋น„์Šค๋งŒ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฑด ์•„๋‹ˆ๋‹ˆ๊นŒ์š”.

ํŠนํžˆ ์˜ค๋ž˜๋œ ์„œ๋น„์Šค๋ฅผ ๊ฑด๋“ค๊ฒŒ ๋œ๋‹ค๋ฉด, ๊ฐ€๋”์€ ์˜†์œผ๋กœ ๋šฑ๋šฑํ•œ๋ฐ ๋ฐ์ดํ„ฐ ์–‘๊นŒ์ง€ ๋งŽ์€ ํ…Œ์ด๋ธ”์„ ๊ฑด๋“œ๋ฆฌ๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊น๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ์—๋Š” ์ ˆ๋Œ€ JPA ๋ฅผ ๋งŒ๋Šฅ์œผ๋กœ ์ƒ๊ฐํ•ด์„œ๋Š” ์•ˆ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ํฌ์ŠคํŒ…์€ JPA ์‚ฌ์šฉ ํŒ์ž…๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ์‹ค๋ฌด์—์„œ ๋” ์ž˜ ์“ธ ์ˆ˜ ์žˆ์„ ์ง€ ๋‚ด์šฉ๋“ค์„ ์ •๋ฆฌํ•ด์„œ ์ž‘์„ฑ ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!