๐ŸŽฏ F-lab Java 11-12์ฃผ์ฐจ ํ†ตํ•ฉ ํ•™์Šต ์ปค๋ฆฌํ˜๋Ÿผ

11-12์ฃผ์ฐจ ์ž๋ฃŒ์˜ ๋ชจ๋“  ํ† ํ”ฝ์„ ๋‘ ์ฃผ์— ๊ฑธ์ณ ์ •๋ฆฌํ•œ ํ•™์Šต ๊ฒฝ๋กœ.
1) 11์ฃผ์ฐจ โ€” JPA์˜ ์ •์ฒด์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ (์‹ฑ๊ธ€ํ†ค โ†’ SQL Mapper โ†’ ORM โ†’ ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘ โ†’ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ)
2) 12์ฃผ์ฐจ โ€” ์—ฐ๊ด€๊ด€๊ณ„์™€ ์„ฑ๋Šฅ ์ตœ์ ํ™” (4๊ฐ€์ง€ ์—ฐ๊ด€๊ด€๊ณ„ โ†’ ํ”„๋ก์‹œ โ†’ N+1 ๋ฌธ์ œ โ†’ CASCADE โ†’ JPQL/QueryDSL)

7์ฃผ์ฐจ์—์„œ JPA์˜ ์ž…๋ฌธ์„ ๋ดค๋‹ค๋ฉด, 11-12์ฃผ์ฐจ๋Š” JPA์˜ ๋ชจ๋“  ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊นŠ์ด ํŒŒํ—ค์นœ๋‹ค.

์ž๋ฐ”ยทSpring ํ•™์Šต์˜ ๋˜ ๋‹ค๋ฅธ ์ •์ ์ด๋ฉฐ, ์‹ค๋ฌด์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ๋งŒ๋‚˜๋Š” ์˜์—ญ์ด๋‹ค.


๐Ÿ“Š ํ•™์Šต ๊ฒฝ๋กœ ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

[Part A โ€” 11์ฃผ์ฐจ: JPA์˜ ์ •์ฒด์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ]
  [Phase 1] ์‹ฑ๊ธ€ํ†ค + SQL Mapper์˜ ์—ญ์‚ฌ
     โ†“
  [Phase 2] ORM๊ณผ JPA์˜ ๋ณธ์งˆ
     โ†“
  [Phase 3] ์—”ํ‹ฐํ‹ฐ์™€ ํ…Œ์ด๋ธ” ๋งคํ•‘ ๊ธฐ์ดˆ
     โ†“
  [Phase 4] EntityManager + ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ
     โ†“
  [Phase 5] ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ 4๊ฐ€์ง€ ์žฅ์  โ—„ 11์ฃผ์ฐจ ์ •์ 

[Part B โ€” 12์ฃผ์ฐจ: ์—ฐ๊ด€๊ด€๊ณ„์™€ ์„ฑ๋Šฅ ์ตœ์ ํ™”]
  [Phase 6] JPA ์—ฐ๊ด€๊ด€๊ณ„ 4๊ฐ€์ง€ (1:1, N:1, 1:N, N:M)
     โ†“
  [Phase 7] mappedBy์™€ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ
     โ†“
  [Phase 8] ํ”„๋ก์‹œ์™€ ์ง€์—ฐ/์ฆ‰์‹œ ๋กœ๋”ฉ
     โ†“
  [Phase 9] N+1 ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ โ—„ 12์ฃผ์ฐจ ์ •์ 
     โ†“
  [Phase 10] ์˜์†์„ฑ ์ „์ด + JPQL/QueryDSL

์ด 10 Phase ร— 39 Unit โ€” 8-9์ฃผ์ฐจ์™€ ๋น„์Šทํ•œ ๋ถ„๋Ÿ‰์˜ ํ†ตํ•ฉ ์ปค๋ฆฌํ˜๋Ÿผ.

๐Ÿ”— 1~12์ฃผ์ฐจ ํ๋ฆ„ ์ •๋ฆฌ

์ฃผ์ฐจ์ฃผ์ œํ•ต์‹ฌ ๋ณ€ํ™”
1์ฃผ์ฐจOOPยทJVMยทGCยท์ปฌ๋ ‰์…˜ยทI/O ๊ฐœ๋ก ์ž๋ฐ” ํฐ ๊ทธ๋ฆผ
2์ฃผ์ฐจJVM ๋‚ด๋ถ€ยท๋ฐ”์ดํŠธ์ฝ”๋“œยทG1 GC"์–ด๋–ป๊ฒŒ ๋Œ์•„๊ฐ€๋‚˜"
3์ฃผ์ฐจ์ปฌ๋ ‰์…˜ยท์ œ๋„ค๋ฆญยทํ•จ์ˆ˜ํ˜•์ž๋ฐ” ํ‘œํ˜„๋ ฅ
4์ฃผ์ฐจ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉยท๋™์‹œ์„ฑยทExecutor๋™์‹œ์„ฑ ์ •๋ณต
5์ฃผ์ฐจAtomic + Spring IoC/DI ์ž…๋ฌธ์ž๋ฐ” โ†’ Spring ๋‹ค๋ฆฌ
6์ฃผ์ฐจํ…Œ์ŠคํŠธ + ์›น ์ธํ”„๋ผ + DB ์ ‘๊ทผ ์ง„ํ™”Spring ์‹ค์ „ ํ™˜๊ฒฝ
7์ฃผ์ฐจJPA/ORM ์ž…๋ฌธ + ํŠธ๋žœ์žญ์…˜ ์ถ”์ƒํ™”DB ์ถ”์ƒํ™” ์ž…๋ฌธ
8์ฃผ์ฐจํ”„๋ก์‹œ์˜ ์ง„ํ™”AOP ๋ฉ”์ปค๋‹ˆ์ฆ˜
9์ฃผ์ฐจSpring AOP ์‹ค์ „ + ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒAOP ์‹ค์ „ ํ™œ์šฉ
10์ฃผ์ฐจํŠธ๋žœ์žญ์…˜ ์ •๋ฆฌ + ๋นˆ ๋ผ์ดํ”„์‚ฌ์ดํด ํ•จ์ • + ๊ฒฉ๋ฆฌ ์ˆ˜์ค€ํŠธ๋žœ์žญ์…˜ ๋งˆ๋ฌด๋ฆฌ
11์ฃผ์ฐจ (์ง€๊ธˆ)JPA์˜ ์ •์ฒด์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธJPA ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์™„์ „ ์ดํ•ด
12์ฃผ์ฐจ (์ง€๊ธˆ)์—ฐ๊ด€๊ด€๊ณ„ + ์„ฑ๋Šฅ ์ตœ์ ํ™” (N+1 ๋“ฑ)JPA ์‹ค์ „ ํ™œ์šฉ

๐Ÿ—“๏ธ ๊ถŒ์žฅ ํ•™์Šต ์ผ์ • (์••์ถ• 14์ผ)

DayPhaseํ•™์Šต ๋ชฉํ‘œ
Week 1 (11์ฃผ์ฐจ)
1์ผ์ฐจPhase 1์‹ฑ๊ธ€ํ†ค + SQL Mapper ์—ญ์‚ฌ
2์ผ์ฐจPhase 2ORM/JPA ๋ณธ์งˆ + Hibernate
3์ผ์ฐจPhase 3์—”ํ‹ฐํ‹ฐ ๋งคํ•‘ + ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…
4-5์ผ์ฐจPhase 4EntityManager + ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ + ์ƒ๋ช…์ฃผ๊ธฐ
6-7์ผ์ฐจPhase 54๊ฐ€์ง€ ์žฅ์  (โ˜… ์ •์ )
Week 2 (12์ฃผ์ฐจ)
8-9์ผ์ฐจPhase 64๊ฐ€์ง€ ์—ฐ๊ด€๊ด€๊ณ„
10์ผ์ฐจPhase 7mappedBy์™€ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ
11์ผ์ฐจPhase 8ํ”„๋ก์‹œ์™€ ์ง€์—ฐ/์ฆ‰์‹œ ๋กœ๋”ฉ
12-13์ผ์ฐจPhase 9N+1 ๋ฌธ์ œ + ํ•ด๊ฒฐ์ฑ… (โ˜… ์ •์ )
14์ผ์ฐจPhase 10CASCADE + JPQL + QueryDSL

์—ฌ์œ  ์ผ์ • (21์ผ): Phase 5์™€ 9์— ๊ฐ +2์ผ. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ N+1์€ ์ง์ ‘ SQL ๋กœ๊ทธ๋ฅผ ๋ณด๋ฉฐ ์ฒดํ™”.


๐ŸŒฑ Part A โ€” 11์ฃผ์ฐจ: JPA์˜ ์ •์ฒด์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

๐Ÿ“š Phase 1 โ€” ์‹ฑ๊ธ€ํ†ค + SQL Mapper์˜ ์—ญ์‚ฌ

๋ชฉํ‘œ: JPA๊ฐ€ ์–ด๋–ค ํ๋ฆ„์˜ ์‚ฐ๋ฌผ์ธ์ง€๋ฅผ SQL Mapper(iBatis/MyBatis)์™€์˜ ๋น„๊ต๋กœ ์ดํ•ดํ•œ๋‹ค.

Unit 1.1 โ€” ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๋ณธ์งˆ (5์ฃผ์ฐจ ๋ณต์Šต+์‹ฌํ™”)

์„ ์ˆ˜ ์ง€์‹: 5์ฃผ์ฐจ Phase 8 (์‹ฑ๊ธ€ํ†ค ๋นˆ)

ํ•ต์‹ฌ ๊ฐœ๋…

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ์ •์˜:

"ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋‹จ ํ•˜๋‚˜๋งŒ ์กด์žฌ ํ•˜๋„๋ก ๋ณด์žฅ + ์ „์—ญ ์ ‘๊ทผ"

ํ•ต์‹ฌ 3์š”์†Œ:
1. static ๋ณ€์ˆ˜๋กœ ์œ ์ผ ์ธ์Šคํ„ด์Šค ์ €์žฅ
2. private ์ƒ์„ฑ์ž๋กœ ์™ธ๋ถ€ ์ƒ์„ฑ ์ฐจ๋‹จ
3. getInstance() ์ •์  ๋ฉ”์„œ๋“œ๋กœ ๋ฐ˜ํ™˜

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}  // private!
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

๋Œ€ํ‘œ์ ์ธ ์‹ฑ๊ธ€ํ†ค ์‚ฌ๋ก€:

  • Spring์˜ Bean ๊ฐ์ฒด (5์ฃผ์ฐจ)
  • JPA์˜ EntityManagerFactory โญ (์ด๋ฒˆ ์ฃผ์ฐจ ํ•ต์‹ฌ)
  • Database Connection Pool (HikariCP)
  • Logger, Caching System

์ž๊ธฐ ์ ๊ฒ€

  • 5์ฃผ์ฐจ Spring ์‹ฑ๊ธ€ํ†ค๊ณผ GoF ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ์ฐจ์ด๋Š”?
  • private ์ƒ์„ฑ์ž ์—†์ด ์‹ฑ๊ธ€ํ†ค์ด ๊ฐ€๋Šฅํ•œ๊ฐ€?

Unit 1.2 โ€” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์˜ ์œ„ํ—˜ + ThreadLocal ์—ฐ๊ฒฐ

์„ ์ˆ˜ ์ง€์‹: Unit 1.1, 4์ฃผ์ฐจ Phase 4, 10์ฃผ์ฐจ Phase 4

ํ•ต์‹ฌ ์œ„ํ—˜

๋ฌธ์ œ:

  • ์‹ฑ๊ธ€ํ†ค์€ ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜๋‚˜
  • โ†’ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๊ณต์œ 
  • โ†’ Race Condition ๊ฐ€๋Šฅ

ํ•ด๊ฒฐ ๋ฐฉํ–ฅ:
1. stateless ์„ค๊ณ„ (๊ฐ€์žฅ ๊ถŒ์žฅ) โ€” ๋ฉค๋ฒ„ ๋ณ€์ˆ˜์— ๊ฐ€๋ณ€ ์ƒํƒœ๋ฅผ ๋‘์ง€ ์•Š์Œ
2. synchronized (์„ฑ๋Šฅ ๋น„์šฉ)
3. Atomic (5์ฃผ์ฐจ Phase 2 โ€” CAS)
4. ThreadLocal (8์ฃผ์ฐจ Phase 1 โ€” ์Šค๋ ˆ๋“œ๋ณ„ ๋…๋ฆฝ ์ €์žฅ์†Œ)

JPA์—์„œ์˜ ์ ์šฉ:

  • EntityManagerFactory = ์‹ฑ๊ธ€ํ†ค (์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์—ญ)
  • EntityManager = ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„ (์Šค๋ ˆ๋“œ๋ณ„๋กœ ๋‹ค๋ฆ„)
  • โ†’ ๋™์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ EntityManager ๋ถ„๋ฆฌ๋กœ ํšŒํ”ผ

์ž๊ธฐ ์ ๊ฒ€

  • ILIC์˜ Service ๋นˆ์— List ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋ฅผ ๋‘๋ฉด? (ํžŒํŠธ: ๋™์‹œ์„ฑ ์‚ฌ๊ณ )
  • 4์ฃผ์ฐจ ConcurrentHashMap์„ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋กœ ๋‘๋Š” ๊ฑด ์•ˆ์ „ํ•œ๊ฐ€?

Unit 1.3 โ€” iBatis โ†’ MyBatis (SQL Mapper์˜ ์ง„ํ™”)

์„ ์ˆ˜ ์ง€์‹: 6์ฃผ์ฐจ Phase 7 (JdbcTemplate)

ํ•ต์‹ฌ ๊ฐœ๋…

iBatis (Internet Based Abstraction for Tabular Information Systems):

  • SQL์„ XML ํŒŒ์ผ์— ๋ถ„๋ฆฌ
  • ์ž๋ฐ” ๊ฐ์ฒด์™€ SQL ๊ฒฐ๊ณผ ๋งคํ•‘ ์ž๋™ํ™”
  • iBatis 3.0 ์ดํ›„ ๊ฐœ๋ฐœ ์ค‘๋‹จ

MyBatis = iBatis์˜ ํ›„๊ณ„์ž:

  • ์–ด๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜ SQL ๋งคํ•‘ ์ถ”๊ฐ€ (@Select, @Insert)
  • ๋™์  SQL (<if>, <foreach>)
  • ๋” ๋งŽ์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ˜ธํ™˜

JDBC vs MyBatis ๋น„๊ต:

JDBC ์ง์ ‘MyBatis
SQL ์ž‘์„ฑ์ž๋ฐ” ์ฝ”๋“œ ์•ˆXML ๋˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
์ž์› ๊ด€๋ฆฌ์ˆ˜๋™ (try/finally)์ž๋™
๊ฒฐ๊ณผ ๋งคํ•‘์ˆ˜๋™ (rs.getInt ๋“ฑ)์ž๋™ (resultType)
์ฝ”๋“œ๋Ÿ‰๋งŽ์Œ์ ์Œ

SQL Mapper์˜ ํ•œ๊ณ„:

  • โœ… ์ž์› ๊ด€๋ฆฌ ์ž๋™ํ™”
  • โŒ SQL์€ ์—ฌ์ „ํžˆ ์ง์ ‘ ์ž‘์„ฑ
  • โŒ ๊ฐ์ฒด-๊ด€๊ณ„ ๋งคํ•‘์€ ์ˆ˜๋™
  • โ†’ ๊ทธ๋ž˜์„œ ORM(JPA)์ด ๋“ฑ์žฅ

์ž๊ธฐ ์ ๊ฒ€

  • JdbcTemplate(6์ฃผ์ฐจ)๊ณผ MyBatis์˜ ์œ„์น˜๋Š” ๊ฐ™์€๊ฐ€? (ํžŒํŠธ: ๋‘˜ ๋‹ค SQL Mapper)
  • ํ•œ๊ตญ SI ์‹œ์žฅ์—์„œ MyBatis๊ฐ€ ์—ฌ์ „ํžˆ ๋งŽ์ด ์“ฐ์ด๋Š” ์ด์œ ๋Š”? (ํžŒํŠธ: SQL ํ†ต์ œ, ์ต์ˆ™ํ•จ)

