π‘ JPA Dirty Checking(λν° μ²΄νΉ) μλ²½ μ 리
μλ νμΈμ! μ€λμ JPAμ ν΅μ¬ κΈ°λ₯ μ€ νλμΈ μμμ± μ»¨ν μ€νΈ(Persistence Context),
κ·Έμ€μμλ λ°μ΄ν° μμ μ μλνν΄ μ£Όλ λν° μ²΄νΉ(Dirty Checking)μ λν΄ κΉμ΄ μκ² λ€λ€λ³΄κ² μ΅λλ€.
1. JPA Dirty Checking(λν° μ²΄νΉ)μ΄λ?
'Dirty'λ "μνκ° λ³κ²½λ¨"μ, 'Checking'μ "κ²μ¬ν¨"μ μλ―Έν©λλ€.
μ¦, μν°ν°μ μν λ³νλ₯Ό κ°μ§ν΄μ μλμΌλ‘ λ°μ΄ν°λ² μ΄μ€μ λ°μνλ λ©μ»€λμ¦μ λλ€.
λλΆμ κ°λ°μλ λ³λμ UPDATE 쿼리λ₯Ό μ§μ μμ±νμ§ μμλ κ°μ²΄μ κ°λ§ λ°κΎΈλ κ²μΌλ‘ λ°μ΄ν°λ₯Ό μμ ν μ μμ΅λλ€.
2. λμ μ리: μ€λ μ·(Snapshot) λΉκ΅
λν° μ²΄νΉμ ν΅μ¬μ μμμ± μ»¨ν μ€νΈ λ΄λΆμ μ μ₯λλ μ€λ μ·μ μμ΅λλ€.

