Skip to content

Latest commit

Β 

History

History
199 lines (124 loc) Β· 8.73 KB

13.md

File metadata and controls

199 lines (124 loc) Β· 8.73 KB

13. μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜κ³Ό μ˜μ†μ„± 관리

πŸ”« 이 글은 κΉ€μ˜ν•œλ‹˜μ˜ 'μžλ°” ORM ν‘œμ€€ JPA ν”„λ‘œκ·Έλž˜λ°'을 κ³΅λΆ€ν•˜λ©° μ •λ¦¬ν•œ κ²ƒμž„μ„ μ•Œλ¦½λ‹ˆλ‹€.


13.1 νŠΈλžœμž­μ…˜ λ²”μœ„μ˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ

  • J2SE ν™˜κ²½μ—μ„œ JPA κ°œλ°œμ—λŠ” 직접 μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό μƒμ„±ν•˜κ³  νŠΈλžœμž­μ…˜μ„ 관리
  • μŠ€ν”„λ§ ν˜Ήμ€ J2EE μ»¨ν…Œμ΄λ„ˆ ν™˜κ²½μ—μ„œ JPAλ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ»¨ν…Œμ΄λ„ˆκ°€ μ œκ³΅ν•˜λŠ” μ „λž΅μ„ 따름

13.1.1 μŠ€ν”„λ§ μ»¨ν…Œμ΄λ„ˆμ˜ κΈ°λ³Έ μ „λž΅

  • μŠ€ν”„λ§μ˜ 경우 νŠΈλžœμž­μ…˜ λ²”μœ„μ˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ „λž΅μ„ 기본으둜 μ‚¬μš©

  • νŠΈλžœμž­μ…˜ λ²”μœ„μ˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ β†’ νŠΈλžœμž­μ…˜ λ²”μœ„μ™€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ˜ 생쑴 λ²”μœ„κ°€ κ°™μŒ
    같은 νŠΈλžœμž­μ…˜ μ•ˆμ—μ„œλŠ” 항상 같은 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈμ— μ ‘κ·Ό

    • λ‹€μ–‘ν•œ μœ„μΉ˜μ—μ„œ μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό μ£Όμž…λ°›μ•„ μ‚¬μš©ν•΄λ„ νŠΈλžœμž­μ…˜μ΄ 같을 μ‹œμ—λŠ” 항상 같은 μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ μ‚¬μš©
    • μ—¬λŸ¬ μŠ€λ ˆλ“œμ—μ„œ λ™μ‹œ μš”μ²­μ΄ μ™€μ„œ 같은 μ—”ν‹°ν‹° λ§€λ‹ˆμ €λ₯Ό μ‚¬μš©ν•΄λ„ νŠΈλžœμž­μ…˜μ— 따라 μ ‘κ·Όν•˜λŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ 닀름(λ©€ν‹° μŠ€λ ˆλ“œ μƒν™©μ—μ„œ μ•ˆμ „)
  • μŠ€ν”„λ§μ—μ„œλŠ” @Transactional μ–΄λ…Έν…Œμ΄μ…˜μ„ μ‚¬μš©ν•˜μ—¬ νŠΈλžœμž­μ…˜μ˜ λ²”μœ„λ₯Ό 지정
    즉, μ–΄λ…Έν…Œμ΄μ…˜μ΄ 뢙은 λ©”μ†Œλ“œλ₯Ό μ‹€ν–‰ν•˜κΈ° 직전에 νŠΈλžœμž­μ…˜ AOPκ°€ λ™μž‘ν•˜μ—¬ νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•˜κ³ , λ©”μ†Œλ“œκ°€ μ •μƒμ μœΌλ‘œ μ’…λ£Œλ˜μ—ˆμ„ λ•ŒλŠ” νŠΈλžœμž­μ…˜μ„ 컀밋(μ»€λ°‹ν•˜κΈ° 전에 λ¨Όμ € μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό ν”ŒλŸ¬μ‹œ)

  • λ§Œμ•½ 쀑간에 μ˜ˆμ™Έ λ°œμƒμ‹œμ—λŠ” νŠΈλžœμž­μ…˜μ„ λ‘€λ°±ν•˜κ³  μ’…λ£Œ(μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ ν”ŒλŸ¬μ‹œ X)