๐Ÿ“š Phase 2 โ€” ORM๊ณผ JPA์˜ ๋ณธ์งˆ

๋ชฉํ‘œ: ORM์˜ ํŒจ๋Ÿฌ๋‹ค์ž„๊ณผ JPA-Hibernate์˜ ๊ด€๊ณ„๋ฅผ ๋ช…ํ™•ํžˆ ์žก๋Š”๋‹ค.

Unit 2.1 โ€” SQL Mapper vs ORM (ํŒจ๋Ÿฌ๋‹ค์ž„ ์ฐจ์ด)

์„ ์ˆ˜ ์ง€์‹: Phase 1, 7์ฃผ์ฐจ Phase 2~3

ํ•ต์‹ฌ ๋น„๊ต

SQL Mapper (MyBatis, JdbcTemplate)ORM (JPA/Hibernate)
๋งคํ•‘SQL โ†” ๊ฐ์ฒด๊ฐ์ฒด โ†” ํ…Œ์ด๋ธ”
SQL ์ž‘์„ฑ๊ฐœ๋ฐœ์ž ์ง์ ‘JPA๊ฐ€ ์ž๋™ ์ƒ์„ฑ
ํ•™์Šต ๊ณก์„ ๋‚ฎ์Œ๋†’์Œ
DBMS ์ข…์†์„ฑ์žˆ์Œ์ ์Œ
๋ณต์žก ํ†ต๊ณ„ ์ฟผ๋ฆฌ์ž์œ ๋กญ๊ฒŒ์–ด๋ ต (JPQL/๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ ํ•„์š”)

SQL Mapper์˜ ์‹œ๊ฐ:

"SQL์„ ์ž‘์„ฑํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ฒด์— ์ฑ„์›Œ์ฃผ์„ธ์š”"

ORM์˜ ์‹œ๊ฐ:

"๊ฐ์ฒด๋ฅผ ๋‹ค๋ฃจ์„ธ์š”. SQL์€ ์ œ๊ฐ€ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค"

๊ฐ์ฒด-๊ด€๊ณ„ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜:

  • ๊ฐ์ฒด๋Š” ์ƒ์†ยท๋‹คํ˜•์„ฑยท์—ฐ๊ด€ ์ฐธ์กฐ
  • ๊ด€๊ณ„ DB๋Š” ํ–‰๊ณผ ์—ดยท์™ธ๋ž˜ ํ‚ค
  • โ†’ ๋‘˜ ์‚ฌ์ด์˜ ๋ณ€ํ™˜์€ ์ฝ”๋“œ๊ฐ€ ๋งŽ์•„์ง
  • โ†’ ์ด ๋ณ€ํ™˜์„ ORM์ด ์ž๋™ํ™”

์ž๊ธฐ ์ ๊ฒ€

  • ๋ณต์žกํ•œ ํ†ต๊ณ„ ์ฟผ๋ฆฌ์—์„œ ORM์˜ ํ•œ๊ณ„๋Š”?
  • SQL Mapper์™€ ORM์„ ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ™์ด ์“ธ ์ˆ˜ ์žˆ๋Š”๊ฐ€? (ํžŒํŠธ: YES, ์‹ค๋ฌด์—์„œ ํ”ํ•จ)

Unit 2.2 โ€” JPA = ํ‘œ์ค€ ๋ช…์„ธ, Hibernate = ๊ตฌํ˜„์ฒด

์„ ์ˆ˜ ์ง€์‹: Unit 2.1

ํ•ต์‹ฌ ๊ตฌ์กฐ

JPA (Java Persistence API):

  • ๋ช…์„ธ(Specification) โ€” ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์ •์˜
  • ์ง์ ‘ ๋™์ž‘ํ•˜๋Š” ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•„๋‹ˆ๋‹ค
  • ex) EntityManager, EntityManagerFactory ์ธํ„ฐํŽ˜์ด์Šค

JPA ๊ตฌํ˜„์ฒด:

  • Hibernate (๊ฐ€์žฅ ๋Œ€์ค‘์ , ~95% ์ ์œ ) โญ
  • EclipseLink
  • DataNucleus
  • OpenJPA

์˜์กด ๊ด€๊ณ„:

[Application Code]
       โ†“
[JPA Interface]   โ† javax.persistence (๋˜๋Š” jakarta.persistence)
       โ†“
[Hibernate]      โ† JPA ๊ตฌํ˜„
       โ†“
[JDBC]
       โ†“
[DB]

ILIC ์‚ฌ๋ก€:

  • spring-boot-starter-data-jpa ์˜์กด์„ฑ ์ถ”๊ฐ€
  • ๋‚ด๋ถ€์ ์œผ๋กœ Hibernate ์ž๋™ ์„ค์ •
  • ๊ฐœ๋ฐœ์ž๋Š” JPA API๋กœ ์ฝ”๋”ฉ

Spring Data JPA์™€์˜ ๊ตฌ๋ถ„:

  • JPA: ์ž๋ฐ” ํ‘œ์ค€ ์ธํ„ฐํŽ˜์ด์Šค
  • Hibernate: JPA์˜ ๊ตฌํ˜„์ฒด
  • Spring Data JPA: JPA๋ฅผ ๋” ํŽธ๋ฆฌํ•˜๊ฒŒ ์“ฐ๋Š” Spring์˜ ์ถ”์ƒํ™” (Repository ์ธํ„ฐํŽ˜์ด์Šค ๋“ฑ)

์ž๊ธฐ ์ ๊ฒ€

  • ์™œ JPA๋ฅผ ํ‘œ์ค€ํ™”ํ–ˆ๋Š”๊ฐ€? (ํžŒํŠธ: ๊ตฌํ˜„์ฒด ๊ต์ฒด ๊ฐ€๋Šฅ)
  • Hibernate๋ฅผ ์ง์ ‘ ์“ฐ์ง€ ์•Š๊ณ  JPA๋กœ ์ฝ”๋”ฉํ•˜๋Š” ์ด์œ ๋Š”?

Unit 2.3 โ€” ๊ฐ์ฒด-๊ด€๊ณ„ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ + JPA ์œ„์น˜

์„ ์ˆ˜ ์ง€์‹: Unit 2.2

ํ•ต์‹ฌ ๋ถˆ์ผ์น˜ 5๊ฐ€์ง€:

์ธก๋ฉด๊ฐ์ฒด (OOP)๊ด€๊ณ„ DB
๋ชจ๋ธ๋ง์ƒํƒœ + ํ–‰๋™ํ–‰๊ณผ ์—ด
์ƒ์†์žˆ์Œ์—†์Œ
์—ฐ๊ด€์ฐธ์กฐ (order.member)์™ธ๋ž˜ํ‚ค
์‹๋ณ„๊ฐ์ฒด ๋™์ผ์„ฑ (==)PK
๋ฐ์ดํ„ฐ ํƒ€์ž…ํ’๋ถ€ (List, Map)์ œํ•œ์ 

๋ถˆ์ผ์น˜๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ• (JPA์˜ ์ผ):

  • ์ƒ์† โ†’ SINGLE_TABLE / JOINED / TABLE_PER_CLASS
  • ์ฐธ์กฐ โ†’ @ManyToOne, @OneToMany ์–ด๋…ธํ…Œ์ด์…˜
  • ๋™์ผ์„ฑ โ†’ 1์ฐจ ์บ์‹œ๋กœ ๋ณด์žฅ (Phase 5์—์„œ)

JPA์˜ ๋ณธ์งˆ:

"๊ฐ์ฒด์™€ RDB ์‚ฌ์ด์˜ ๋ฒˆ์—ญ๊ธฐ"

์ž๊ธฐ ์ ๊ฒ€

  • "ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜"์˜ ๊ฐ€์žฅ ๋ช…ํ™•ํ•œ ์‚ฌ๋ก€๋ฅผ ๋ณธ์ธ ์ฝ”๋“œ์—์„œ ์ฐพ์•„๋ณธ๋‹ค๋ฉด?
  • ILIC์˜ Booking ๊ฐ์ฒด์™€ bookings ํ…Œ์ด๋ธ”์˜ ๋งคํ•‘์ด ์ž๋™ํ™”๋˜๋Š” ์ด์ ์€?

๐Ÿ“š Phase 3 โ€” ์—”ํ‹ฐํ‹ฐ์™€ ํ…Œ์ด๋ธ” ๋งคํ•‘ ๊ธฐ์ดˆ

๋ชฉํ‘œ: ์ž๋ฐ” ๊ฐ์ฒด โ†’ DB ํ…Œ์ด๋ธ” ๋งคํ•‘์˜ ๊ธฐ๋ณธ ์–ด๋…ธํ…Œ์ด์…˜์„ ์†์— ์ตํžŒ๋‹ค.

Unit 3.1 โ€” @Entity์™€ ์—”ํ‹ฐํ‹ฐ์˜ ์กฐ๊ฑด

์„ ์ˆ˜ ์ง€์‹: 7์ฃผ์ฐจ Phase 4

ํ•ต์‹ฌ ๊ฐœ๋…

@Entity:

  • "JPA๊ฐ€ ๊ด€๋ฆฌํ•˜๋Š” ๊ฐ์ฒด"๋ผ๋Š” ํ‘œ์‹œ
  • ์ด๊ฒŒ ์žˆ์–ด์•ผ JPA๊ฐ€ ์ธ์‹ โ†’ ์—”ํ‹ฐํ‹ฐ

์—”ํ‹ฐํ‹ฐ์˜ ํ•„์ˆ˜ ์กฐ๊ฑด โญ :

  • โœ… ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์ˆ˜ (public ๋˜๋Š” protected)
  • โœ… ์‹๋ณ„์ž ํ•„๋“œ (@Id)
  • โŒ final ํด๋ž˜์Šค ์‚ฌ์šฉ ๋ถˆ๊ฐ€ (Hibernate๊ฐ€ ํ”„๋ก์‹œ ๋งŒ๋“ค์–ด์•ผ ํ•จ)
  • โŒ enum, interface, inner class ๋ถˆ๊ฐ€
  • โŒ ์ €์žฅํ•  ํ•„๋“œ์— final ์‚ฌ์šฉ ๋ถˆ๊ฐ€

๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์™œ ํ•„์š”ํ•œ๊ฐ€?:

  • JPA๊ฐ€ ๋ฆฌํ”Œ๋ ‰์…˜ ์œผ๋กœ ๊ฐ์ฒด ์ƒ์„ฑ (3์ฃผ์ฐจ Phase 5)
  • โ†’ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๊ฐ€ ์žˆ์–ด์•ผ ํ•จ
@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    
    private String name;
    
    public Member() {}  // ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์ˆ˜!
    
    public Member(String name) {
        this.name = name;
    }
}

์ž๊ธฐ ์ ๊ฒ€

  • final ํด๋ž˜์Šค๋ฅผ ์—”ํ‹ฐํ‹ฐ๋กœ ๋งŒ๋“ค๋ฉด ์–ด๋–ค ์—๋Ÿฌ๊ฐ€? (ํžŒํŠธ: ํ”„๋ก์‹œ ์ƒ์„ฑ ์‹คํŒจ)
  • 8์ฃผ์ฐจ Phase 5์˜ CGLIB์™€ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋Š”๊ฐ€?

Unit 3.2 โ€” @Table ๋งคํ•‘

์„ ์ˆ˜ ์ง€์‹: Unit 3.1

ํ•ต์‹ฌ ๊ฐœ๋…

๊ธฐ๋ณธ ๋งคํ•‘:

  • ํด๋ž˜์Šค๋ช… โ†’ ํ…Œ์ด๋ธ”๋ช… ์ž๋™ ๋งคํ•‘
  • Member ํด๋ž˜์Šค โ†’ member ํ…Œ์ด๋ธ”

@Table ์œผ๋กœ ๋ช…์‹œ:

@Entity
@Table(name = "MBR")  // ์‹ค์ œ ํ…Œ์ด๋ธ”๋ช…์„ MBR๋กœ
public class Member {
    // ...
}

@Column ๋งคํ•‘ (7์ฃผ์ฐจ Phase 4 ๋ณต์Šต):

@Column(name = "user_name", length = 100, nullable = false)
private String userName;

Spring Boot์˜ ์ž๋™ ๋ณ€ํ™˜ (7์ฃผ์ฐจ Unit 4.5):

  • ์ž๋ฐ” ํ•„๋“œ: userName (camelCase)
  • DB ์ปฌ๋Ÿผ: user_name (snake_case)
  • โ†’ ์ž๋™ ๋งคํ•‘

์ž๊ธฐ ์ ๊ฒ€

  • @Table ์„ ์ƒ๋žตํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€?
  • ํ•œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ ํ…Œ์ด๋ธ”์— ๋งคํ•‘๋  ์ˆ˜ ์žˆ๋Š”๊ฐ€? (ํžŒํŠธ: @SecondaryTable)

Unit 3.3 โ€” ์ž„๋ฒ ๋””๋“œ ํƒ€์ž… (@Embeddable + @AttributeOverrides)

์„ ์ˆ˜ ์ง€์‹: Unit 3.2

ํ•ต์‹ฌ ๊ฐœ๋…

์ž„๋ฒ ๋””๋“œ ํƒ€์ž…(Embedded Type):

  • "๊ฐ’ ํƒ€์ž…(Value Type)"์˜ ์ผ์ข…
  • ์—ฌ๋Ÿฌ ํ•„๋“œ๋ฅผ ํ•˜๋‚˜์˜ ๊ฐ์ฒด๋กœ ๋ฌถ๊ธฐ
  • ์ฝ”๋“œ ์žฌ์‚ฌ์šฉ์„ฑ โ†‘

์˜ˆ์‹œ โ€” ์ฃผ์†Œ๋ฅผ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์œผ๋กœ:

@Embeddable
public class Address {
    private String city;
    private String street;
    private String zipcode;
    
    protected Address() {}  // ๊ธฐ๋ณธ ์ƒ์„ฑ์ž ํ•„์ˆ˜
    
    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
    // Getter๋งŒ (๊ฐ’ ํƒ€์ž…์€ ๋ถˆ๋ณ€ ๊ถŒ์žฅ)
}

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    private String name;
    
    @Embedded
    private Address address;  // ์ž„๋ฒ ๋””๋“œ ์‚ฌ์šฉ
}

DB ํ…Œ์ด๋ธ” ๊ฒฐ๊ณผ:

CREATE TABLE Member (
    id BIGINT PRIMARY KEY,
    name VARCHAR(255),
    city VARCHAR(255),     -- Address์˜ ํ•„๋“œ
    street VARCHAR(255),
    zipcode VARCHAR(255)
);

@AttributeOverrides โ€” ๊ฐ™์€ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์„ ์—ฌ๋Ÿฌ ๋ฒˆ ์‚ฌ์šฉ ์‹œ:

@Entity
public class Employee {
    @Id @GeneratedValue
    private Long id;
    
    @Embedded
    @AttributeOverrides({
        @AttributeOverride(name = "city", column = @Column(name = "home_city")),
        @AttributeOverride(name = "street", column = @Column(name = "home_street")),
        @AttributeOverride(name = "zipcode", column = @Column(name = "home_zipcode"))
    })
    private Address homeAddress;
    
    @Embedded
    @AttributeOverrides({...})
    private Address workAddress;
}

๊ฐ’ ํƒ€์ž…์˜ ์›์น™:

  • ๋ถˆ๋ณ€(Immutable) โ€” Setter ๋งŒ๋“ค์ง€ ๋ง๊ณ  ์ƒ์„ฑ์ž๋กœ๋งŒ
  • ๊ณต์œ ํ•˜์ง€ ๋ง ๊ฒƒ โ€” ๋ถ€์ž‘์šฉ ๋ฐฉ์ง€

์ž๊ธฐ ์ ๊ฒ€

  • ๊ฐ’ ํƒ€์ž…์„ ๊ฐ€๋ณ€์œผ๋กœ ๋งŒ๋“ค๋ฉด ์–ด๋–ค ์‚ฌ๊ณ ๊ฐ€? (ํžŒํŠธ: ๋‹ค๋ฅธ ์—”ํ‹ฐํ‹ฐ์— ์˜ํ–ฅ)
  • ILIC์—์„œ ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์œผ๋กœ ํ‘œํ˜„ํ•˜๊ธฐ ์ข‹์€ ๋„๋ฉ”์ธ์€? (ํžŒํŠธ: ์ฃผ์†Œ, ์šด์ž„, ์—ฐ๋ฝ์ฒ˜)