- μν°ν° μ‘°ν (Snapshot μμ±): DBμμ λ°μ΄ν°λ₯Ό μ‘°ννλ©΄ JPAλ μν°ν°λ₯Ό μμμ± μ»¨ν μ€νΈμ λ΄μΌλ©΄μ, μ΅μ΄ μνλ₯Ό 볡μ¬ν μ€λ μ·μ λ¨κΉλλ€.
- μν°ν° μμ : μ ν리μΌμ΄μ λ‘μ§μμ μν°ν°μ κ°μ λ³κ²½ν©λλ€. μ΄λ λ©λͺ¨λ¦¬μμ κ°μ²΄ κ°μ λ°λμ§λ§ DBμλ μμ§ λ°μλμ§ μμ΅λλ€.
- Flush μμ (λΉκ΅ λ° λ°μ): νΈλμμ μ΄ λλλ μμ μ flush()κ° νΈμΆλλ©΄, JPAλ νμ¬ μν°ν°μ κ°κ³Ό μ΅μ΄μ μ€λ μ·μ λμ‘°ν©λλ€.
- UPDATE μ€ν: λ³κ²½ μ¬νμ΄ νμΈλλ©΄ μ¦μ UPDATE SQLμ μμ±νμ¬ DBμ λ°μν©λλ€.
3. @DynamicUpdateμ 쿼리 μ¬μ¬μ©
κΈ°λ³Έμ μΌλ‘ JPAλ λͺ¨λ νλλ₯Ό μ λ°μ΄νΈνλ 쿼리λ₯Ό μμ±ν©λλ€.
π‘ μ λͺ¨λ νλλ₯Ό μ λ°μ΄νΈν κΉ?
- 쿼리 μ¬μ¬μ©: νλ μ‘°ν©μ΄ λ¬λΌλ μΏΌλ¦¬κ° νμ λμΌνλ―λ‘, λ°μ΄ν°λ² μ΄μ€κ° μ΄μ μ λ§λ μ€ν κ³νμ μ¬μ¬μ©(Parsing/Caching)ν μ μμ΅λλ€.
- μΌκ΄μ±: μ 체 λ°μ΄ν° ꡬ쑰λ₯Ό νμ νκΈ° λͺ νν©λλ€.
π‘ @DynamicUpdateλ μΈμ μΈκΉ?
λ§μ½ νλκ° λ무 λ§μ(μ: 30κ° μ΄μ) λ³κ²½λ νλλ§ μΏΌλ¦¬μ λ°μνκ³ μΆλ€λ©΄ ν΄λμ€ μλ¨μ @DynamicUpdateλ₯Ό μ¬μ©νλ©΄ λ©λλ€.
- μμ λ νλλ§ UPDATE 쿼리μ ν¬ν¨λ©λλ€.
- λ°μ΄ν°λ² μ΄μ€ λ‘κΉ μ©λμ΄ λ―Όκ°νκ±°λ μ μ‘ λ°μ΄ν°λμ μ΅μ νν΄μΌ ν λ μ 리ν©λλ€.
4. λν° μ²΄νΉμ΄ μλνμ§ μλλ€λ©΄? (Check List)
μ½λλ₯Ό κ³ μ³€λλ° DBκ° κ·Έλλ‘λΌλ©΄ λ€μ λ κ°μ§λ₯Ό λ¨Όμ νμΈνλκ² μ’μ΅λλ€.
- @Transactional λΆμ¬: λν° μ²΄νΉμ νΈλμμ λ²μ λ΄μμλ§ μΌμ΄λ©λλ€.
- readOnly = true μ΅μ : @Transactional(readOnly = true) μ€μ μ, μ€νλ§μ μ±λ₯ μ΅μ νλ₯Ό μν΄ μ€λ μ·μ μ°μ§ μμΌλ―λ‘ λ³κ²½ κ°μ§κ° μΌμ΄λμ§ μμ΅λλ€.
5. λͺ μμ μ²λ¦¬κ° νμν μμΈ μΌμ΄μ€
β save()λ₯Ό νΈμΆν΄μΌ νλ κ²½μ°
- μ€μμ μν μμ : μΈλΆ(DTO)μμ λμ΄μ¨ κ°μ²΄λ μΈμ μ μ μ₯λμλ μν°ν° λ± μμμ± μ»¨ν μ€νΈκ° κ΄λ¦¬νμ§ μλ κ°μ²΄λ₯Ό μμ ν λ.
- μλ‘μ΄ μν°ν° λ±λ‘: DBμ μλ κ°μ²΄λ₯Ό μ²μ μ μ₯ν λλ λ°λμ save()λ₯Ό ν΅ν΄ μμ μνλ‘ λ§λ€μ΄μΌ ν©λλ€.
- Tip: μ€μμ κ°μ²΄λ₯Ό μμ ν λλ save()λ₯Ό ν΅ν merge보λ€, IDλ‘ λ€μ μ‘°ν(find)νμ¬ μμ μνμμ μμ νλ λ°©μμ΄ λ°μ΄ν° μ μ€ λ°©μ§ μΈ‘λ©΄μμ ν¨μ¬ μμ ν©λλ€.
β‘ flush()λ₯Ό νΈμΆν΄μΌ νλ κ²½μ°
- ID κ°μ μ¦μ νμΈ: MySQLμ Auto-increment μ¬μ© μ, λ‘μ§ μ€κ°μ μμ±λ IDκ° νμνλ€λ©΄ κ°μ λ‘ flush()λ₯Ό νΈμΆν΄μΌ ν©λλ€.
- λ³΅ν© μΏΌλ¦¬ μν: λμΌ νΈλμμ λ΄μμ μν°ν° μμ ν JPQLμ΄λ Native Queryλ₯Ό λ 릴 λ λ°μ΄ν° μ ν©μ±μ μν΄ μ¬μ©ν©λλ€.
λ§λ¬΄λ¦¬
κ²°κ΅ JPAμ λν° μ²΄νΉμ κ°λ°μκ° 'λ°μ΄ν°μ μ μ₯'μ΄λΌλ κ΄μ λ³΄λ€ 'κ°μ²΄μ μν'μ μ§μ€ν μ μκ² ν΄μ£Όλ κ°μ²΄ μ§ν₯μ μΈ κΈ°λ₯μ λλ€.
νΈλμμ μ λ²μμ μν°ν°μ μλͺ μ£ΌκΈ°λ₯Ό μ νν μ΄ν΄νκ³ μ¬μ©νλ€λ©΄, ν¨μ¬ λ κ°κ²°νκ³ μμ ν μ½λλ₯Ό μμ±ν μ μμ΅λλ€ :)
λ³Έ ν¬μ€ν μ μμμ± μ»¨ν μ€νΈμ μν°ν° λ§€λμ μ κ΄λ¦¬ λ©μ»€λμ¦μ κΈ°λ°μΌλ‘ μμ±λμμ΅λλ€.