13.2 μ€€μ˜μ† μƒνƒœμ™€ 지연 λ‘œλ”©

  • νŠΈλžœμž­μ…˜μ΄ μ‚΄μ•„μžˆλŠ” μ„œλΉ„μŠ€ 계측과 λ ˆν¬μ§€ν† λ¦¬ κ³„μΈ΅μ—μ„œ μ—”ν‹°ν‹°λŠ” μ˜μ† μƒνƒœ
    반면 ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅μ—μ„œ μ—”ν‹°ν‹°λŠ” μ€€μ˜μ† μƒνƒœ
    λ”°λΌμ„œ ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅μ—μ„œλŠ” λ³€κ²½ 감지와 지연 λ‘œλ”© X

  • ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅μ—μ„œλ„ 이λ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ—¬λŸ¬κ°€μ§€ 방법이 쑴재

    1. κΈ€λ‘œλ²Œ 페치 μ „λž΅ μˆ˜μ •

      • 지연 λ‘œλ”© β†’ μ¦‰μ‹œ λ‘œλ”©

      • 이 λ•Œ λ°œμƒν•  수 μžˆλŠ” 문제 2가지

        1. μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ—”ν‹°ν‹°λ₯Ό λ‘œλ”©

          AλΌλŠ” λ·°μ—μ„œλŠ” Order와 Member λ‘˜ λ‹€ μ‚¬μš© BλΌλŠ” λ·°μ—μ„œλŠ” Order만 μ‚¬μš©

          μ¦‰μ‹œ λ‘œλ”© μ „λž΅μœΌλ‘œ 인해 Bμ—μ„œλŠ” Order, Member λ‘˜ λ‹€ λ‘œλ”©

        2. N+1 문제 λ°œμƒ(JPQL μ‚¬μš©μ‹œ)

          JPAκ°€ JPQL을 λΆ„μ„ν•˜μ—¬ SQL을 생성할 λ•Œ κΈ€λ‘œλ²Œ 페치 μ „λž΅μ„ μ°Έκ³  X

          λ”°λΌμ„œ Order을 λ¨Όμ € κ°€μ Έμ˜€κ³  λ‚˜μ„œ Member의 μ „λž΅μ΄ μ¦‰μ‹œ λ‘œλ”©μ΄λ―€λ‘œ κ·Έμ œμ„œμ•Ό Memberλ₯Ό κ°€μ Έμ˜΄
          이 λ•Œ, Member의 수만큼 SQL문이 λ°œμƒν•˜λ―€λ‘œ 이λ₯Ό N+1이라고 함

          μ΄λŠ” JPQL 페치 쑰인으둜 ν•΄κ²° κ°€λŠ₯

    2. JPQL 페치 쑰인

      • Join λͺ…λ Ήμ–΄ λ§ˆμ§€λ§‰μ— fetchλ₯Ό λ„£μ–΄μ£Όλ©΄ 됨
      • N+1 문제λ₯Ό ν•΄κ²°ν•˜λ©΄μ„œ 화면에 ν•„μš”ν•œ μ—”ν‹°ν‹°λ₯Ό 미리 λ‘œλ”©ν•˜λŠ” ν˜„μ‹€μ μΈ 방법
      • λ¬΄λΆ„λ³„ν•˜κ²Œ μ‚¬μš©μ‹œ 화면에 맞좘 λ ˆν¬μ§€ν† λ¦¬ λ©”μ†Œλ“œκ°€ 증가
        즉, 뷰와 λ ˆν¬μ§€ν† λ¦¬ κ°„μ˜ 논리적인 μ˜μ‘΄μ„±μ΄ λ°œμƒ
    3. κ°•μ œ μ΄ˆκΈ°ν™”

      • μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μ‚΄μ•„μžˆμ„ λ•Œ ν”„λ¦¬μ  ν…Œμ΄μ…˜ 계측이 ν•„μš”ν•œ μ—”ν‹°ν‹°λ₯Ό κ°•μ œλ‘œ μ΄ˆκΈ°ν™”

        @Transactional
        public Order findOrder(Long id) {
            Order o = orderRepository.findOrder(id);
            o.getMember().getName(); // ν”„λ‘μ‹œ 객체 κ°•μ œ μ΄ˆκΈ°ν™”
            return o;
        }
      • ν•˜μ΄λ²„λ„€μ΄νŠΈλ₯Ό μ‚¬μš©ν•˜λ©΄ initialize() λ©”μ†Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ ν”„λ‘μ‹œλ₯Ό κ°•μ œλ‘œ μ΄ˆκΈ°ν™”(JPA ν‘œμ€€μ—μ„  μ—†μŒ)

      • μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ ν”„λ¦¬μ  ν…Œμ΄μ…˜ 계측에 ν•„μš”ν•œ μ—”ν‹°ν‹°λ₯Ό μ΄ˆκΈ°ν™” ν•œλ‹€λ©΄ μ„œλΉ„μŠ€κ°€ ν”„λ¦¬μ  ν…Œμ΄μ…˜μ— μ’…μ†μ μ΄κ²Œ λ˜λ―€λ‘œ 쀑간 계측을 두어 뢄리, 이가 λ°”λ‘œ FACADE 계측

    4. FACADE(νΌμ‚¬λ“œ) 계측 μΆ”κ°€

      • ν”„λ¦¬μ  ν…Œμ΄μ…˜ 계측과 도메인 λͺ¨λΈ 계측(μ„œλΉ„μŠ€, λ ˆν¬μ§€ν† λ¦¬) κ°„μ˜ 논리적 μ˜μ‘΄μ„± 뢄리

      • ν”„λ‘μ‹œ 객체λ₯Ό μ΄ˆκΈ°ν™”

      • λ ˆν¬μ§€ν† λ¦¬λ₯Ό 직접 ν˜ΈμΆœν•˜μ—¬ λ·°κ°€ μš”κ΅¬ν•˜λŠ” μ—”ν‹°ν‹°λ₯Ό 검색

      • κ²°κ³Όμ μœΌλ‘œλŠ” μ½”λ“œλ₯Ό 더 많이 μž‘μ„±ν•˜λŠ” 것은 κ°™μŒ

  • 이 λͺ¨λ“  λ¬Έμ œλŠ” μ—”ν‹°ν‹°κ°€ ν”„λ¦¬μ  ν…Œμ΄μ…˜μ—μ„œλŠ” μ€€μ˜μ† μƒνƒœμ΄κΈ° λ•Œλ¬Έμ— λ°œμƒ