Unit 3.4 โ€” ddl-auto + DDL/DML/DCL ์ฐธ๊ณ 

์„ ์ˆ˜ ์ง€์‹: Unit 3.3

ํ•ต์‹ฌ ๊ฐœ๋…

spring.jpa.hibernate.ddl-auto ์˜ต์…˜:

์˜ต์…˜๋™์ž‘
create์‹œ์ž‘ ์‹œ ๊ธฐ์กด ํ…Œ์ด๋ธ” ์‚ญ์ œ + ์ƒˆ๋กœ ์ƒ์„ฑ
create-dropcreate + ์ข…๋ฃŒ ์‹œ ์‚ญ์ œ
update๋ณ€๊ฒฝ ์‚ฌํ•ญ๋งŒ ๋ฐ˜์˜ (์•ˆ์ „ํ•˜์ง€ ์•Š์Œ)
validate์Šคํ‚ค๋งˆ ๋งคํ•‘๋งŒ ๊ฒ€์ฆ (๋ณ€๊ฒฝ ์—†์Œ)
none์ž๋™ ์ฒ˜๋ฆฌ ์•ˆ ํ•จ

โš ๏ธ ์šด์˜ ํ™˜๊ฒฝ ์ ˆ๋Œ€ ๊ธˆ์ง€ โญ :

  • create, create-drop, update โ†’ ๋ฐ์ดํ„ฐ ์†์‹ค ์œ„ํ—˜

๊ฐœ๋ฐœ ๋‹จ๊ณ„๋ณ„ ๊ถŒ์žฅ:

  • ๋กœ์ปฌ: create ๋˜๋Š” update
  • ์Šคํ…Œ์ด์ง•: validate
  • ํ”„๋กœ๋•์…˜: none (Flyway/Liquibase ์‚ฌ์šฉ)

SQL ๋ถ„๋ฅ˜ ์ฐธ๊ณ :

๋ถ„๋ฅ˜์˜๋ฏธ๋ช…๋ น
DDL (Data Definition Language)๊ณจ๊ฒฉ ์ •์˜CREATE, ALTER, DROP, TRUNCATE
DML (Data Manipulation Language)๋ฐ์ดํ„ฐ ์กฐ์ž‘SELECT, INSERT, UPDATE, DELETE
DCL (Data Control Language)๊ถŒํ•œยทํŠธ๋žœ์žญ์…˜GRANT, REVOKE, COMMIT, ROLLBACK

์ž๊ธฐ ์ ๊ฒ€

  • ์šด์˜์—์„œ ddl-auto=update๊ฐ€ ์œ„ํ—˜ํ•œ ์ด์œ  3๊ฐ€์ง€๋Š”?
  • ILIC์˜ 102๊ฐœ ํ…Œ์ด๋ธ”์„ ์šด์˜ ํ™˜๊ฒฝ์—์„œ ์–ด๋–ป๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒŒ ์ข‹์„๊นŒ? (ํžŒํŠธ: Flyway)

๐Ÿ“š Phase 4 โ€” EntityManager์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

๋ชฉํ‘œ: JPA์˜ ํ•ต์‹ฌ ๋ฉ”์ปค๋‹ˆ์ฆ˜ โ€” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ์ •์ฒด์™€ ์—”ํ‹ฐํ‹ฐ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์ดํ•ดํ•œ๋‹ค.

Unit 4.1 โ€” EntityManagerFactory (์‹ฑ๊ธ€ํ†ค)

์„ ์ˆ˜ ์ง€์‹: Phase 1, 2

ํ•ต์‹ฌ ๊ฐœ๋…

EntityManagerFactory (EMF):

  • EntityManager๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํŒฉํ† ๋ฆฌ
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์—์„œ 1๊ฐœ๋งŒ ์กด์žฌ (์‹ฑ๊ธ€ํ†ค)
  • ์ƒ์„ฑ ๋น„์šฉ์ด ํฌ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑ

Spring Boot์—์„œ์˜ ๋™์ž‘:

  • @SpringBootApplication ์‹คํ–‰ ์‹œ ์ž๋™ ์ƒ์„ฑ
  • ๋นˆ์œผ๋กœ ๋“ฑ๋ก โ†’ DI ๊ฐ€๋Šฅ
  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ข…๋ฃŒ๊นŒ์ง€ ์œ ์ง€

์ž๋ฐ” ํ‘œ์ค€ ์‚ฌ์šฉ (์ฐธ๊ณ ):

EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-pu");

Spring ํ™˜๊ฒฝ (์‹ค๋ฌด):

@PersistenceUnit
private EntityManagerFactory emf;  // ์ž๋™ ์ฃผ์ž…

์ž๊ธฐ ์ ๊ฒ€

  • EntityManagerFactory๊ฐ€ ์‹ฑ๊ธ€ํ†ค์ธ ์ด์œ ๋Š”?
  • Spring Boot๊ฐ€ EMF๋ฅผ ์ž๋™ ๋“ฑ๋กํ•˜๋Š” ์‹œ์ ์€? (ํžŒํŠธ: ์ปจํ…์ŠคํŠธ ์ดˆ๊ธฐํ™”)

Unit 4.2 โ€” EntityManager (ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„)

์„ ์ˆ˜ ์ง€์‹: Unit 4.1, 7์ฃผ์ฐจ Phase 7

ํ•ต์‹ฌ ๊ฐœ๋…

EntityManager (EM):

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค
  • ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„๋กœ ์ƒ์„ฑยท์†Œ๋ฉธ

Spring + @Transactional ์กฐํ•ฉ:

  • ํŠธ๋žœ์žญ์…˜ ์‹œ์ž‘ ์‹œ EM ์ž๋™ ์ƒ์„ฑ
  • ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ ์‹œ EM ์ž๋™ ๋‹ซํž˜
  • ๊ฐœ๋ฐœ์ž๋Š” ์ง์ ‘ ๋‹ซ์„ ํ•„์š” X

ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ:

  • persist(entity): ์˜์†ํ™” (์ €์žฅ)
  • find(Class, id): ์กฐํšŒ (1์ฐจ ์บ์‹œ ํ™œ์šฉ)
  • getReference(Class, id): ํ”„๋ก์‹œ ๋ฐ˜ํ™˜ (Phase 8)
  • remove(entity): ์‚ญ์ œ
  • merge(entity): ์ค€์˜์† โ†’ ์˜์†
  • detach(entity): ์˜์† โ†’ ์ค€์˜์†

์ค‘์š” โ€” ์Šค๋ ˆ๋“œ ์•ˆ์ „ X:

"EntityManager๋Š” ๊ณต์œ  X โ€” ํŠธ๋žœ์žญ์…˜๋งˆ๋‹ค ๋ณ„๋„ ์ธ์Šคํ„ด์Šค"

์ด๊ฒŒ EntityManagerFactory(์‹ฑ๊ธ€ํ†ค)์™€์˜ ๊ฒฐ์ •์  ์ฐจ์ด.

์ž๊ธฐ ์ ๊ฒ€

  • ํ•œ EntityManager๋ฅผ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ์“ฐ๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€?
  • @Transactional ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ EM์„ ์ง์ ‘ close()ํ•˜๋ฉด? (ํžŒํŠธ: ํ•˜์ง€ ๋งˆ๋ผ)

Unit 4.3 โ€” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์ •์˜

์„ ์ˆ˜ ์ง€์‹: Unit 4.2

ํ•ต์‹ฌ ๊ฐœ๋…

"์—”ํ‹ฐํ‹ฐ ๋งค๋‹ˆ์ € ๋‚ด๋ถ€์—์„œ ๋™์ž‘ํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„ โ€” ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ณด๊ด€ํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๊ณณ"

์œ„์น˜:

EntityManager
   โ””โ”€โ”€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ (Persistence Context)
         โ””โ”€โ”€ 1์ฐจ ์บ์‹œ (์—”ํ‹ฐํ‹ฐ ๋ณด๊ด€)

์—ญํ• :

  • ์—”ํ‹ฐํ‹ฐ์˜ ์ƒ๋ช…์ฃผ๊ธฐ ๊ด€๋ฆฌ
  • 1์ฐจ ์บ์‹œ ์ œ๊ณต
  • ๋ณ€๊ฒฝ ๊ฐ์ง€ (Dirty Checking)
  • ์“ฐ๊ธฐ ์ง€์—ฐ

์ค‘์š” ํ†ต์ฐฐ:

"JPA์˜ ๋ชจ๋“  ์‹ ๊ธฐํ•œ ๋™์ž‘์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์•ˆ์—์„œ ์ผ์–ด๋‚œ๋‹ค"

์ด๊ฒŒ Phase 5์—์„œ ์„ค๋ช…ํ•  4๊ฐ€์ง€ ์žฅ์ ์˜ ์ถœ๋ฐœ์ .

์ž๊ธฐ ์ ๊ฒ€

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์™€ 1์ฐจ ์บ์‹œ๋Š” ๊ฐ™์€ ๊ฒƒ์ธ๊ฐ€? (ํžŒํŠธ: 1์ฐจ ์บ์‹œ๋Š” ์ผ๋ถ€)
  • EntityManager๊ฐ€ ๋‹ซํžˆ๋ฉด ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋Š” ์–ด๋–ป๊ฒŒ ๋˜๋Š”๊ฐ€?

Unit 4.4 โ€” ์—”ํ‹ฐํ‹ฐ ์ƒ๋ช…์ฃผ๊ธฐ (๋น„์˜์†/์˜์†/์ค€์˜์†/์‚ญ์ œ)

์„ ์ˆ˜ ์ง€์‹: Unit 4.3

ํ•ต์‹ฌ 4๊ฐ€์ง€ ์ƒํƒœ โญ :

new        โ”€persist()โ”€โ”€> [์˜์†(Managed)] โ”€โ”€remove()โ”€โ”€> [์‚ญ์ œ(Removed)]
[๋น„์˜์†]                       โ”‚
(Transient)                    โ”‚ detach()
                               โ”‚ close()
                               โ”‚ clear()
                               โ†“
                       [์ค€์˜์†(Detached)]
                               โ”‚
                               โ”‚ merge()
                               โ†“
                          [์˜์†(Managed)]

4๊ฐ€์ง€ ์ƒํƒœ ์ž์„ธํžˆ:

์ƒํƒœ์ •์˜์˜์†์„ฑ ์ปจํ…์ŠคํŠธDB
๋น„์˜์†(Transient)new๋กœ ์ƒ์„ฑ, ์˜์†ํ™” XโŒโŒ
์˜์†(Managed)persist ๋˜๋Š” find๋กœ ๊ด€๋ฆฌ ์ค‘โœ…(์ปค๋ฐ‹ ์‹œ ๋ฐ˜์˜)
์ค€์˜์†(Detached)์˜์†์ด์—ˆ์œผ๋‚˜ ๋ถ„๋ฆฌ๋จโŒ(์ด์ „ ๋ฐ์ดํ„ฐ ์กด์žฌ)
์‚ญ์ œ(Removed)remove๋กœ ์‚ญ์ œ ์˜ˆ์ •โœ… (์ œ๊ฑฐ ํ‘œ์‹œ)(์ปค๋ฐ‹ ์‹œ ์‚ญ์ œ)

์ƒํƒœ ๋ณ€๊ฒฝ ๋ฉ”์„œ๋“œ:

  • persist(entity): ๋น„์˜์† โ†’ ์˜์†
  • find(Class, id): โ†’ ์˜์†
  • remove(entity): ์˜์† โ†’ ์‚ญ์ œ
  • detach(entity): ์˜์† โ†’ ์ค€์˜์† (๊ฐœ๋ณ„)
  • clear(): ๋ชจ๋“  ์˜์† โ†’ ์ค€์˜์†
  • close(): EM ์ข…๋ฃŒ โ†’ ๋ชจ๋‘ ์ค€์˜์†
  • merge(entity): ์ค€์˜์† โ†’ ์˜์†

์ค‘์š”ํ•œ ์ฐจ์ด โญ :

  • detach(): ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์—์„œ๋งŒ ๋ถ„๋ฆฌ โ€” DB๋Š” ๊ทธ๋Œ€๋กœ
  • remove(): DB์—์„œ๋„ ์‚ญ์ œ (์ปค๋ฐ‹ ์‹œ)

์ž๊ธฐ ์ ๊ฒ€

  • ๋น„์˜์† ์—”ํ‹ฐํ‹ฐ์— setter๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด DB์— ๋ฐ˜์˜๋˜๋Š”๊ฐ€? (ํžŒํŠธ: NO)
  • detach()์™€ close()์˜ ์ฐจ์ด๋Š”? (ํžŒํŠธ: ๋ฒ”์œ„)

๐Ÿ“š Phase 5 โ€” ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ 4๊ฐ€์ง€ ์žฅ์  (โ˜… 11์ฃผ์ฐจ ์ •์ )

๋ชฉํ‘œ: JPA๊ฐ€ ์™œ ๊ฐ•๋ ฅํ•œ์ง€๋ฅผ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ 4๊ฐ€์ง€ ๋™์ž‘ ๋ฉ”์ปค๋‹ˆ์ฆ˜์œผ๋กœ ์ดํ•ดํ•œ๋‹ค. ๋ฉด์ ‘ยท์‹ค๋ฌด ๋‹จ๊ณจ.

Unit 5.1 โ€” 1์ฐจ ์บ์‹œ

์„ ์ˆ˜ ์ง€์‹: Phase 4

ํ•ต์‹ฌ ๊ฐœ๋…

1์ฐจ ์บ์‹œ:

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋‚ด๋ถ€์˜ ์—”ํ‹ฐํ‹ฐ ์ €์žฅ ๊ณต๊ฐ„
  • ๊ฐ™์€ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ DB ์กฐํšŒ ํšŒํ”ผ

๋™์ž‘ ํ๋ฆ„:

EntityManager em = emf.createEntityManager();
User user1 = em.find(User.class, 1L);  // โ‘  DB ์กฐํšŒ + 1์ฐจ ์บ์‹œ ์ €์žฅ
User user2 = em.find(User.class, 1L);  // โ‘ก 1์ฐจ ์บ์‹œ์—์„œ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ (SQL ์‹คํ–‰ X)

1์ฐจ ์บ์‹œ์˜ 6๋‹จ๊ณ„:
1. ์ฒซ ์กฐํšŒ: 1์ฐจ ์บ์‹œ ๋น„์–ด์žˆ์Œ
2. DB์—์„œ ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ
3. 1์ฐจ ์บ์‹œ์— ์ €์žฅ
4. ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
5. ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ ์žฌ์กฐํšŒ ์‹œ 1์ฐจ ์บ์‹œ์—์„œ ๋ฐ˜ํ™˜
6. ๊ฐ์ฒด ๋™์ผ์„ฑ (==) ๋ณด์žฅ

๋ฒ”์œ„:

  • ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„ (EntityManager ์ƒ๋ช… ์ฃผ๊ธฐ์™€ ๊ฐ™์Œ)
  • ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ ์‹œ 1์ฐจ ์บ์‹œ๋„ ์‚ฌ๋ผ์ง

์ž๊ธฐ ์ ๊ฒ€

  • 1์ฐจ ์บ์‹œ๊ฐ€ ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„์ธ ์ด์œ ๋Š”?
  • ILIC์˜ ๋™์ผ ํŠธ๋žœ์žญ์…˜์—์„œ ๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ 5๋ฒˆ ์กฐํšŒ ์‹œ SQL์€ ๋ช‡ ๋ฒˆ ์‹คํ–‰๋˜๋Š”๊ฐ€?

Unit 5.2 โ€” ๋™์ผ์„ฑ ๋ณด์žฅ

์„ ์ˆ˜ ์ง€์‹: Unit 5.1

ํ•ต์‹ฌ ๊ฐœ๋…

User user1 = em.find(User.class, 1L);
User user2 = em.find(User.class, 1L);
System.out.println(user1 == user2);  // true!

์™œ ๊ฐ€๋Šฅํ•œ๊ฐ€:

  • 1์ฐจ ์บ์‹œ์—์„œ ๊ฐ™์€ ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜
  • โ†’ ๊ฐ์ฒด ๋™์ผ์„ฑ(==) ๋ณด์žฅ

๊ฐ์ฒด ๋™๋“ฑ์„ฑ vs ๋™์ผ์„ฑ:

  • ๋™๋“ฑ์„ฑ(equals): ๊ฐ’์ด ๊ฐ™์Œ
  • ๋™์ผ์„ฑ(==): ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ฐ™์Œ

JPA๋Š” ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ๋™์ผ์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

์˜์˜:

  • "๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ๋Š” ๊ฐ™์€ ๊ฐ์ฒด" ๋ผ๋Š” ๊ฐ์ฒด์ง€ํ–ฅ์  ์ง๊ด€ ์œ ์ง€
  • DB ํ–‰ = ์ž๋ฐ” ๊ฐ์ฒด ๋ผ๋Š” 1:1 ๋งคํ•‘

์ž๊ธฐ ์ ๊ฒ€

  • ๋‹ค๋ฅธ ํŠธ๋žœ์žญ์…˜์—์„œ ์กฐํšŒํ•œ ๊ฐ™์€ ID์˜ ์—”ํ‹ฐํ‹ฐ๋Š” == ๋น„๊ต๊ฐ€ true์ผ๊นŒ? (ํžŒํŠธ: NO)
  • equals/hashCode๋ฅผ ์—”ํ‹ฐํ‹ฐ์— ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š”๊ฐ€? (ํžŒํŠธ: ID ๊ธฐ๋ฐ˜)

Unit 5.3 โ€” ์“ฐ๊ธฐ ์ง€์—ฐ

์„ ์ˆ˜ ์ง€์‹: Unit 5.2

ํ•ต์‹ฌ ๊ฐœ๋…

์“ฐ๊ธฐ ์ง€์—ฐ(Write-Behind):

  • persist() ํ˜ธ์ถœ ์‹œ ์ฆ‰์‹œ INSERT ์•ˆ ํ•จ
  • ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— ํ•œ๊บผ๋ฒˆ์— SQL ์‹คํ–‰

์˜ˆ์‹œ:

em.getTransaction().begin();

em.persist(memberA);  // INSERT SQL ์•ˆ ๋ณด๋ƒ„
em.persist(memberB);  // INSERT SQL ์•ˆ ๋ณด๋ƒ„
em.persist(memberC);  // INSERT SQL ์•ˆ ๋ณด๋ƒ„
// ์—ฌ๊ธฐ๊นŒ์ง€ DB๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ชจ๋ฆ„

em.getTransaction().commit();
// โ†’ ์ปค๋ฐ‹ ์ง์ „์— INSERT SQL 3๊ฐœ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ๋ณด๋ƒ„!

๋‚ด๋ถ€ ๋™์ž‘:

  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ์•ˆ์— SQL ์ €์žฅ์†Œ ์กด์žฌ
  • persist ์‹œ SQL์„ ์ €์žฅ์†Œ์—๋งŒ ๋ชจ์Œ
  • commit ์‹œ ๋ชจ๋“  SQL์„ DB์— ์ „์†ก

ํšจ๊ณผ:

  • ๋ฐฐ์น˜ ์ฒ˜๋ฆฌ ์ตœ์ ํ™” ๊ฐ€๋Šฅ (Hibernate ์„ค์ •์œผ๋กœ batch ์‚ฌ์ด์ฆˆ ์กฐ์ •)
  • ๋„คํŠธ์›Œํฌ ์™•๋ณต โ†“
  • ์„ฑ๋Šฅ โ†‘

์ž๊ธฐ ์ ๊ฒ€

  • ์“ฐ๊ธฐ ์ง€์—ฐ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š”? (ํžŒํŠธ: IDENTITY ์ „๋žต โ€” 7์ฃผ์ฐจ Phase 4)
  • 100๊ฐœ INSERT๋ฅผ 1๋ฒˆ์˜ ๋„คํŠธ์›Œํฌ ํ˜ธ์ถœ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ์˜ต์…˜์€? (ํžŒํŠธ: hibernate.jdbc.batch_size)

Unit 5.4 โ€” ๋ณ€๊ฒฝ ๊ฐ์ง€ (Dirty Checking) โญโญโญ

์„ ์ˆ˜ ์ง€์‹: Unit 5.3

ํ•ต์‹ฌ ๊ฐœ๋… โ€” JPA์˜ ๊ฐ€์žฅ ์‹ ๊ธฐํ•œ ๋™์ž‘

em.getTransaction().begin();

Member member = em.find(Member.class, 1L);  // ์˜์† ์ƒํƒœ
member.setUsername("hi");  // setter ํ˜ธ์ถœ๋งŒ!
member.setAge(10);

em.getTransaction().commit();
// โ†’ UPDATE ์ฟผ๋ฆฌ ์ž๋™ ์‹คํ–‰!

em.update() ํ˜ธ์ถœ X. setter๋งŒ ํ˜ธ์ถœํ–ˆ๋Š”๋ฐ UPDATE ๊ฐ€ ์ผ์–ด๋‚ฌ๋‹ค.

๋‚ด๋ถ€ ๋™์ž‘ โ€” ์Šค๋ƒ…์ƒท ๋น„๊ต:
1. ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ค์–ด์˜ฌ ๋•Œ ์Šค๋ƒ…์ƒท ์ €์žฅ (1์ฐจ ์บ์‹œ ์˜†)
2. setter ํ˜ธ์ถœ โ†’ ์—”ํ‹ฐํ‹ฐ ๋ณ€๊ฒฝ
3. ์ปค๋ฐ‹ ์‹œ์ ์— ์Šค๋ƒ…์ƒท๊ณผ ํ˜„์žฌ ์—”ํ‹ฐํ‹ฐ ๋น„๊ต
4. ์ฐจ์ด๊ฐ€ ์žˆ์œผ๋ฉด โ†’ UPDATE SQL ์ž๋™ ์ƒ์„ฑ
5. ์“ฐ๊ธฐ ์ง€์—ฐ ์ €์žฅ์†Œ์— ์ถ”๊ฐ€
6. DB ๋ฐ˜์˜

๋น„๊ต ํ๋ฆ„:

[์กฐํšŒ ์‹œ์ ]                     [์ปค๋ฐ‹ ์‹œ์ ]
์—”ํ‹ฐํ‹ฐ: {name: "A", age: 20}    ์—”ํ‹ฐํ‹ฐ: {name: "B", age: 25}
์Šค๋ƒ…์ƒท: {name: "A", age: 20}    ์Šค๋ƒ…์ƒท: {name: "A", age: 20}
                                       โ†“
                               [์ฐจ์ด ๊ฒ€์ถœ] โ†’ UPDATE SQL ์ƒ์„ฑ

์ค‘์š”ํ•œ ํ•จ์ •:

  • ์ค€์˜์† ์—”ํ‹ฐํ‹ฐ๋Š” ๋ณ€๊ฒฝ ๊ฐ์ง€ X โ€” merge() ๋˜๋Š” ๋‹ค์‹œ ์˜์†ํ™” ํ•„์š”
  • ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ ๋ฐ–์—์„œ ๋ณ€๊ฒฝํ•œ ๊ฐ’์€ ์ž๋™ ๋ฐ˜์˜ ์•ˆ ๋จ

์ž๊ธฐ ์ ๊ฒ€

  • "๋ณ€๊ฒฝ ๊ฐ์ง€"๊ฐ€ ์ž‘๋™ํ•˜๋Š” ์ „์ œ ์กฐ๊ฑด์€?
  • ๋ช…์‹œ์ ์œผ๋กœ ๋ณ€๊ฒฝ ๊ฐ์ง€๋ฅผ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด? (ํžŒํŠธ: Hibernate.unproxy(), readOnly)

Unit 5.5 โ€” ํ”Œ๋Ÿฌ์‹œ + 2์ฐจ ์บ์‹œ ๋ณด๋„ˆ์Šค

์„ ์ˆ˜ ์ง€์‹: Unit 5.4

ํ”Œ๋Ÿฌ์‹œ(Flush):

"์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ DB์— ๋ฐ˜์˜ํ•˜๋Š” ์‹œ์ "

ํ”Œ๋Ÿฌ์‹œ ๋ฐœ์ƒ 3๊ฐ€์ง€ ์‹œ์ :
1. em.flush() ์ง์ ‘ ํ˜ธ์ถœ
2. ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์ง์ „ (์ž๋™)
3. JPQL ์ฟผ๋ฆฌ ์‹คํ–‰ ์ง์ „ (์ž๋™)

3๋ฒˆ์ด ์ค‘์š”ํ•œ ์ด์œ :

  • ๋ณ€๊ฒฝ ๊ฐ์ง€๋กœ ๋ฉ”๋ชจ๋ฆฌ์—๋งŒ ์žˆ๋Š” ๋ณ€๊ฒฝ์„
  • JPQL ์‹คํ–‰ ์ „ DB์— ๋ฐ˜์˜ํ•ด์•ผ ์ผ๊ด€๋œ ๊ฒฐ๊ณผ

ํ”Œ๋Ÿฌ์‹œ โ‰  ์ปค๋ฐ‹:

  • ํ”Œ๋Ÿฌ์‹œ: SQL์„ DB๋กœ ์ „์†ก (๋ฉ”๋ชจ๋ฆฌ โ†’ DB ๋™๊ธฐํ™”)
  • ์ปค๋ฐ‹: ํŠธ๋žœ์žญ์…˜ ์ข…๋ฃŒ (์˜๊ตฌ ๋ฐ˜์˜)
  • โ†’ flush ํ›„์—๋„ rollback ๊ฐ€๋Šฅ

2์ฐจ ์บ์‹œ (๋ณด๋„ˆ์Šค):

  • ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์—ญ ์บ์‹œ (1์ฐจ ์บ์‹œ๋Š” ํŠธ๋žœ์žญ์…˜ ๋‹จ์œ„)
  • ์—ฌ๋Ÿฌ ํŠธ๋žœ์žญ์…˜์ด ๊ณต์œ 
  • ๋ณ„๋„ ์„ค์ • ํ•„์š” (Ehcache, Redis, Hazelcast)

์™œ ๋ณต์‚ฌ๋ณธ์„ ๋ฐ˜ํ™˜ํ•˜๋Š”๊ฐ€:

  • ์บ์‹œ๋œ ๊ฐ์ฒด๋ฅผ ์ง์ ‘ ๋ฐ˜ํ™˜ โ†’ ๋™์‹œ์„ฑ ์ถฉ๋Œ
  • โ†’ ํŠธ๋žœ์žญ์…˜๋งˆ๋‹ค ๋…๋ฆฝ ๋ณต์‚ฌ๋ณธ ๋ฐ˜ํ™˜

1์ฐจ vs 2์ฐจ ์บ์‹œ:

1์ฐจ ์บ์‹œ2์ฐจ ์บ์‹œ
๋ฒ”์œ„ํŠธ๋žœ์žญ์…˜์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์—ญ
๊ธฐ๋ณธ ์ œ๊ณตโœ…โŒ (๋ณ„๋„ ์„ค์ •)
๊ฐ์ฒด ๋ฐ˜ํ™˜๊ฐ™์€ ์ธ์Šคํ„ด์Šค๋ณต์‚ฌ๋ณธ
๋™์‹œ์„ฑ์•ˆ์ „๋ณต์‚ฌ๋ณธ์œผ๋กœ ๊ฒฉ๋ฆฌ

์ž๊ธฐ ์ ๊ฒ€

  • JPQL ์‹คํ–‰ ์ „ ์ž๋™ ํ”Œ๋Ÿฌ์‹œ๊ฐ€ ์ผ์–ด๋‚˜๋Š” ์ด์œ ๋Š”?
  • ILIC์—์„œ 2์ฐจ ์บ์‹œ๋ฅผ ๋„์ž…ํ•œ๋‹ค๋ฉด ์–ด๋–ค ๋ฐ์ดํ„ฐ๊ฐ€ ์ ํ•ฉํ•œ๊ฐ€? (ํžŒํŠธ: ๋งˆ์Šคํ„ฐ ๋ฐ์ดํ„ฐ, ๋ณ€๊ฒฝ ์ ์Œ)

โšก Part B โ€” 12์ฃผ์ฐจ: ์—ฐ๊ด€๊ด€๊ณ„์™€ ์„ฑ๋Šฅ ์ตœ์ ํ™”

๐Ÿ“š Phase 6 โ€” JPA ์—ฐ๊ด€๊ด€๊ณ„ 4๊ฐ€์ง€

๋ชฉํ‘œ: ๊ฐ์ฒด ์ฐธ์กฐ์™€ ์™ธ๋ž˜ ํ‚ค๋ฅผ ์–ด๋–ป๊ฒŒ ๋งคํ•‘ํ•˜๋Š”์ง€ 4๊ฐ€์ง€ ๊ด€๊ณ„๋กœ ์ •๋ฆฌํ•œ๋‹ค.

Unit 6.1 โ€” ์—ฐ๊ด€๊ด€๊ณ„์˜ ๋ถ„๋ฅ˜ + ๋‹จ๋ฐฉํ–ฅ vs ์–‘๋ฐฉํ–ฅ

์„ ์ˆ˜ ์ง€์‹: Phase 5

ํ•ต์‹ฌ ๊ฐœ๋…

4๊ฐ€์ง€ ์—ฐ๊ด€๊ด€๊ณ„:

  • 1:1 (@OneToOne)
  • N:1 (@ManyToOne) โ€” ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ โญ
  • 1:N (@OneToMany)
  • N:M (@ManyToMany) โ€” ์‹ค๋ฌด์—์„œ ์ž˜ ์•ˆ ์”€

๋‹จ๋ฐฉํ–ฅ vs ์–‘๋ฐฉํ–ฅ:

  • ๋‹จ๋ฐฉํ–ฅ: ํ•œ ์—”ํ‹ฐํ‹ฐ์—์„œ๋งŒ ๋‹ค๋ฅธ ์—”ํ‹ฐํ‹ฐ ์ฐธ์กฐ (A โ†’ B)
  • ์–‘๋ฐฉํ–ฅ: ์–‘์ชฝ์ด ์„œ๋กœ ์ฐธ์กฐ (A โ†” B)

ํ•ต์‹ฌ ํ†ต์ฐฐ:

"์–‘๋ฐฉํ–ฅ์€ ์‚ฌ์‹ค ๋‹จ๋ฐฉํ–ฅ 2๊ฐœ"

๊ฐ์ฒด ์ž…์žฅ: A โ†’ B ์™€ B โ†’ A ์˜ ๋‘ ์ฐธ์กฐ

DB ์ž…์žฅ: ์™ธ๋ž˜ ํ‚ค 1๊ฐœ๋กœ ์ถฉ๋ถ„

โ†’ ๊ทธ๋ž˜์„œ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ ๊ฐœ๋…์ด ๋“ฑ์žฅ (Phase 7)

์ž๊ธฐ ์ ๊ฒ€

  • ์–‘๋ฐฉํ–ฅ์ด ๊ฐ์ฒด ์ž…์žฅ์—์„œ๋Š” ์ž์—ฐ์Šค๋Ÿฌ์šด๋ฐ DB ์ž…์žฅ์—์„œ๋Š” ์™œ ๊ทธ๋ ‡์ง€ ์•Š์€๊ฐ€?
  • ๋‹จ๋ฐฉํ–ฅ๋งŒ์œผ๋กœ ์ถฉ๋ถ„ํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š”? (ํžŒํŠธ: ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒฝ์šฐ)

Unit 6.2 โ€” 1:1 (OneToOne) ๋งคํ•‘

์„ ์ˆ˜ ์ง€์‹: Unit 6.1

ํ•ต์‹ฌ ๊ฐœ๋…

์–ธ์ œ ์‚ฌ์šฉ:

  • ํšŒ์› โ†’ ์‚ฌ๋ฌผํ•จ
  • ์‚ฌ์šฉ์ž โ†’ ํ”„๋กœํ•„
  • ๋ถ€๊ฐ€ ์ •๋ณด