13.3 OSIV(Open Session In View)

  • OSIVλŠ” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅κΉŒμ§€ μ—΄μ–΄ λ†“λŠ” 것을 λœ»ν•¨
    λ”°λΌμ„œ λ·°μ—μ„œλ„ 지연 λ‘œλ”©κ³Ό λ³€κ²½ 감지등 μ‚¬μš© κ°€λŠ₯
  • OSIVλŠ” ν•˜μ΄λ²„λ„€μ΄νŠΈμ—μ„œ μ‚¬μš©ν•˜λŠ” μ–Έμ–΄λ‘œ JPAμ—μ„œλŠ” OEIV(Open EntityManager In View)라고 함

13.3.1 κ³Όκ±° OSIV(μš”μ²­ λ‹Ή νŠΈλžœμž­μ…˜)

  • ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ΄ λ“€μ–΄μ˜€μžλ§ˆμž μ„œλΈ”λ¦Ώ ν•„ν„° ν˜Ήμ€ μŠ€ν”„λ§ μΈν„°μ…‰ν„°μ—μ„œ νŠΈλžœμž­μ…˜μ„ μ‹œμž‘, μš”μ²­μ΄ λλ‚˜λ©΄ νŠΈλžœμž­μ…˜λ„ 끝
    이λ₯Ό μš”μ²­ λ‹Ή νŠΈλžœμž­μ…˜ OSIV라고 함

  • 이에 κ°€μž₯ 큰 λ¬Έμ œμ μ€ ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅μ—μ„œ μ—”ν‹°ν‹° 변경이 κ°€λŠ₯ν•˜λ‹€λŠ” 것

    ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅μ—μ„œ μ—”ν‹°ν‹°λ₯Ό λ³€κ²½ν•œ λ’€ μš”μ²­μ„ 끝내면 μ˜λ„ν•œ 것이 μ•„λ‹ˆλ”λΌλ„ λ°μ΄ν„°λ² μ΄μŠ€μ— 반영이 κ°€λŠ₯

  • μ΄λ‘œμΈν•΄ μœ μ§€λ³΄μˆ˜κ°€ μƒλ‹Ήνžˆ νž˜λ“€μ–΄μ§€λ―€λ‘œ λ‹€μŒκ³Ό 같은 방법을 μ‚¬μš©

    1. μ—”ν‹°ν‹°λ₯Ό 읽기 μ „μš© μΈν„°νŽ˜μ΄μŠ€λ‘œ 제곡

      • 읽기 μ „μš© λ©”μ†Œλ“œλ§Œ μ œκ³΅ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό ν”„λ¦¬μ  ν…Œμ΄μ…˜ 계측에 제곡

        interface MemberView {
            public String getName();
        }
        
        @Entity
        class Member implements MemberView {
            ...
        }
        
        class MemberService {
            public MemberView getMember(Long id) {
                return memberRepository.findById(id);
            }
        }
    2. μ—”ν‹°ν‹° λž˜ν•‘

      • μ—”ν‹°ν‹°μ˜ 읽기 μ „μš© λ©”μ†Œλ“œλ§Œ 가지고 μžˆλŠ” μ—”ν‹°ν‹°λ₯Ό 감싼 객체λ₯Ό λ§Œλ“€κ³  이λ₯Ό λ°˜ν™˜

        class MemberWrapper {
            private Member m;
            
            public MemberWrapper(Member m) {
                this.m = m;
            }
            
            public String getName() {
                return m.getName();
            }
        }
    3. DTO λ°˜ν™˜

      • κ°€μž₯ 전톡적인 λ°©λ²•μœΌλ‘œ λ‹¨μˆœν•œ λ°μ΄ν„°λ§Œ μ „λ‹¬ν•˜λŠ” DTOλ₯Ό μƒμ„±ν•˜μ—¬ λ°˜ν™˜
      • OSIVλ₯Ό μ‚¬μš©ν•˜λŠ” μž₯점을 살릴 수 μ—†κ³  μ—”ν‹°ν‹°λ₯Ό λ³΅μ‚¬ν•œ λ“―ν•œ DTO 클래슀λ₯Ό λ§Œλ“€μ–΄μ•Ό ν•˜λŠ” 단점
  • μ΄λŸ¬ν•œ λ¬Έμ œμ λ“€μ„ λ³΄μ•ˆν•˜κΈ° μœ„ν•΄ λΉ„μ§€λ‹ˆμŠ€ κ³„μΈ΅μ—μ„œλ§Œ νŠΈλžœμž­μ…˜μ„ μœ μ§€ν•˜λŠ” λ°©μ‹μ˜ OSIVλ₯Ό μ‚¬μš©(μŠ€ν”„λ§μ—μ„œ μ œκ³΅ν•˜λŠ” OSIV)