FK ์œ„์น˜ ๊ฒฐ์ •:

  • ์ž์ฃผ ์กฐํšŒ๋˜๋Š” ์ชฝ์— FK ๊ถŒ์žฅ
  • ํšŒ์›์ด ์‚ฌ๋ฌผํ•จ์„ ์ž์ฃผ ์กฐํšŒ โ†’ ํšŒ์›์— FK

๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘:

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    
    @OneToOne
    @JoinColumn(name = "locker_id")  // FK๋Š” Member ํ…Œ์ด๋ธ”์—
    private Locker locker;
}

@Entity
public class Locker {
    @Id @GeneratedValue
    private Long id;
}

์–‘๋ฐฉํ–ฅ ๋งคํ•‘:

@Entity
public class Locker {
    @Id @GeneratedValue
    private Long id;
    
    @OneToOne(mappedBy = "locker")  // ์ฃผ์ธ์ด ์•„๋‹˜
    private Member member;
}

์ž๊ธฐ ์ ๊ฒ€

  • 1:1์„ 1:N๊ณผ ๊ตฌ๋ถ„ ์ง“๋Š” ๋ช…ํ™•ํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๊ทœ์น™์€?
  • FK๋ฅผ ์–‘์ชฝ ์–ด๋””์— ๋‘๋“  ๊ฒฐ๊ณผ๋Š” ๊ฐ™์€๊ฐ€? (ํžŒํŠธ: ์„ฑ๋Šฅ ์ฐจ์ด ์žˆ์Œ)

Unit 6.3 โ€” N:1 (ManyToOne) โ€” ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ โญ

์„ ์ˆ˜ ์ง€์‹: Unit 6.2

ํ•ต์‹ฌ ๊ฐœ๋…

๊ฐ€์žฅ ์ž์ฃผ ๋“ฑ์žฅํ•˜๋Š” ๊ด€๊ณ„:

  • ํšŒ์›(N) โ†’ ํŒ€(1)
  • ์ฃผ๋ฌธ(N) โ†’ ํšŒ์›(1)
  • ๋Œ“๊ธ€(N) โ†’ ๊ฒŒ์‹œ๊ธ€(1)

FK ์œ„์น˜:

  • N(๋‹ค์ˆ˜) ์ชฝ์— FK ์œ„์น˜ โ† ์ž์—ฐ์Šค๋Ÿฌ์›€
  • โ†’ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์€ @ManyToOne โญ
@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)  // ์ง€์—ฐ ๋กœ๋”ฉ ๊ถŒ์žฅ!
    @JoinColumn(name = "team_id")  // FK๋Š” Member์—
    private Team team;
}

@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
}

โš ๏ธ ์ฃผ์˜ ์‚ฌํ•ญ:
1. FK๋Š” N์ชฝ์— โ€” ํ•ญ์ƒ
2. fetch = FetchType.LAZY ๊ถŒ์žฅ โ€” N+1 ๋ฐฉ์ง€ (Phase 9)
3. ์ž˜๋ชป๋œ ์–‘๋ฐฉํ–ฅ ์„ค์ • ์‹œ ๋ฌดํ•œ ๋ฃจํ”„ โ€” toString, JSON ์ง๋ ฌํ™” ์‹œ

์ž๊ธฐ ์ ๊ฒ€

  • @ManyToOne ์˜ ๊ธฐ๋ณธ fetch ์ „๋žต์€? (ํžŒํŠธ: EAGER โ€” ์œ„ํ—˜!)
  • ์™œ LAZY๋กœ ๋ช…์‹œํ•ด์•ผ ํ•˜๋Š”๊ฐ€?

Unit 6.4 โ€” 1:N (OneToMany)

์„ ์ˆ˜ ์ง€์‹: Unit 6.3

ํ•ต์‹ฌ ๊ฐœ๋…

๋ณดํ†ต ์–‘๋ฐฉํ–ฅ์—์„œ N:1 + 1:N ์กฐํ•ฉ์œผ๋กœ ์‚ฌ์šฉ:

  • N:1 ์ชฝ์ด ์ฃผ์ธ (FK ๊ด€๋ฆฌ)
  • 1:N ์ชฝ์€ mappedBy (์ฝ๊ธฐ ์ „์šฉ)
@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
    
    @OneToMany(mappedBy = "team")  // ์ฃผ์ธ์ด ์•„๋‹˜!
    private List<Member> members = new ArrayList<>();
}

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "team_id")  // ์ฃผ์ธ (FK ๊ด€๋ฆฌ)
    private Team team;
}

@OneToMany ๊ฐ€ ์ฃผ์ธ์ด ๋˜๋Š” ๊ฒฝ์šฐ๋Š”?:

  • ๋น„์ถ”์ฒœ (์ถ”๊ฐ€ UPDATE ์ฟผ๋ฆฌ ๋ฐœ์ƒ)
  • ๋‹จ๋ฐฉํ–ฅ๋งŒ ํ•„์š”ํ•  ๋•Œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

โš ๏ธ ์ฃผ์˜ ์‚ฌํ•ญ:

  • mappedBy ์—†์œผ๋ฉด โ†’ ์กฐ์ธ ํ…Œ์ด๋ธ” ์ž๋™ ์ƒ์„ฑ (๋น„ํšจ์œจ)
  • ํ•ญ์ƒ @ManyToOne ์ชฝ์ด ์ฃผ์ธ์ด์–ด์•ผ ํ•จ

์ž๊ธฐ ์ ๊ฒ€

  • @OneToMany๋ฅผ ์ฃผ์ธ์œผ๋กœ ๋งŒ๋“ค๋ฉด ์ถ”๊ฐ€ UPDATE๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š”?
  • 'mappedBy = "team"' ์˜ "team"์€ ์–ด๋””๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š”๊ฐ€? (ํžŒํŠธ: Member ์—”ํ‹ฐํ‹ฐ์˜ ํ•„๋“œ๋ช…)

Unit 6.5 โ€” N:M (ManyToMany) โ€” ์ค‘๊ฐ„ ์—”ํ‹ฐํ‹ฐ ํŒจํ„ด โญ

์„ ์ˆ˜ ์ง€์‹: Unit 6.4

ํ•ต์‹ฌ ๊ฐœ๋…

N:M์˜ ์ง์ ‘ ์‚ฌ์šฉ โ€” ๋น„์ถ”์ฒœ:

@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT")
private List<Product> products = new ArrayList<>();

์™œ ์•ˆ ์ข‹์€๊ฐ€:

  • ์ž๋™ ์กฐ์ธ ํ…Œ์ด๋ธ”์— ๋ถ€๊ฐ€ ์ •๋ณด ์ถ”๊ฐ€ ๋ถˆ๊ฐ€
  • ๋“ฑ๋ก์ผ, ์ƒํƒœ, ์ˆ˜๋Ÿ‰ ๋“ฑ ๋ชป ๋„ฃ์Œ
  • โ†’ ์‹ค๋ฌด์—์„œ ๊ฑฐ์˜ ์•ˆ ์”€

์ค‘๊ฐ„ ์—”ํ‹ฐํ‹ฐ ํŒจํ„ด (์‹ค๋ฌด ํ‘œ์ค€):

@Entity
public class MemberProduct {  // ๋˜๋Š” Order๋กœ ์ด๋ฆ„ ๋ณ€๊ฒฝ
    @Id @GeneratedValue
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
    
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
    
    private int amount;          // ๋ถ€๊ฐ€ ์ •๋ณด!
    private int price;           // ๋ถ€๊ฐ€ ์ •๋ณด!
    private LocalDateTime orderDateTime;  // ๋ถ€๊ฐ€ ์ •๋ณด!
}

์›์น™:

"N:M์€ ํ•ญ์ƒ 1:N + N:1๋กœ ํ’€์–ด๋ผ"

์˜๋ฏธ ๋ถ€์—ฌ:

  • MemberProduct โ†’ Order ๊ฐ™์ด ๋น„์ฆˆ๋‹ˆ์Šค ์˜๋ฏธ ์žˆ๋Š” ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝ
  • ๋‹จ์ˆœ ์—ฐ๊ฒฐ ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ๋„๋ฉ”์ธ ์—”ํ‹ฐํ‹ฐ๋กœ ๊ฒฉ์ƒ

์ž๊ธฐ ์ ๊ฒ€

  • ILIC์—์„œ N:M๋กœ ํ‘œํ˜„ํ•˜๊ณ  ์‹ถ์ง€๋งŒ ์ค‘๊ฐ„ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋” ๋‚˜์€ ์‚ฌ๋ก€๋Š”? (ํžŒํŠธ: ์‚ฌ์šฉ์ž-๊ถŒํ•œ, ์ฑ…-์ €์ž)
  • ์ค‘๊ฐ„ ์—”ํ‹ฐํ‹ฐ์˜ PK ์ „๋žต์€? (ํžŒํŠธ: ๋‹จ์ผ PK ๋˜๋Š” ๋ณตํ•ฉ PK)

๐Ÿ“š Phase 7 โ€” mappedBy์™€ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ

๋ชฉํ‘œ: ์–‘๋ฐฉํ–ฅ ์—ฐ๊ด€๊ด€๊ณ„์˜ ๊ฐ€์žฅ ์–ด๋ ค์šด ๊ฐœ๋…์„ ์ •๋ฆฌํ•œ๋‹ค.

Unit 7.1 โ€” ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ํ•„์š”ํ•œ ์ด์œ 

์„ ์ˆ˜ ์ง€์‹: Phase 6

ํ•ต์‹ฌ ๋ฌธ์ œ

์–‘๋ฐฉํ–ฅ์€ ๊ฐ์ฒด ์ž…์žฅ: A โ†’ B + B โ†’ A (2๊ฐœ ์ฐธ์กฐ)
DB ์ž…์žฅ: FK 1๊ฐœ๋กœ ํ‘œํ˜„

๋ฌธ์ œ:

  • A์—์„œ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ๊ณผ B์—์„œ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ ์ค‘ ์–ด๋А ๊ฒƒ์„ DB์— ๋ฐ˜์˜?
  • ๋‘˜ ๋‹ค ๋ฐ˜์˜ํ•˜๋ฉด ์ถฉ๋Œ / ๋น„ํšจ์œจ

ํ•ด๊ฒฐ:

"ํ•œ์ชฝ๋งŒ ์ฃผ์ธ ์œผ๋กœ ์ •ํ•˜๊ณ , ๊ทธ ์ชฝ๋งŒ DB FK ๊ด€๋ฆฌ"

๋‹ค๋ฅธ ์ชฝ์€ ์ฝ๊ธฐ ์ „์šฉ

๊ทœ์น™:

  • N์ชฝ์ด ์ฃผ์ธ (@ManyToOne ์ชฝ)
  • 1์ชฝ์€ mappedBy

์ž๊ธฐ ์ ๊ฒ€

  • ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ์ธก๋ฉด์—์„œ ์™œ ํ•œ์ชฝ๋งŒ ์ฃผ์ธ์ด์–ด์•ผ ํ•˜๋Š”๊ฐ€?
  • ๋‘ ์ชฝ์ด ๋ชจ๋‘ FK๋ฅผ ๋ณ€๊ฒฝํ•˜๋ฉด ์–ด๋–ค ์‚ฌ๊ณ ๊ฐ€? (ํžŒํŠธ: ์ถฉ๋Œ, ์ผ๊ด€์„ฑ ๊นจ์ง)

Unit 7.2 โ€” mappedBy ์‚ฌ์šฉ๋ฒ•

์„ ์ˆ˜ ์ง€์‹: Unit 7.1

ํ•ต์‹ฌ ๊ฐœ๋…

mappedBy:

  • ์ฃผ์ธ์ด ์•„๋‹Œ ์ชฝ์— ๋ช…์‹œ
  • ๊ฐ’์€ ์ฃผ์ธ ์—”ํ‹ฐํ‹ฐ์˜ ํ•„๋“œ๋ช…
@OneToMany(mappedBy = "team")  
//                    โ†‘ Member ์—”ํ‹ฐํ‹ฐ์˜ team ํ•„๋“œ๋ฅผ ๊ฐ€๋ฆฌํ‚ด
private List<Member> members;

์˜๋ฏธ:

"๋‚˜๋Š” ์ฃผ์ธ์ด ์•„๋‹ˆ๊ณ , ์ €์ชฝ(Member.team)์ด ์ฃผ์ธ์ด๋‹ค"

JPA๊ฐ€ ํ•˜๋Š” ์ผ:

  • ์ฃผ์ธ์ด ์•„๋‹Œ ์ชฝ: ์ฝ๊ธฐ ์ „์šฉ โ€” FK ๋ณ€๊ฒฝ ์•ˆ ํ•จ
  • ์ฃผ์ธ ์ชฝ๋งŒ ๋ณด๊ณ  DB ๋™๊ธฐํ™”

์ž์ฃผ ํ•˜๋Š” ์‹ค์ˆ˜:

  • ์ฃผ์ธ์ด ์•„๋‹Œ ์ชฝ์—์„œ ๋ณ€๊ฒฝํ•˜๊ณ  DB ๋ฐ˜์˜ ๊ธฐ๋Œ€
  • โ†’ ๋ณ€๊ฒฝ ์•ˆ ๋จ โ†’ ๋””๋ฒ„๊น… ์–ด๋ ค์›€

์—ฐ๊ด€๊ด€๊ณ„ ํŽธ์˜ ๋ฉ”์„œ๋“œ (์‹ค๋ฌด ํ‘œ์ค€):

@Entity
public class Member {
    public void setTeam(Team team) {
        this.team = team;
        team.getMembers().add(this);  // ์–‘์ชฝ ๋™๊ธฐํ™”!
    }
}

์ž๊ธฐ ์ ๊ฒ€

  • mappedBy์˜ ๊ฐ’ "team"์ด ์ž˜๋ชป๋œ ํ•„๋“œ๋ช…์ด๋ฉด? (ํžŒํŠธ: ์ปดํŒŒ์ผ OK, ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ)
  • ์–‘์ชฝ์„ ํ•ญ์ƒ ๊ฐ™์ด ๋ฐ”๊ฟ”์•ผ ํ•˜๋Š” ์ด์œ ๋Š”? (ํžŒํŠธ: 1์ฐจ ์บ์‹œ ์ผ๊ด€์„ฑ)

Unit 7.3 โ€” N:1 + 1:N ์–‘๋ฐฉํ–ฅ ๋ชจ๋ฒ” ์‚ฌ๋ก€

์„ ์ˆ˜ ์ง€์‹: Unit 7.2

ํ•ต์‹ฌ ํŒจํ„ด

๊ฐ€์žฅ ํ”ํ•œ ์–‘๋ฐฉํ–ฅ โ€” ํšŒ์›๊ณผ ํŒ€:

@Entity
public class Member {
    @Id @GeneratedValue
    private Long id;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;  // ์ฃผ์ธ (FK ๊ด€๋ฆฌ)
    
    // ํŽธ์˜ ๋ฉ”์„œ๋“œ
    public void changeTeam(Team team) {
        this.team = team;
        team.getMembers().add(this);
    }
}

@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
    
    @OneToMany(mappedBy = "team")  // ์ฃผ์ธ X
    private List<Member> members = new ArrayList<>();
}

5๊ฐ€์ง€ ๊ถŒ์žฅ ์‚ฌํ•ญ:
1. โœ… N์ชฝ์ด ์ฃผ์ธ (@ManyToOne)
2. โœ… fetch = FetchType.LAZY ๋ช…์‹œ
3. โœ… ์ปฌ๋ ‰์…˜์€ ํ•„๋“œ ์ดˆ๊ธฐํ™” (new ArrayList<>())
4. โœ… ํŽธ์˜ ๋ฉ”์„œ๋“œ๋กœ ์–‘์ชฝ ๋™๊ธฐํ™”
5. โœ… Lombok @ToString ์—์„œ ์ปฌ๋ ‰์…˜ ์ œ์™ธ (๋ฌดํ•œ ๋ฃจํ”„ ๋ฐฉ์ง€)

์ž๊ธฐ ์ ๊ฒ€

  • ๋‹จ๋ฐฉํ–ฅ ๋งคํ•‘์œผ๋กœ ์‹œ์ž‘ํ•˜๊ณ  ํ•„์š” ์‹œ ์–‘๋ฐฉํ–ฅ์œผ๋กœ ํ™•์žฅํ•˜๋ผ๋Š” ์กฐ์–ธ์˜ ์˜๋ฏธ๋Š”?
  • ์–‘๋ฐฉํ–ฅ์ด ๋ฌดํ•œ ๋ฃจํ”„๋ฅผ ์ผ์œผํ‚ค๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋Š”? (ํžŒํŠธ: toString, JSON ์ง๋ ฌํ™”)

๐Ÿ“š Phase 8 โ€” ํ”„๋ก์‹œ์™€ ์ง€์—ฐ/์ฆ‰์‹œ ๋กœ๋”ฉ

๋ชฉํ‘œ: JPA์˜ ํ”„๋ก์‹œ ๋ฉ”์ปค๋‹ˆ์ฆ˜๊ณผ ๋กœ๋”ฉ ์ „๋žต โ€” 8-9์ฃผ์ฐจ ํ”„๋ก์‹œ์™€ ๋‹ค๋ฅธ ๋งฅ๋ฝ์˜ ํ”„๋ก์‹œ.

Unit 8.1 โ€” em.find() vs em.getReference()

์„ ์ˆ˜ ์ง€์‹: Phase 5

ํ•ต์‹ฌ ์ฐจ์ด:

em.find()em.getReference()
๋ฐ˜ํ™˜์‹ค์ œ ์—”ํ‹ฐํ‹ฐํ”„๋ก์‹œ ๊ฐ์ฒด
SQL ์‹คํ–‰์ฆ‰์‹œ์ง€์—ฐ (ํ•„๋“œ ์ ‘๊ทผ ์‹œ)
ํƒ€์ž…UserUser$Proxy1 (CGLIB)

์˜ˆ์‹œ:

User user = em.find(User.class, 1L);  // ์ฆ‰์‹œ SELECT
System.out.println(user.getName());   // SQL ์‹คํ–‰ X (์ด๋ฏธ ๋กœ๋“œ๋จ)

User proxyUser = em.getReference(User.class, 1L);  // SQL ์•ˆ ํ•จ
System.out.println(proxyUser.getName());           // ์—ฌ๊ธฐ์„œ SELECT ์‹คํ–‰

ํ”„๋ก์‹œ ๊ฐ์ฒด ํ™•์ธ:

System.out.println(proxyUser.getClass().getName());
// ์ถœ๋ ฅ: com.sun.proxy.$Proxy1

์ž๊ธฐ ์ ๊ฒ€

  • 8-9์ฃผ์ฐจ์˜ JDK ๋™์  ํ”„๋ก์‹œ์™€ ๊ฐ™์€ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ธ๊ฐ€? (ํžŒํŠธ: ๋น„์Šทํ•˜์ง€๋งŒ ๋‹ค๋ฅธ ๋ชฉ์ )
  • getReference()๋กœ ๋ฐ›์€ ํ›„ EntityManager๊ฐ€ ๋‹ซํžˆ๋ฉด? (ํžŒํŠธ: LazyInitializationException)

Unit 8.2 โ€” JPA ํ”„๋ก์‹œ ๋ฉ”์ปค๋‹ˆ์ฆ˜

์„ ์ˆ˜ ์ง€์‹: Unit 8.1

ํ•ต์‹ฌ ๋™์ž‘ ํ๋ฆ„:

Step 1 โ€” getReference() ํ˜ธ์ถœ:

User proxyUser = em.getReference(User.class, 1L);
// ํ”„๋ก์‹œ ๊ฐ์ฒด ๋ฐ˜ํ™˜
// proxyUser.target = null (์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ๋ฏธ๋กœ๋“œ)

Step 2 โ€” ํ•„๋“œ ์ ‘๊ทผ ์‹œ์ :

proxyUser.getName();
// โ†“ ์ด ์ˆœ๊ฐ„:
// 1. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ๋กœ๋“œ ์š”์ฒญ
// 2. DB SELECT ์‹คํ–‰
// 3. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ๋ณด๊ด€
// 4. proxyUser.target = ์‹ค์ œ ์—”ํ‹ฐํ‹ฐ ์—ฐ๊ฒฐ
// 5. proxyUser.target.getName() ํ˜ธ์ถœ

ํ”„๋ก์‹œ์˜ ํŠน์ง•:

  • ์›๋ณธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ƒ์†ํ•œ ํด๋ž˜์Šค (CGLIB ์‚ฌ์šฉ)
  • ID๋Š” ๊ฐ€์ง€๊ณ  ์žˆ์Œ (์ƒ์„ฑ ์‹œ ๋ฐ›์Œ)
  • ์‹ค์ œ ๋ฐ์ดํ„ฐ๋Š” target ์ฐธ์กฐ

โš ๏ธ ์ฃผ์˜ โ€” ๋น„๊ต ์‹œ instanceof ์‚ฌ์šฉ:

if (user instanceof User) { ... }   // ํ”„๋ก์‹œ๋„ ์žกํž˜ โœ…
if (user.getClass() == User.class) { ... }  // ํ”„๋ก์‹œ๋Š” false โŒ

์ž๊ธฐ ์ ๊ฒ€

  • ํ”„๋ก์‹œ๊ฐ€ ์›๋ณธ ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•˜๋Š” ์ด์œ ๋Š”? (ํžŒํŠธ: ๋‹คํ˜•์„ฑ)
  • final ํด๋ž˜์Šค๊ฐ€ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋  ์ˆ˜ ์—†๋Š” ์ด์œ ์™€ ์—ฐ๊ฒฐ๋˜๋Š”๊ฐ€? (ํžŒํŠธ: YES)

Unit 8.3 โ€” ์ง€์—ฐ ๋กœ๋”ฉ (LAZY)

์„ ์ˆ˜ ์ง€์‹: Unit 8.2

ํ•ต์‹ฌ ๊ฐœ๋…

์ง€์—ฐ ๋กœ๋”ฉ(Lazy Loading):

  • ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฆ‰์‹œ ์กฐํšŒํ•˜์ง€ ์•Š์Œ
  • ์‚ฌ์šฉ ์‹œ์  ์— SQL ์‹คํ–‰
  • ํ”„๋ก์‹œ ๊ฐ์ฒด๋กœ ์ฐธ์กฐ๋งŒ ์œ ์ง€
@Entity
public class Member {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    private Team team;
}

๋™์ž‘ ์‹œ๋‚˜๋ฆฌ์˜ค:

Member member = em.find(Member.class, 1L);
// SELECT * FROM member WHERE id = 1;
// member.team = ํ”„๋ก์‹œ ๊ฐ์ฒด (Team$Proxy1)

System.out.println(member.getTeam());     // SQL X (ํ”„๋ก์‹œ๋งŒ ์ถœ๋ ฅ)
System.out.println(member.getTeam().getName());  
// โ†‘ ์ด ์‹œ์ ์— SELECT * FROM team WHERE id = ?;

์–ธ์ œ ์‚ฌ์šฉ:

  • ๊ฑฐ์˜ ๋ชจ๋“  ManyToOne, OneToOne ๊ด€๊ณ„
  • ์‚ฌ์šฉ ์•ˆ ํ•  ๊ฐ€๋Šฅ์„ฑ ์žˆ๋Š” ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ

์ž๊ธฐ ์ ๊ฒ€

  • ์ง€์—ฐ ๋กœ๋”ฉ์˜ SQL ์‹คํ–‰ ์‹œ์ ์„ ์ •ํ™•ํžˆ ์–ธ์ œ์ธ๊ฐ€?
  • ILIC์˜ ์šด์ž„ ๊ฒฌ์  ์กฐํšŒ ์‹œ ์–ด๋–ค ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ LAZY๋กœ ๋‘˜๊นŒ?

Unit 8.4 โ€” ์ฆ‰์‹œ ๋กœ๋”ฉ (EAGER) โ€” ์ฃผ์˜ โญ

์„ ์ˆ˜ ์ง€์‹: Unit 8.3

ํ•ต์‹ฌ ๊ฐœ๋…

์ฆ‰์‹œ ๋กœ๋”ฉ(Eager Loading):

  • ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฆ‰์‹œ ํ•จ๊ป˜ ์กฐํšŒ
  • JOIN ๋˜๋Š” ์ถ”๊ฐ€ SELECT
@ManyToOne(fetch = FetchType.EAGER)
private Team team;
Member member = em.find(Member.class, 1L);
// SELECT m.*, t.* FROM member m JOIN team t ON ... WHERE m.id = 1;
// ๋˜๋Š”: SELECT * FROM member WHERE id = 1; + SELECT * FROM team WHERE id = ?;

์—ฐ๊ด€๊ด€๊ณ„๋ณ„ ๊ธฐ๋ณธ๊ฐ’ (์™ธ์›Œ์•ผ ํ•จ) โญ :

๊ด€๊ณ„๊ธฐ๋ณธ fetch
@ManyToOneEAGER (์œ„ํ—˜!)
@OneToOneEAGER (์œ„ํ—˜!)
@OneToManyLAZY
@ManyToManyLAZY

โš ๏ธ ์ฆ‰์‹œ ๋กœ๋”ฉ์˜ ๋ฌธ์ œ โญ :

  1. N+1 ๋ฌธ์ œ โ€” Phase 9์—์„œ ์ž์„ธํžˆ
  2. JPQL์—์„œ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ฟผ๋ฆฌ ํญ์ฆ
  3. ํ•ญ์ƒ ๋ชจ๋“  ์—ฐ๊ด€์„ ๊ฐ€์ ธ์˜ด โ€” ์„ฑ๋Šฅ ์ €ํ•˜

์‹ค๋ฌด ๊ฒฐ๋ก :

"๋ชจ๋“  ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ LAZY๋กœ ๋ช…์‹œ"

EAGER๊ฐ€ ํ•„์š”ํ•˜๋ฉด fetch join (Phase 9)

@ManyToOne(fetch = FetchType.LAZY)  // ํ•ญ์ƒ ๋ช…์‹œ!
@OneToOne(fetch = FetchType.LAZY)   // ํ•ญ์ƒ ๋ช…์‹œ!

์ž๊ธฐ ์ ๊ฒ€

  • ์™œ ManyToOne์˜ ๊ธฐ๋ณธ๊ฐ’์ด EAGER์ธ๊ฐ€? (ํžŒํŠธ: ์ง๊ด€์ ์ด์ง€๋งŒ ์œ„ํ—˜)
  • ILIC์—์„œ EAGER ๋•Œ๋ฌธ์— ์–ด๋–ค ์‚ฌ๊ณ ๊ฐ€ ๊ฐ€๋Šฅํ•œ๊ฐ€?

๐Ÿ“š Phase 9 โ€” N+1 ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ (โ˜… 12์ฃผ์ฐจ ์ •์ )

๋ชฉํ‘œ: ์‹ค๋ฌด์—์„œ ๊ฐ€์žฅ ์ž์ฃผ ๋งŒ๋‚˜๋Š” JPA ์„ฑ๋Šฅ ๋ฌธ์ œ๋ฅผ 4๋‹จ๊ณ„๋กœ ํ•ด๊ฒฐํ•œ๋‹ค.

Unit 9.1 โ€” N+1 ๋ฌธ์ œ ์ •์˜ (์ฆ‰์‹œ/์ง€์—ฐ ๋‘ ์‹œ๋‚˜๋ฆฌ์˜ค)

์„ ์ˆ˜ ์ง€์‹: Phase 8

ํ•ต์‹ฌ ์ •์˜

N+1 ๋ฌธ์ œ:

"ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ(1)๋ฅผ ์‹คํ–‰ํ•œ ํ›„, ์ถ”๊ฐ€๋กœ N๊ฐœ์˜ ์ฟผ๋ฆฌ ๊ฐ€ ์‹คํ–‰๋˜๋Š” ๋ฌธ์ œ"

์ฆ‰์‹œ ๋กœ๋”ฉ(EAGER) ์‹œ ๋ฐœ์ƒ:

// User์— @OneToMany(fetch = EAGER) private Set<Article> articles;
List<User> users = em.createQuery("SELECT u FROM User u").getResultList();

์‹คํ–‰๋˜๋Š” SQL:

-- (1) User 100๋ช… ์กฐํšŒ
SELECT * FROM user;

-- (N=100) User๋งˆ๋‹ค article ์กฐํšŒ
SELECT * FROM article WHERE user_id = 1;
SELECT * FROM article WHERE user_id = 2;
SELECT * FROM article WHERE user_id = 3;
... (100๋ฒˆ)

โ†’ ์ด 101๊ฐœ์˜ ์ฟผ๋ฆฌ!

์ง€์—ฐ ๋กœ๋”ฉ(LAZY) ์‹œ์—๋„ ๋ฐœ์ƒ ๊ฐ€๋Šฅ:

List<User> users = em.createQuery("SELECT u FROM User u").getResultList();
// (1) User 100๋ช… ์กฐํšŒ โ€” LAZY๋ผ์„œ article์€ ์•ˆ ๊ฐ€์ ธ์˜ด

for (User user : users) {
    System.out.println(user.getArticles().size());
    // โ†‘ getter ํ˜ธ์ถœ ์‹œ์ ์— 100๋ฒˆ SQL ์‹คํ–‰!
}

โ†’ ๊ฒฐ๊ตญ ๊ฐ™์€ N+1 ๋ฌธ์ œ

ํ•ต์‹ฌ ํ†ต์ฐฐ:

"๋‹จ์ˆœํžˆ LAZY๋กœ ๋ฐ”๊พผ๋‹ค๊ณ  ํ•ด๊ฒฐ ์•ˆ ๋จ. JPQL/getter ํŒจํ„ด ์ž์ฒด ๊ฐ€ ๋ฌธ์ œ"

์ž๊ธฐ ์ ๊ฒ€

  • "์œ ์ €๊ฐ€ 100๋ช…์ด๋ฉด 100๋ฒˆ ์ฟผ๋ฆฌ ์‹คํ–‰์ด ๋‹น์—ฐํ•œ๊ฐ€?"์˜ ๋‹ต์€? (ํžŒํŠธ: NO)
  • N+1์„ ์ธ์ง€ํ•˜๋Š” ๊ฐ€์žฅ ๋น ๋ฅธ ๋ฐฉ๋ฒ•์€? (ํžŒํŠธ: SQL ๋กœ๊ทธ ํ™œ์„ฑํ™”)

Unit 9.2 โ€” join vs fetch join

์„ ์ˆ˜ ์ง€์‹: Unit 9.1

ํ•ต์‹ฌ ์ฐจ์ด โญ :

์ผ๋ฐ˜ JOIN โ€” N+1 ํ•ด๊ฒฐ ์•ˆ ๋จ:

List<Member> members = em.createQuery(
    "SELECT m FROM Member m JOIN m.team t", Member.class)
    .getResultList();

์‹คํ–‰๋˜๋Š” SQL:

SELECT m.*  -- โ† Member๋งŒ SELECT, Team์€ ๋ฏธํฌํ•จ
FROM Member m
JOIN Team t ON m.team_id = t.id;

โ†’ Team์€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ์•ˆ ๋“ค์–ด์˜ด โ†’ getTeam() ํ˜ธ์ถœ ์‹œ ์ถ”๊ฐ€ SQL โ†’ N+1 ์—ฌ์ „!

FETCH JOIN โ€” ํ•œ ๋ฒˆ์— ํ•ด๊ฒฐ โญ :

List<Member> members = em.createQuery(
    "SELECT m FROM Member m JOIN FETCH m.team", Member.class)
    .getResultList();

์‹คํ–‰๋˜๋Š” SQL:

SELECT m.*, t.*  -- โ† Team๋„ ํ•จ๊ป˜ SELECT!
FROM Member m
JOIN Team t ON m.team_id = t.id;

โ†’ Team๋„ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ค์–ด์˜ด โ†’ getTeam() SQL X โ†’ N+1 ํ•ด๊ฒฐ!

JOIN vs FETCH JOIN ์ •๋ฆฌ:

JOINFETCH JOIN
๊ฒฐ๊ณผMember๋งŒMember + Team
์˜์†์„ฑ ์ปจํ…์ŠคํŠธMember๋งŒ๋‘˜ ๋‹ค
getter ์‹œ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๋ฐœ์ƒ์—†์Œ