13.3.2 μŠ€ν”„λ§ OSIV(λΉ„μ§€λ‹ˆμŠ€ 계측 νŠΈλžœμž­μ…˜)

  • spring-orm.jar μ—μ„œλŠ” λ‹€μ–‘ν•œ OSIV 클래슀 제곡

  • OSIVλ₯Ό μ‚¬μš©ν•˜μ§€λ§Œ νŠΈλžœμž­μ…˜μ€ λΉ„μ§€λ‹ˆμŠ€ κ³„μΈ΅μ—μ„œλ§Œ μ‚¬μš©

  • λ™μž‘ 원리

    1. ν΄λΌμ΄μ–ΈνŠΈμ˜ μš”μ²­μ΄ λ“€μ–΄μ˜€λ©΄ μ„œλΈ”λ¦Ώ ν•„ν„°λ‚˜ μŠ€ν”„λ§ μΈν„°μ…‰ν„°μ—μ„œ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ 생성
    2. μ„œλΉ„μŠ€ κ³„μΈ΅μ—μ„œ @Transactional 둜 μΈν•˜μ—¬ νŠΈλžœμž­μ…˜μ΄ μ‹œμž‘ν•  λ•Œ, 미리 생성해 λ‘” μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό 찾아와 μ‹œμž‘
    3. μ„œλΉ„μŠ€ 계측이 λλ‚˜λ©΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈ ν”ŒλŸ¬μ‹œ 및 νŠΈλžœμž­μ…˜ 컀밋, μ’…λ£Œ
    4. ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅κΉŒμ§€ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈκ°€ μœ μ§€λ˜λ―€λ‘œ μ—”ν‹°ν‹°λŠ” μ˜μ† μƒνƒœ μœ μ§€
    5. λͺ¨λ“  μž‘μ—…μ΄ λλ‚˜κ³  μ„œλΈ”λ¦Ώ ν•„ν„° ν˜Ήμ€ μŠ€ν”„λ§ 인터셉터에 응닡이 κ°€λ©΄ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό μ’…λ£Œ, ν”ŒλŸ¬μ‹œ X
  • μ—”ν‹°ν‹°λ₯Ό λ³€κ²½ν•˜μ§€ μ•Šκ³  λ‹¨μˆœνžˆ μ‘°νšŒν•  λ•ŒλŠ” νŠΈλžœμž­μ…˜μ΄ ν•„μš” X, 이λ₯Ό νŠΈλžœμž­μ…˜ 없이 읽기라고 함

  • λ§Œμ•½ ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅μ—μ„œ μ—”ν‹°ν‹°λ₯Ό μˆ˜μ •ν•˜κ³  νŠΈλžœμž­μ…˜μ„ μ‹œμž‘ν•˜λŠ” μ„œλΉ„μŠ€ 계측을 ν˜ΈμΆœν•˜λ©΄ 문제 λ°œμƒ

    미리 λ³€κ²½ 후에 νŠΈλžœμž­μ…˜ μ•ˆμœΌλ‘œ λ“€μ–΄κ°€ ν”ŒλŸ¬μ‹œκ°€ 될 수 있기 λ•Œλ¬Έ

  • μ—¬λŸ¬ νŠΈλžœμž­μ…˜μ΄ ν•˜λ‚˜μ˜ μ˜μ†μ„± μ»¨ν…μŠ€νŠΈλ₯Ό κ³΅μœ ν•˜λ―€λ‘œ 주의(특히 νŠΈλžœμž­μ…˜ λ‘€λ°± μ‹œ 주의)

  • κΌ­ OSIV만이 닡은 μ•„λ‹˜, μ—¬λŸ¬κ°€μ§€ μ—”ν‹°ν‹°λ₯Ό μ‚¬μš©ν•˜λŠ” 뷰의 경우 JPQL을 μž‘μ„±ν•˜μ—¬ DTO둜 μ‘°νšŒν•˜λŠ” 것이 더 효과적

  • JVM을 λ²—μ–΄λ‚œ ν™˜κ²½(μ™ΈλΆ€ API 호좜 μ‹œ)μ—μ„œλŠ” OSIVλ₯Ό μ‚¬μš©ν•  수 μ—†κΈ° λ•Œλ¬Έμ— μ—”ν‹°ν‹°λ₯Ό 직접 λ…ΈμΆœν•˜λŠ” 것이 μ•„λ‹Œ DTO둜 λ³€κ²½ν•œ 뒀에 λ…ΈμΆœν•˜λŠ” 것이 μ•ˆμ „


13.4 λ„ˆλ¬΄ μ—„κ²©ν•œ 계측

  • OSIVλ₯Ό μ‚¬μš©ν•œλ‹€λ©΄, λ‹¨μˆœν•œ μ—”ν‹°ν‹° μ‘°νšŒν•  μ‹œμ— ν”„λ¦¬μ  ν…Œμ΄μ…˜ κ³„μΈ΅μ—μ„œλ„ λ ˆν¬μ§€ν† λ¦¬λ₯Ό 직접 ν˜ΈμΆœν•΄λ„ μ•„λ¬΄λŸ° λ¬Έμ œκ°€ μ—†μŒ