์ž๊ธฐ ์ ๊ฒ€

  • LAZY ์„ค์ •์„ ์œ ์ง€ํ•˜๋ฉด์„œ fetch join์„ ์“ฐ๋Š” ๊ฒŒ ์™œ ์ข‹์€๊ฐ€?
  • ILIC์˜ ์–ด๋–ค ์ฟผ๋ฆฌ์— fetch join์ด ํ•„์š”ํ• ๊นŒ? (ํžŒํŠธ: ์šด์ž„ + ์šด์ž„ ํ•ญ๋ชฉ)

Unit 9.3 โ€” fetch join + ํŽ˜์ด์ง•์˜ OneToMany ํ•จ์ •

์„ ์ˆ˜ ์ง€์‹: Unit 9.2

ํ•ต์‹ฌ ํ•จ์ • โญ :

@ManyToOne + ํŽ˜์ด์ง• โ€” ์ •์ƒ ๋™์ž‘:

List<Member> members = em.createQuery(
    "SELECT m FROM Member m JOIN FETCH m.team ORDER BY m.id", Member.class)
    .setFirstResult(0)
    .setMaxResults(3)  // โœ… ์ •์ƒ
    .getResultList();
SELECT m.*, t.* FROM Member m JOIN Team t ON ... ORDER BY m.id LIMIT 3;

โ†’ Member ๊ธฐ์ค€ ํŽ˜์ด์ง• OK

@OneToMany + ํŽ˜์ด์ง• โ€” ๋ฐ์ดํ„ฐ ์กฐํšŒ ๋ฌธ์ œ ๋ฐœ์ƒ โญ :

List<Team> teams = em.createQuery(
    "SELECT t FROM Team t JOIN FETCH t.members", Team.class)
    .setFirstResult(0)
    .setMaxResults(3)  // โŒ ์œ„ํ—˜!
    .getResultList();

๋ฌด์—‡์ด ๋ฌธ์ œ์ธ๊ฐ€:

-- ์˜๋„: Team 3๊ฐœ
-- ์‹ค์ œ SQL:
SELECT t.*, m.* FROM Team t JOIN Member m ON t.id = m.team_id LIMIT 3;

LIMIT 3 ๊ฐ€ JOIN ๊ฒฐ๊ณผ์˜ ํ–‰ ์ˆ˜ ์— ์ ์šฉ๋จ!

  • Team A(๋ฉค๋ฒ„ 3๋ช…) โ†’ 3๊ฐœ ํ–‰ โ†’ LIMIT 3์— ๋ชจ๋‘ ์žกํž˜
  • โ†’ Team B์™€ C๋Š” ๊ฒฐ๊ณผ์— ์—†์Œ!

Hibernate์˜ ๋Œ€์‘:

  • ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํŽ˜์ด์ง• (DB๋กœ๋Š” ๋ชจ๋“  ๋ฐ์ดํ„ฐ ๋กœ๋“œ)
  • โ†’ ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ๋กœ!
  • ๊ฒฝ๊ณ  ๋กœ๊ทธ: firstResult/maxResults specified with collection fetch; applying in memory!

์™œ ์ด ๋ฌธ์ œ๊ฐ€ ์ผ์–ด๋‚˜๋Š”๊ฐ€:

"OneToMany๋Š” 1ํ–‰์ด Nํ–‰์œผ๋กœ ๋Š˜์–ด๋‚จ. ํŽ˜์ด์ง•์˜ ๋‹จ์œ„๊ฐ€ ๊นจ์ง"

์ž๊ธฐ ์ ๊ฒ€

  • ILIC์˜ "์ตœ๊ทผ ์ฃผ๋ฌธ 10๊ฑด + ์ฃผ๋ฌธ ํ•ญ๋ชฉ" ์กฐํšŒ ์‹œ ์ด ํ•จ์ •์— ๊ฑธ๋ฆฌ๋Š”๊ฐ€?
  • ๋ฉ”๋ชจ๋ฆฌ ํŽ˜์ด์ง•์˜ ์œ„ํ—˜์€? (ํžŒํŠธ: OOM)

Unit 9.4 โ€” @BatchSize ํ•ด๊ฒฐ โญ

์„ ์ˆ˜ ์ง€์‹: Unit 9.3

ํ•ต์‹ฌ ํ•ด๊ฒฐ

@BatchSize:

  • LAZY ์œ ์ง€ + IN ์ฟผ๋ฆฌ๋กœ ๋ฌถ์–ด์„œ ์กฐํšŒ
  • N+1 ํ•ด๊ฒฐ + OneToMany ํŽ˜์ด์ง• ๋ฌธ์ œ ํ•ด๊ฒฐ
@Entity
public class Team {
    @Id @GeneratedValue
    private Long id;
    
    @BatchSize(size = 10)  // ์ตœ๋Œ€ 10๊ฐœ์”ฉ ๋ฌถ์–ด์„œ
    @OneToMany(mappedBy = "team", fetch = FetchType.LAZY)
    private List<Member> members;
}

ํŽ˜์ด์ง• + @BatchSize ์‚ฌ์šฉ:

List<Team> teams = em.createQuery(
    "SELECT t FROM Team t ORDER BY t.id", Team.class)
    .setFirstResult(0)
    .setMaxResults(3)  // โœ… Team ๊ธฐ์ค€ ์ •ํ™•ํ•œ ํŽ˜์ด์ง•
    .getResultList();

for (Team team : teams) {
    team.getMembers().size();
}

์‹คํ–‰๋˜๋Š” SQL:

-- (1) Team ํŽ˜์ด์ง• ์กฐํšŒ
SELECT id FROM Team ORDER BY id LIMIT 3;

-- (2) IN ์ ˆ๋กœ ํ•œ ๋ฒˆ์— ๋ฉค๋ฒ„ ์กฐํšŒ
SELECT * FROM Member WHERE team_id IN (1, 2, 3);

โ†’ 2๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ๋! (1+N โ†’ 2 ๋˜๋Š” 1+N/๋ฐฐ์น˜์‚ฌ์ด์ฆˆ)

์ „์—ญ ์„ค์ •:

spring:
  jpa:
    properties:
      hibernate:
        default_batch_fetch_size: 100

โš ๏ธ ์ฃผ์˜ โ€” fetch join๊ณผ ํ•จ๊ป˜ ์“ฐ์ง€ ๋ง ๊ฒƒ:

  • fetch join์ด ์šฐ์„  โ†’ @BatchSize ๋ฌด์‹œ

3๊ฐ€์ง€ ํ•ด๊ฒฐ์ฑ… ๋น„๊ต โญ :

๋„๊ตฌ์ ํ•ฉ ์ƒํ™ฉ
fetch joinManyToOne ๋‹จ๊ฑด, ํŽ˜์ด์ง• ์—†๋Š” ์ปฌ๋ ‰์…˜
@BatchSizeOneToMany + ํŽ˜์ด์ง•, ์ผ๋ฐ˜ LAZY ์ตœ์ ํ™”
EntityGraph๋™์ ์œผ๋กœ fetch ์ „๋žต ๊ฒฐ์ •

์ž๊ธฐ ์ ๊ฒ€

  • batch size๋ฅผ ๋„ˆ๋ฌด ํฌ๊ฒŒ ์„ค์ •ํ•˜๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€? (ํžŒํŠธ: IN ์ ˆ ํ•œ๋„)
  • ILIC์—์„œ default_batch_fetch_size๋ฅผ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•˜๋Š” ๊ฒŒ ์ข‹์„๊นŒ?

๐Ÿ“š Phase 10 โ€” ์˜์†์„ฑ ์ „์ด + JPQL/QueryDSL

๋ชฉํ‘œ: JPA ํ•™์Šต์„ ๋งˆ๋ฌด๋ฆฌํ•˜๋Š” 4๊ฐ€์ง€ ๋„๊ตฌ.

Unit 10.1 โ€” CASCADE (์˜์†์„ฑ ์ „์ด)

์„ ์ˆ˜ ์ง€์‹: Phase 5, 6

ํ•ต์‹ฌ ๊ฐœ๋…

CASCADE:

  • "๋ถ€๋ชจ์˜ ์ž‘์—…์ด ์ž์‹์—๊ฒŒ ์ „ํŒŒ"
  • ๋ถ€๋ชจ ์ €์žฅ โ†’ ์ž์‹ ์ž๋™ ์ €์žฅ
  • ๋ถ€๋ชจ ์‚ญ์ œ โ†’ ์ž์‹ ์ž๋™ ์‚ญ์ œ
@Entity
public class Parent {
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    private List<Child> children = new ArrayList<>();
}

CASCADE ์˜ต์…˜:

์˜ต์…˜๋™์ž‘
ALL๋ชจ๋“  ์ž‘์—… ์ „ํŒŒ
PERSIST์ €์žฅ๋งŒ ์ „ํŒŒ
REMOVE์‚ญ์ œ๋งŒ ์ „ํŒŒ
MERGE๋ณ‘ํ•ฉ๋งŒ ์ „ํŒŒ
REFRESH์ƒˆ๋กœ๊ณ ์นจ
DETACH๋ถ„๋ฆฌ

์‹ค๋ฌด ์‚ฌ๋ก€:

Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);

em.persist(parent);  // child1, child2๋„ ์ž๋™ ์ €์žฅ!

์–ธ์ œ ์‚ฌ์šฉ:

  • ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๊ฐ€ ๋ช…ํ™• ํ•  ๋•Œ (๋ผ์ดํ”„ ์‚ฌ์ดํด ๊ฐ™์ด๊ฐ)
  • ๋‹จ์ผ ๋ถ€๋ชจ ๊ฐ€ ์ž์‹์„ ์†Œ์œ  (๋‹ค๋ฅธ ๊ณณ์—์„œ ์ž์‹์„ ์ฐธ์กฐ X)
  • ์˜ˆ: ๊ฒŒ์‹œ๊ธ€-๋Œ“๊ธ€, ์ฃผ๋ฌธ-์ฃผ๋ฌธ์•„์ดํ…œ

์ž๊ธฐ ์ ๊ฒ€

  • ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์ฐธ์กฐ๋˜๋Š” ์ž์‹์— CASCADE.REMOVE๋ฅผ ๊ฑธ๋ฉด? (ํžŒํŠธ: ์‚ฌ๊ณ )
  • ILIC์—์„œ CASCADE๊ฐ€ ์ ํ•ฉํ•œ ๊ด€๊ณ„๋Š”? (ํžŒํŠธ: ์ฃผ๋ฌธ-์ฃผ๋ฌธํ•ญ๋ชฉ)

Unit 10.2 โ€” orphanRemoval (๊ณ ์•„ ๊ฐ์ฒด)

์„ ์ˆ˜ ์ง€์‹: Unit 10.1

ํ•ต์‹ฌ ๊ฐœ๋…

orphanRemoval:

  • ๋ถ€๋ชจ-์ž์‹ ๊ด€๊ณ„๊ฐ€ ๋Š์–ด์ง„ ์ž์‹ ์ž๋™ ์‚ญ์ œ
  • ์ž์‹ ์ปฌ๋ ‰์…˜์—์„œ ์ œ๊ฑฐ ์‹œ โ†’ DB์—์„œ๋„ ์‚ญ์ œ
@Entity
public class Parent {
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Child> children = new ArrayList<>();
    
    public void removeChild(Child child) {
        children.remove(child);
        child.setParent(null);
    }
}

๋™์ž‘:

Parent parent = em.find(Parent.class, 1L);
parent.removeChild(parent.getChildren().get(0));
// โ†’ DELETE ์ž๋™ ์‹คํ–‰

CASCADE.REMOVE vs orphanRemoval โญ :

CASCADE.REMOVEorphanRemoval
ํŠธ๋ฆฌ๊ฑฐ๋ถ€๋ชจ ์ž์ฒด ์‚ญ์ œ์ž์‹ ์ปฌ๋ ‰์…˜ ์ œ๊ฑฐ
์‚ฌ์šฉ ์‹œ์ em.remove(parent)parent.children.remove(child)

๋‘˜ ๋‹ค ์žˆ์–ด์•ผ ์™„๋ฒฝํ•œ ๋ถ€๋ชจ-์ž์‹ ๊ด€๋ฆฌ:

@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)

โš ๏ธ ์ฃผ์˜:

  • orphanRemoval์€ ๋‹จ์ผ ์†Œ์œ ์ž ๊ด€๊ณ„ ์ผ ๋•Œ๋งŒ
  • ๋‹ค๋ฅธ ๊ณณ์—์„œ ์ฐธ์กฐ๋˜๋Š” ์ž์‹์— ์“ฐ๋ฉด ์‚ฌ๊ณ 

์ž๊ธฐ ์ ๊ฒ€

  • ๋ถ€๋ชจ๋ฅผ ์‚ญ์ œํ•˜๋ฉด ์ž์‹๋„ ์‚ญ์ œ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ ์ž์‹๋งŒ ๋”ฐ๋กœ ์‚ญ์ œํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์–ด๋–ค ์˜ต์…˜์ด? (ํžŒํŠธ: CASCADE.REMOVE๋งŒ)
  • ILIC์˜ ์šด์ž„ ๊ฒฌ์ ๊ณผ ์šด์ž„ ํ•ญ๋ชฉ ๊ด€๊ณ„์— ์–ด๋–ค ์กฐํ•ฉ์ด ์ ํ•ฉํ•œ๊ฐ€?

Unit 10.3 โ€” JPQL์˜ ๋ณธ์งˆ

์„ ์ˆ˜ ์ง€์‹: Phase 5

ํ•ต์‹ฌ ๊ฐœ๋…

JPQL (Java Persistence Query Language):

  • JPA๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด
  • ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด ๋Œ€์ƒ
List<User> users = em.createQuery(
    "SELECT u FROM User u WHERE u.age > 20", User.class)
    .getResultList();

JPQL โ†’ SQL ๋ณ€ํ™˜:

SELECT * FROM user WHERE age > 20;

SQL๊ณผ์˜ ์ฐจ์ด:

  • ๋Œ€์ƒ: ์—”ํ‹ฐํ‹ฐ vs ํ…Œ์ด๋ธ”
  • ๋Œ€์†Œ๋ฌธ์ž: ์—”ํ‹ฐํ‹ฐ ์ด๋ฆ„์€ case-sensitive
  • ์ž๋™ ๋งคํ•‘: ๊ฒฐ๊ณผ๋ฅผ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋กœ

SQL์ด ํ•„์š”ํ•œ ์‹œ์ :

  • ๋งค์šฐ ๋ณต์žกํ•œ ํ†ต๊ณ„ ์ฟผ๋ฆฌ
  • DB ํŠนํ™” ๊ธฐ๋Šฅ ์‚ฌ์šฉ
  • ๋„ค์ดํ‹ฐ๋ธŒ ์ฟผ๋ฆฌ: em.createNativeQuery(...)

์ž๊ธฐ ์ ๊ฒ€

  • ์™œ JPA๊ฐ€ ์ž์ฒด ์ฟผ๋ฆฌ ์–ธ์–ด๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๊ฐ€?
  • JPQL๊ณผ SQL์„ ํ•จ๊ป˜ ์“ธ ์ˆ˜ ์žˆ๋Š”๊ฐ€? (ํžŒํŠธ: YES โ€” Native Query)

Unit 10.4 โ€” QueryDSL (์‹ค๋ฌด ํ‘œ์ค€) โญ

์„ ์ˆ˜ ์ง€์‹: Unit 10.3

ํ•ต์‹ฌ ๊ฐœ๋…

QueryDSL:

  • JPQL์„ ์ž๋ฐ” ์ฝ”๋“œ๋กœ ์ž‘์„ฑ
  • ์ปดํŒŒ์ผ ์‹œ์ ์— ์˜ค๋ฅ˜ ๊ฒ€์ถœ
  • ๋™์  ์ฟผ๋ฆฌ ์ž‘์„ฑ์— ๊ฐ•๋ ฅ

JPQL์˜ ๋ฌธ์ œ:

  • ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ โ†’ ์˜คํƒ€๊ฐ€ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ
  • ๋™์  ์ฟผ๋ฆฌ ์ž‘์„ฑ ์–ด๋ ค์›€

QueryDSL์˜ ํ•ด๊ฒฐ:

List<User> users = queryFactory
    .selectFrom(qUser)
    .where(qUser.age.gt(20))
    .orderBy(qUser.name.asc())
    .offset(10)
    .limit(5)
    .fetch();

์ž๋™ SQL ๋ณ€ํ™˜:

SELECT * FROM user WHERE age > 20 ORDER BY name ASC LIMIT 5 OFFSET 10;

QueryDSL์˜ ์žฅ์  โญ :
1. ํƒ€์ž… ์•ˆ์ „ โ€” ์ปดํŒŒ์ผ ์‹œ์  ์˜ค๋ฅ˜ ๊ฒ€์ถœ
2. ์ž๋™์™„์„ฑ โ€” IDE ์ง€์›
3. ๋™์  ์ฟผ๋ฆฌ โ€” BooleanBuilder, ์กฐ๊ฑด๋ฌธ ์ž์œ ๋กญ๊ฒŒ
4. ์žฌ์‚ฌ์šฉ์„ฑ โ€” ๋ฉ”์„œ๋“œ๋กœ ์ถ”์ถœ ๊ฐ€๋Šฅ

์‹ค๋ฌด ํ‘œ์ค€ ์กฐํ•ฉ:

[Spring Data JPA] - ๋‹จ์ˆœ CRUD, ๋ฉ”์„œ๋“œ ์ด๋ฆ„ ์ฟผ๋ฆฌ
       +
[QueryDSL] - ๋ณต์žก ์ฟผ๋ฆฌ, ๋™์  ์ฟผ๋ฆฌ
       =
์‹ค๋ฌด JPA ํ”„๋กœ์ ํŠธ

ILIC ์‚ฌ๋ก€ (๊ฐ€๋Šฅ์„ฑ):

  • ๋‹จ์ˆœ CRUD: Spring Data JPA Repository
  • ๋ณต์žก ๊ฒ€์ƒ‰ (์šด์ž„ ๋‹ค์ค‘ ์กฐ๊ฑด ์กฐํšŒ): QueryDSL

์ž๊ธฐ ์ ๊ฒ€

  • QueryDSL ํ•™์Šต ๋น„์šฉ์ด ์žˆ์Œ์—๋„ ๊ถŒ์žฅ๋˜๋Š” ์ด์œ ๋Š”?
  • ILIC์˜ ์šด์ž„ ๊ฒ€์ƒ‰ ์กฐ๊ฑด์ด 6๊ฐœ๋ผ๋ฉด QueryDSL์ด ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”๊ฐ€? (ํžŒํŠธ: ๋™์  where)

๐ŸŽ“ ์ข…ํ•ฉ ์ž๊ธฐ ์ ๊ฒ€ (11-12์ฃผ์ฐจ ์กธ์—… ์‹œํ—˜)

Part A: 11์ฃผ์ฐจ

SQL Mapper์™€ ORM

  1. SQL Mapper์™€ ORM์˜ ๋งคํ•‘ ๋Œ€์ƒ ์ฐจ์ด๋Š”?
  2. JPA, Hibernate, Spring Data JPA์˜ ๊ด€๊ณ„๋Š”?
  3. ๊ฐ์ฒด-๊ด€๊ณ„ ํŒจ๋Ÿฌ๋‹ค์ž„ ๋ถˆ์ผ์น˜ 5๊ฐ€์ง€ ์ธก๋ฉด์€?

์—”ํ‹ฐํ‹ฐ ๋งคํ•‘

  1. @Entity์˜ 4๊ฐ€์ง€ ์กฐ๊ฑด์€?
  2. ์ž„๋ฒ ๋””๋“œ ํƒ€์ž…์„ ๊ฐ€๋ณ€์œผ๋กœ ๋งŒ๋“ค๋ฉด ์–ด๋–ค ์‚ฌ๊ณ ๊ฐ€?
  3. ddl-auto์˜ ์šด์˜ ํ™˜๊ฒฝ ๊ถŒ์žฅ๊ฐ’์€?

EntityManager์™€ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ

  1. EntityManagerFactory์™€ EntityManager์˜ ์ƒ๋ช…์ฃผ๊ธฐ ์ฐจ์ด๋Š”?
  2. ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์˜ ์ •์˜๋ฅผ ํ•œ ๋ฌธ์žฅ์œผ๋กœ?
  3. ์—”ํ‹ฐํ‹ฐ 4๊ฐ€์ง€ ์ƒํƒœ์™€ ์ „์ด ๋ฉ”์„œ๋“œ๋Š”?

4๊ฐ€์ง€ ์žฅ์  (โ˜…)

  1. 1์ฐจ ์บ์‹œ์˜ ๋™์ž‘ 6๋‹จ๊ณ„๋Š”?
  2. ๋™์ผ์„ฑ ๋ณด์žฅ์ด ๊ฐ€๋Šฅํ•œ ์ด์œ ๋Š”?
  3. ์“ฐ๊ธฐ ์ง€์—ฐ์ด ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š”?
  4. ๋ณ€๊ฒฝ ๊ฐ์ง€(Dirty Checking)์˜ ๋‚ด๋ถ€ ๋™์ž‘์€? (์Šค๋ƒ…์ƒท)
  5. ํ”Œ๋Ÿฌ์‹œ ๋ฐœ์ƒ 3๊ฐ€์ง€ ์‹œ์ ์€?
  6. 1์ฐจ ์บ์‹œ์™€ 2์ฐจ ์บ์‹œ์˜ ์ฐจ์ด 4๊ฐ€์ง€๋Š”?

Part B: 12์ฃผ์ฐจ

์—ฐ๊ด€๊ด€๊ณ„

  1. 4๊ฐ€์ง€ ์—ฐ๊ด€๊ด€๊ณ„์™€ ๊ฐ๊ฐ์˜ ์‚ฌ์šฉ ์‹œ์ ์€?
  2. ๋‹จ๋ฐฉํ–ฅ๊ณผ ์–‘๋ฐฉํ–ฅ์˜ ๊ฐ์ฒด ์ž…์žฅ vs DB ์ž…์žฅ ์ฐจ์ด๋Š”?
  3. N:M์„ ์‹ค๋ฌด์—์„œ ์•ˆ ์“ฐ๋Š” ์ด์œ ์™€ ๋Œ€์•ˆ์€?

mappedBy

  1. ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ์ด ํ•„์š”ํ•œ ์ด์œ ๋Š”?
  2. mappedBy์˜ ๊ฐ’์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์€?
  3. ์–‘์ชฝ์„ ํ•จ๊ป˜ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋Š” ์ด์œ ๋Š”? (ํžŒํŠธ: 1์ฐจ ์บ์‹œ)

ํ”„๋ก์‹œ์™€ ๋กœ๋”ฉ

  1. em.find()์™€ em.getReference()์˜ ์ฐจ์ด๋Š”?
  2. ํ”„๋ก์‹œ ๋น„๊ต์— instanceof๋ฅผ ์“ฐ๋Š” ์ด์œ ๋Š”?
  3. 4๊ฐ€์ง€ ์—ฐ๊ด€๊ด€๊ณ„์˜ ๊ธฐ๋ณธ fetch ์ „๋žต์€? (์™ธ์šธ ๊ฒƒ)
  4. ๋ชจ๋“  ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ LAZY๋กœ ๋ช…์‹œํ•˜๋ผ๋Š” ๊ถŒ์žฅ์˜ ์ด์œ ๋Š”?

N+1 ๋ฌธ์ œ (โ˜…)

  1. N+1 ๋ฌธ์ œ์˜ ์ •์˜๋ฅผ ํ•œ ๋ฌธ์žฅ์œผ๋กœ?
  2. ์ฆ‰์‹œ ๋กœ๋”ฉ๊ณผ ์ง€์—ฐ ๋กœ๋”ฉ ๋ชจ๋‘์—์„œ N+1์ด ๋ฐœ์ƒํ•˜๋Š” ์ด์œ ๋Š”?
  3. JOIN๊ณผ FETCH JOIN์˜ ๊ฒฐ์ •์  ์ฐจ์ด๋Š”?
  4. OneToMany + ํŽ˜์ด์ง• + fetch join ์‚ฌ์šฉ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ํ•จ์ •์€?
  5. @BatchSize๊ฐ€ OneToMany ํŽ˜์ด์ง• ํ•จ์ •์„ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋Š”๊ฐ€?

CASCADE์™€ ์ฟผ๋ฆฌ ๋„๊ตฌ

  1. CASCADE.REMOVE์™€ orphanRemoval์˜ ์ฐจ์ด๋Š”?
  2. JPQL์ด SQL๊ณผ ๋‹ค๋ฅธ ๋ณธ์งˆ์  ์ฐจ์ด๋Š”?
  3. QueryDSL์„ ๊ถŒ์žฅํ•˜๋Š” ์ด์œ  3๊ฐ€์ง€๋Š”?

๐Ÿ“Œ ํ•™์Šต ์šด์˜ ํŒ

9-์„น์…˜ ๋งˆ์Šคํ„ฐ ํ”„๋กฌํ”„ํŠธ๋กœ ๊นŠ์ด ํŒŒ์•ผ ํ•  Unit

โ˜…โ˜…โ˜… ๋ฉด์ ‘ยท์‹ค๋ฌด ๋‹จ๊ณจ (๋ฐ˜๋“œ์‹œ):

  • Unit 5.4 โ€” ๋ณ€๊ฒฝ ๊ฐ์ง€(Dirty Checking) ๋‚ด๋ถ€ ๋™์ž‘
  • Unit 6.3 โ€” N:1 ManyToOne (๊ฐ€์žฅ ์ž์ฃผ ์‚ฌ์šฉ)
  • Unit 7.2 โ€” mappedBy์™€ ์—ฐ๊ด€๊ด€๊ณ„์˜ ์ฃผ์ธ
  • Unit 8.4 โ€” LAZY/EAGER ๊ธฐ๋ณธ๊ฐ’๊ณผ ๊ถŒ์žฅ
  • Unit 9.1~9.4 โ€” N+1 ๋ฌธ์ œ์™€ 4๊ฐ€์ง€ ํ•ด๊ฒฐ์ฑ…
  • Unit 10.4 โ€” QueryDSL

โ˜…โ˜… ๋งค์šฐ ๊ถŒ์žฅ:

  • Unit 5.1 โ€” 1์ฐจ ์บ์‹œ
  • Unit 5.5 โ€” ํ”Œ๋Ÿฌ์‹œ
  • Unit 6.5 โ€” N:M ์ค‘๊ฐ„ ์—”ํ‹ฐํ‹ฐ ํŒจํ„ด
  • Unit 8.2 โ€” ํ”„๋ก์‹œ ๋ฉ”์ปค๋‹ˆ์ฆ˜

Phase๋ณ„ ์ง„๋„ ์ฒดํฌ๋ฆฌ์ŠคํŠธ

[ Part A โ€” 11์ฃผ์ฐจ ]
[ ] Phase 1 โ€” ์‹ฑ๊ธ€ํ†ค + SQL Mapper์˜ ์—ญ์‚ฌ (Unit 1.1~1.3)
[ ] Phase 2 โ€” ORM/JPA ๋ณธ์งˆ (Unit 2.1~2.3)
[ ] Phase 3 โ€” ์—”ํ‹ฐํ‹ฐ ๋งคํ•‘ (Unit 3.1~3.4)
[ ] Phase 4 โ€” EntityManager + ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ (Unit 4.1~4.4)
[ ] Phase 5 โ€” 4๊ฐ€์ง€ ์žฅ์  (Unit 5.1~5.5)  โ˜… 11์ฃผ์ฐจ ์ •์ 

[ Part B โ€” 12์ฃผ์ฐจ ]
[ ] Phase 6 โ€” 4๊ฐ€์ง€ ์—ฐ๊ด€๊ด€๊ณ„ (Unit 6.1~6.5)
[ ] Phase 7 โ€” mappedBy (Unit 7.1~7.3)
[ ] Phase 8 โ€” ํ”„๋ก์‹œ์™€ ๋กœ๋”ฉ (Unit 8.1~8.4)
[ ] Phase 9 โ€” N+1 ๋ฌธ์ œ์™€ ํ•ด๊ฒฐ (Unit 9.1~9.4)  โ˜… 12์ฃผ์ฐจ ์ •์ 
[ ] Phase 10 โ€” CASCADE + JPQL/QueryDSL (Unit 10.1~10.4)

[ ] ์ข…ํ•ฉ ์ž๊ธฐ ์ ๊ฒ€ 33๋ฌธํ•ญ ํ†ต๊ณผ

11-12์ฃผ์ฐจ์˜ ๋‘ ์ •์ 

11์ฃผ์ฐจ ์ •์  โ€” Phase 5 (4๊ฐ€์ง€ ์žฅ์ ):

  • JPA์˜ ํ•ต์‹ฌ ๊ฐ€์น˜๋ฅผ ์ดํ•ดํ•˜๋Š” ์ง€์ 
  • 1์ฐจ ์บ์‹œ โ†’ ๋™์ผ์„ฑ โ†’ ์“ฐ๊ธฐ ์ง€์—ฐ โ†’ ๋ณ€๊ฒฝ ๊ฐ์ง€์˜ ์—ฐ์‡„
  • "์™œ JPA๊ฐ€ ๊ฐ•๋ ฅํ•œ๊ฐ€"์˜ ๋‹ต

12์ฃผ์ฐจ ์ •์  โ€” Phase 9 (N+1 ๋ฌธ์ œ):

  • JPA ์‹ค๋ฌด์˜ ์ตœ๋Œ€ ํ•จ์ •
  • fetch join, @BatchSize ์˜ ๊ฒฐ์ •
  • ๋ฉด์ ‘ยท์‹ค๋ฌด ๋ชจ๋‘์—์„œ ๊ฐ€์žฅ ์ค‘์š”

1~12์ฃผ์ฐจ ํ†ตํ•ฉ ํ๋ฆ„์˜ ์ ˆ์ • (๋‹ค์‹œ)

Java ํ•™์Šต์˜ ๋˜ ํ•˜๋‚˜์˜ ํด๋ผ์ด๋งฅ์Šค:

  • 1~3์ฃผ์ฐจ: ์ž๋ฐ” ์–ธ์–ด
  • 4์ฃผ์ฐจ: ๋™์‹œ์„ฑ
  • 5์ฃผ์ฐจ: Spring ์ž…๋ฌธ
  • 6์ฃผ์ฐจ: DB ์ ‘๊ทผ ์ง„ํ™”
  • 7์ฃผ์ฐจ: JPA ์ž…๋ฌธ + ํŠธ๋žœ์žญ์…˜
  • 8-9์ฃผ์ฐจ: AOP ๋ฉ”์ปค๋‹ˆ์ฆ˜ (โ˜…)
  • 10์ฃผ์ฐจ: ํŠธ๋žœ์žญ์…˜ ๋งˆ๋ฌด๋ฆฌ
  • 11-12์ฃผ์ฐจ: JPA ์™„์ „ ์ •๋ณต (โ˜…โ˜…)

โ†’ 8-9์ฃผ์ฐจ๊ฐ€ AOP์˜ ์ •์ , 11-12์ฃผ์ฐจ๊ฐ€ JPA์˜ ์ •์ 

ํ•™์Šต ์‹œ ์ฃผ์˜

์ด๋ฒˆ 2์ฃผ์ฐจ๋Š” ๋ฐ˜๋“œ์‹œ SQL ๋กœ๊ทธ๋ฅผ ์ผœ๊ณ  ํ•™์Šตํ•˜์„ธ์š”:

spring:
  jpa:
    show-sql: true
    properties:
      hibernate:
        format_sql: true
        use_sql_comments: true
logging:
  level:
    org.hibernate.SQL: DEBUG
    org.hibernate.type.descriptor.sql.BasicBinder: TRACE

ํŠนํžˆ Phase 5 (4๊ฐ€์ง€ ์žฅ์ ) ์™€ Phase 9 (N+1) ๋Š” SQL ๋กœ๊ทธ ์—†์ด๋Š” ์ดํ•ด ๋ถˆ๊ฐ€๋Šฅ. ์ง์ ‘ ์‹คํ–‰ํ•˜๋ฉด์„œ ์ฟผ๋ฆฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋‚˜๊ฐ€๋Š”์ง€๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•˜์„ธ์š”.


profile
Software Developer

0๊ฐœ์˜ ๋Œ“๊ธ€