week 5 incheol - GANGNAM-JAVA/JAVA-STUDY GitHub Wiki

์•Œ๊ณ ๋ฆฌ์ฆ˜

๊ธฐ์ˆ  ๋ฌธ์ œ

  • JAVA (๋ฐ•ํšจ์›)

    • ํ•ด์‹œ๋งต ์ถฉ๋Œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•(ํ™•์ธํ•„์š”)

      hashcode % M ์„ ํ†ตํ•ด์„œ ๋ฒ„ํ‚ท์˜ ํฌ๊ธฐ๋ณด๋‹ค ์ž‘์€ ์ธ๋ฑ์Šค์— ์ €์žฅ์„ ํ•˜๋„๋ก ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ 1/Mํ™•๋ฅ ๋กœ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค. ํ•ด์‹œ๋งต ์ถฉ๋Œ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋Œ€ํ‘œ์ ์œผ๋กœ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

      Open Addressing์€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•˜๋ ค๋Š” ํ•ด์‹œ ๋ฒ„ํ‚ท์ด ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ธ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ํ•ด์‹œ ๋ฒ„ํ‚ท์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

      Separate Chaining์—์„œ ๊ฐ ๋ฐฐ์—ด์˜ ์ธ์ž๋Š” ์ธ๋ฑ์Šค๊ฐ€ ๊ฐ™์€ ํ•ด์‹œ ๋ฒ„ํ‚ท์„ ์—ฐ๊ฒฐํ•œ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ์˜ ์ฒซ ๋ถ€๋ถ„(head)์ด๋‹ค.

      Java HashMap์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์€ Separate Channing์ด๋‹ค. Open Addressing์€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•  ๋•Œ ์ฒ˜๋ฆฌ๊ฐ€ ํšจ์œจ์ ์ด๊ธฐ ์–ด๋ ค์šด๋ฐ, HashMap์—์„œ remove() ๋ฉ”์„œ๋“œ๋Š” ๋งค์šฐ ๋นˆ๋ฒˆํ•˜๊ฒŒ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ HashMap์— ์ €์žฅ๋œ ํ‚ค-๊ฐ’ ์Œ ๊ฐœ์ˆ˜๊ฐ€ ์ผ์ • ๊ฐœ์ˆ˜ ์ด์ƒ์œผ๋กœ ๋งŽ์•„์ง€๋ฉด, ์ผ๋ฐ˜์ ์œผ๋กœ Open Addressing์€ Separate Chaining๋ณด๋‹ค ๋Š๋ฆฌ๋‹ค. Open Addressing์˜ ๊ฒฝ์šฐ ํ•ด์‹œ ๋ฒ„ํ‚ท์„ ์ฑ„์šด ๋ฐ€๋„๊ฐ€ ๋†’์•„์งˆ์ˆ˜๋ก Worst Case ๋ฐœ์ƒ ๋นˆ๋„๊ฐ€ ๋” ๋†’์•„์ง€๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋ฐ˜๋ฉด Separate Chaining ๋ฐฉ์‹์˜ ๊ฒฝ์šฐ ํ•ด์‹œ ์ถฉ๋Œ์ด ์ž˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก '์กฐ์ •'ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด Worst Case ๋˜๋Š” Worst Case์— ๊ฐ€๊นŒ์šด ์ผ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค(์—ฌ๊ธฐ์— ๋Œ€ํ•ด์„œ๋Š” "๋ณด์กฐ ํ•ด์‹œ ํ•จ์ˆ˜"์—์„œ ์„ค๋ช…ํ•˜๊ฒ ๋‹ค).

      Java 8 HashMap์—์„œ๋Š” Entry ํด๋ž˜์Šค ๋Œ€์‹  Node ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Node ํด๋ž˜์Šค ์ž์ฒด๋Š” ์‚ฌ์‹ค์ƒ Java 7์˜ Entry ํด๋ž˜์Šค์™€ ๋‚ด์šฉ์ด ๊ฐ™์ง€๋งŒ, ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ ๋Œ€์‹  ํŠธ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์œ„ ํด๋ž˜์Šค์ธ TreeNode๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด Java 7 HashMap๊ณผ ๋‹ค๋ฅด๋‹ค.

      ๋ฐ์ดํ„ฐ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด, Separate Chaining์—์„œ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ ๋Œ€์‹  ํŠธ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

      8๊ณผ 6์œผ๋กœ 2 ์ด์ƒ์˜ ์ฐจ์ด๋ฅผ ๋‘” ๊ฒƒ์€, ๋งŒ์•ฝ ์ฐจ์ด๊ฐ€ 1์ด๋ผ๋ฉด ์–ด๋–ค ํ•œ ํ‚ค-๊ฐ’ ์Œ์ด ๋ฐ˜๋ณต๋˜์–ด ์‚ฝ์ž…/์‚ญ์ œ๋˜๋Š” ๊ฒฝ์šฐ ๋ถˆํ•„์š”ํ•˜๊ฒŒ ํŠธ๋ฆฌ์™€ ๋งํฌ๋“œ ๋ฆฌ์ŠคํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” ์ผ์ด ๋ฐ˜๋ณต๋˜์–ด ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    • thread safe๋ž€? ํ•ด๊ฒฐ/ํšŒํ”ผ ๋ฐฉ๋ฒ•?

      • java.util.concurrent ํŒจํ‚ค์ง€์—๋Š” ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ๋ฐ์ดํ„ฐ์˜ ์›์ž์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•œ API๋ฅผ ํ™•์ธ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

        • synchronized

          public synchronized void ๋ฉ”์†Œ๋“œ () { 
              ๋‚ด์šฉ... 
          } 
          
          public void ๋ฉ”์†Œ๋“œ () { 
              ๋‚ด์šฉ... 
              synchronized (this) { ๋™๊ธฐํ™”๋‚ด์šฉ... } 
          }
        • ReentrantLock

          ๊ธฐ์กด์˜ synchronized๋Š” ์ด๋ ‡๊ฒŒ ๋ฉ”์†Œ๋“œ์ „์ฒด๋‚˜ ๊ตฌ๊ฐ„์„ ๋ฌถ์–ด์„œ ๋™๊ธฐํ™”๋ฅผ ์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

          ๊ทธ๋Ÿฐ๋ฐ ReentrantLock ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์กฐ๊ธˆ์€ ๋ฒˆ๊ฑฐ๋กญ๋”๋ผ๋„ ์‹œ์ž‘์ ๊ณผ ๋์ ์„ ๋ช…๋ฐฑํžˆ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

          class SomeClass { 
              private final ReentrantLock locker = new ReentrantLock(); 
              public void SomeMethod () { 
                  locker.lock(); 
                  // ์“ฐ๋ ˆ๋“œ์— ๋ฝ์„ ๊ฒ๋‹ˆ๋‹ค.(๋™๊ธฐํ™”์˜ ์‹œ์ž‘) 
                  try { ๋™๊ธฐํ™”๋‚ด์šฉ๋“ค... } 
                  catch (์–ด๋–ค์˜ˆ์™ธ๋“ค) { ํ•ด๋‹น์˜ˆ์™ธ์ฒ˜๋ฆฌ... } 
                  finally { 
                      locker.unlock(); // ์“ฐ๋ ˆ๋“œ์˜ ๋ฝ์„ ํ’‰๋‹ˆ๋‹ค.(๋™๊ธฐํ™” ๋์ง€์ ) 
                  } 
              } 
          }
        • AtomicInteger

          public class AtomicInteger extends Number implements java.io.Serializable { 
              private volatile int value; public final int incrementAndGet() { 
                  int current; 
                  int next; 
                  do { 
                      current = get(); next = current + 1; 
                  } 
                  while (!compareAndSet(current, next)); 
                  
                  return next; 
              } 
                  
              public final boolean compareAndSet(int expect, int update) { 
                  return unsafe.compareAndSwapInt(this, valueOffset, expect, update); 
              } 
          }

          ๋‹ค๋ฅธ AtomicInteger ๋ฉ”์†Œ๋“œ ๋“ค๋„ ๊ฑฐ์˜ ์œ ์‚ฌํ•œ ํŒจํ„ด์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค. ๋˜ํ•œ ๋ˆˆ์—ฌ๊ฒจ ๋ณผ ์ ์€ volatile int value; ์„ ์–ธ๋ถ€ ์ธ๋ฐ voliatile๋Š” ๋ณ€์ˆ˜์˜ ๊ฐ€์‹œ์„ฑ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋œ๋‹ค. volatile ํ‚ค์›Œ๋“œ๊ฐ€ ๋ถ™์–ด ์žˆ๋Š” ๊ฐ์ฒด๋Š” CPU์บ์‹œ๊ฐ€ ์•„๋‹Œ ๋ฉ”์ธ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ๊ฐ’์„ ์ฐธ์กฐํ•ด์˜จ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๊ตณ์ด CAS์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋ฌธ์ œ๊ฐ€ ์—†๋Š” ๊ฒƒ ์•„๋‹๊นŒ? ๊ทธ๋ ‡์ง€ ์•Š๋‹ค. volatile ํ‚ค์›Œ๋“œ๋Š” ์˜ค์ง ํ•œ๊ฐœ์˜ ์“ฐ๋ ˆ๋“œ์—์„œ ์“ฐ๊ธฐ์ž‘์—…์„ ํ•  ๋•Œ, ๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๋Š” ์ฝ๊ธฐ ์ž‘์—…๋งŒ ํ•  ๋•Œ ์•ˆ์ •์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ AtomicIntger๋Š” ์—ฌ๋Ÿฌ ์“ฐ๋ ˆ๋“œ์—์„œ ์ฝ๊ธฐ/์“ฐ๊ธฐ ์ž‘์—…์„ ๋ณ‘ํ–‰ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ CAS์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ผ๋Š” 2์ค‘์˜ ์•ˆ์ •์žฅ์น˜๋ฅผ ์„ค์น˜ํ•ด ๋†“์€ ๊ฒƒ์ด๋‹ค.

      • ํšŒํ”ผ

        • ๋ฐ์ดํ„ฐ ๋ถˆ๋ณ€์„ฑ ํ™•๋ณด : ๋ชจ๋“  ํ•„๋“œ๋ฅผ final๋กœ ์„ ์–ธ
        • ๋ฐ์ดํ„ฐ ์‚ฌ๋ณธ์„ ํ™œ์šฉ : Collections.unmodifiableList(list);
        • Compare and Swap(CAS) ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ : Synchronized์™€ ๊ฐ™์€ ๋ช…์‹œ์  Lock์„ ์‚ฌ์šฉํ•˜๊ธฐ ๋ณด๋‹ค CAS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์„ฑ๋Šฅํ–ฅ์ƒ์— ๋„์›€์„ ์ค€๋‹ค. Low Level์˜ Atomic ์ „๋žต์— ํ•ด๋‹นํ•œ๋‹ค. java.util.concurrent.atomic ํŒจํ‚ค์ง€์—๋Š” CAS๋ฅผ ์ ์šฉํ•œ ๋ฉ”์†Œ๋“œ๊ฐ€ ๋งŽ์ด ์žˆ๋‹ค.
  • SPRING (์œ ์ •ํ˜„)

    • n+1 ์ฟผ๋ฆฌ ๋ฌธ์ œ๋ž€?

      • Join ๊ด€๊ณ„์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ด์Šˆ๋กœ join๋œ ๋ชจ๋ธ์„ ์ฝ์„ ๋•Œ ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๋Š”๊ฒŒ ์•„๋‹Œ ์ฟผ๋ฆฌ์—์„œ ๋งŒ๋“ค์–ด์ง„ ๋ฐ์ดํ„ฐ์˜ ๊ฐฏ์ˆ˜(n)๋งŒํผ select ์ฟผ๋ฆฌ๋ฅผ ์ถ”๊ฐ€๋กœ ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด์˜ค๊ฒŒ ๋œ๋‹ค.
      • fetch.eager ์—์„œ fetch.lazy ์„ ๋ณ€๊ฒฝํ•œ๋‹ค๊ณ  ํ•ด์„œ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์‹œ์ ์ด ๋ณ€๊ฒฝ๋  ๋ฟ์ด์ง€ ์‹คํ–‰๋˜๋Š” ์ฟผ๋ฆฌ์˜ ๊ฐฏ์ˆ˜๋Š” ๋ณ€ํ•จ์ด ์—†๋‹ค.
      • ์›์ธ : jpaRepository์— ์ •์˜ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด JPA๋Š” ๋ฉ”์„œ๋“œ ์ด๋ฆ„์„ ๋ถ„์„ํ•ด์„œ JPQL์„ ์ƒ์„ฑํ•˜์—ฌ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค. JPQL์€ SQL์„ ์ถ”์ƒํ™”ํ•œ ๊ฐ์ฒด์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด๋กœ์„œ ํŠน์ • SQL์— ์ข…์†๋˜์ง€ ์•Š๊ณ  ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด์™€ ํ•„๋“œ ์ด๋ฆ„์„ ๊ฐ€์ง€๊ณ  ์ฟผ๋ฆฌ๋ฅผ ํ•œ๋‹ค.
      • ํ•ด๊ฒฐ๋ฐฉ์•ˆ
        • fetch join - inner join : ์ง์ ‘ ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ์— ์‚ฌ์šฉํ•  JPQL์„ ๋ช…์‹œํ•ด์ฃผ๋ฉด์„œ fetch ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค€๋‹ค. (ํŽ˜์ด์ง• api๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค)

        • FetchMode.SUBSELECT

          ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค

          @Entity
          class Member{
              @Id @GeneratedValue
              private Long id;
          
              @org.hibernate.annotations.Fetch(FetchMode.SUBSELECT)
              @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
              private List<Order> orders = new ArrayList<>();
          }

          ์•„๋ž˜์™€ ๊ฐ™์ด ์‹คํ–‰๋œ๋‹ค.

          SELECT * FROM Member;
          SELECT * FROM Order_
              WHERE MEMBER_ID IN(
                  SELECT ID
                  FROM Member
              )

          ์ฆ‰์‹œ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์กฐํšŒ์‹œ์ ์—, ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์ง€์—ฐ๋กœ๋”ฉ๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ์— ์œ„์˜ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋œ๋‹ค.

          ๋ชจ๋‘ ์ง€์—ฐ๋กœ๋”ฉ์œผ๋กœ ์„ค์ •ํ•˜๊ณ  ์„ฑ๋Šฅ ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ณณ์—๋Š” JPQL ํŽ˜์น˜ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ถ”์ฒœ๋˜๋Š” ์ „๋žต์ด๋‹ค.

        • EntityGraph - left outer join : @EntityGraph ์˜ attributePaths์— ์ฟผ๋ฆฌ ์ˆ˜ํ–‰์‹œ ๋ฐ”๋กœ ๊ฐ€์ ธ์˜ฌ ํ•„๋“œ๋ช…์„ ์ง€์ •ํ•˜๋ฉด Lazy๊ฐ€ ์•„๋‹Œ Eager ์กฐํšŒ๋กœ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค.

          • ๊ณตํ†ต์ ์œผ๋กœ ์นดํ…Œ์‹œ์•ˆ ๊ณฑ(Cartesian Product)์ด ๋ฐœ์ƒํ•˜์—ฌ Subject์˜ ์ˆ˜๋งŒํผ Academy๊ฐ€ ์ค‘๋ณต ๋ฐœ์ƒํ•˜๊ฒŒ
          • Set์€ ์ค‘๋ณต์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ค‘๋ณต๋“ฑ๋ก์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
          • 2๋ฒˆ์งธ ๋ฐฉ๋ฒ•์€ distinct๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค
        • BatchSize

          ํ•˜์ด๋ฒ„๋„ค์ดํŠธ๊ฐ€ ์ œ๊ณตํ•˜๋Š” org.hibernate.annotations.BatchSize ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•˜๋ฉด ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ์ง€์ •๋œ size ๋งŒํผ SQL์˜ IN์ ˆ์„ ์‚ฌ์šฉํ•ด์„œ ์กฐํšŒํ•œ๋‹ค.

          @Entity
          class Member{
              @Id @GeneratedValue
              private Long id;
          
              @org.hibernate.annotations.BatchSize(size = 5)
              @OneToMany(mappedBy = "member", fetch = FetchType.EAGER)
              private List<Order> orders = new ArrayList<>();
          }

          ์ฆ‰์‹œ๋กœ๋”ฉ์ด๋ฏ€๋กœ Member๋ฅผ ์กฐํšŒํ•˜๋Š” ์‹œ์ ์— Order๋ฅผ ๊ฐ™์ด ์กฐํšŒํ•œ๋‹ค.@BatchSize๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ Member์˜ ๊ฑด์ˆ˜๋งŒํผ ์ถ”๊ฐ€ SQL์„ ๋‚ ๋ฆฌ์ง€ ์•Š๊ณ , ์กฐํšŒํ•œ Member ์˜ id๋“ค์„ ๋ชจ์•„์„œ SQL IN ์ ˆ์„ ๋‚ ๋ฆฐ๋‹ค.

          SELECT * FROM
          ORDER_ WHERE MEMBER_ID IN(
              ?, ?, ?, ?, ?
          )

          size๋Š” IN์ ˆ์— ์˜ฌ์ˆ˜์žˆ๋Š” ์ตœ๋Œ€ ์ธ์ž ๊ฐœ์ˆ˜๋ฅผ ๋งํ•œ๋‹ค. ๋งŒ์•ฝ Member์˜ ๊ฐœ์ˆ˜๊ฐ€ 10๊ฐœ๋ผ๋ฉด ์œ„์˜ IN์ ˆ์ด 2๋ฒˆ ์‹คํ–‰๋ ๊ฒƒ์ด๋‹ค.

          ๊ทธ๋ฆฌ๊ณ  ๋งŒ์•ฝ ์ง€์—ฐ๋กœ๋”ฉ์ด๋ผ๋ฉด ์ง€์—ฐ๋กœ๋”ฉ๋œ ์—”ํ‹ฐํ‹ฐ ์ตœ์ดˆ ์‚ฌ์šฉ์‹œ์ ์— 5๊ฑด์„ ๋ฏธ๋ฆฌ ๋กœ๋”ฉํ•ด๋‘๊ณ , 6๋ฒˆ์งธ ์—”ํ‹ฐํ‹ฐ ์‚ฌ์šฉ ์‹œ์ ์— ๋‹ค์Œ SQL์„ ์ถ”๊ฐ€๋กœ ์‹คํ–‰ํ•œ๋‹ค.

          hibernate.default_batch_fetch_size ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์— ๊ธฐ๋ณธ์œผ๋กœ @BatchSize๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

          <property name="hibernate.default_batch_fetch_size" value="5" />
    • @ControllerAdvice, @ExceptionHandler์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜์‹œ์˜ค

      @ControllerAdvice

      ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋ณด์กฐํ•˜๋Š” ํด๋ž˜์Šค์— ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜.

      ์ปจํŠธ๋กค๋Ÿฌ์—์„œ ์“ฐ์ด๋Š” ๊ณตํ†ต๊ธฐ๋Šฅ๋“ค์„ ๋ชจ๋“ˆํ™”ํ•˜์—ฌ ์ „์—ญ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

      @ExceptionHandler

      ์ปจํŠธ๋กค๋Ÿฌ ๋ฉ”์†Œ๋“œ์— ์‚ฌ์šฉํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜.

      ์–ด๋…ธํ…Œ์ด์…˜ ์ธ์ž๋กœ ์ „๋‹ฌ๋œ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•œ๋‹ค.

      ์ „๋‹ฌ๋œ ์˜ˆ์™ธํด๋ž˜์Šค์™€ ํ™•์žฅ๋œ ํด๋ž˜์Šค๊นŒ์ง€ ์ฒ˜๋ฆฌํ•œ๋‹ค.

      @ExceptionHandler ์—๋Ÿฌ ์ฒ˜๋ฆฌ ๋งŒ๋“ค๊ธฐ

      Spring Web MVC - Annotated Controllers - Exceptions

      ๊ธฐ๋ณธ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

      ์•„๋ž˜์™€ ๊ฐ™์ด ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

      @Controller
      public class SimpleController {
      
          // ...@ExceptionHandler
          public ResponseEntity<String> handle(IOException ex) {
              // ...
          }
      }
      

      ์œ„์™€ ๊ฐ™์ด ์ž‘์„ฑ๋˜๋ฉด ํ•ด๋‹น Controller์˜ ๋ฉ”์†Œ๋“œ์—์„œ ๋ฐœ์ƒํ•œ IOException์€ ์œ„์— @ExceptionHandler๋กœ ์„ ์–ธ๋œ handle ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ์—๋Ÿฌ๊ฐ€ ์ฒ˜๋ฆฌ๋œ๋‹ค.

      @ExceptionHandler({FileSystemException.class, RemoteException.class})
      public ResponseEntity<String> handle(IOException ex) {
          // ...
      }
      

      ์œ„์™€ ๊ฐ™์ด @ExceptionHandler์— ๋Œ€์ƒ Exception ๋ชฉ๋ก์„ ์ •์˜ํ•˜์—ฌ ์ฒ˜๋ฆฌ ๋Œ€์ƒ์ธ Exception ์œ ํ˜•์„ ์ข€๋” ์ขํž ์ˆ˜ ์žˆ๋‹ค.

      IOException ์ค‘ FileSystemException๊ณผ RemoteException ์— ๋Œ€ํ•ด์„œ๋งŒ ํ•ด๋‹น handle ๋ฉ”์„œ๋“œ๊ฐ€ ๋™์ž‘ํ•œ๋‹ค.

      @ExceptionHandler({FileSystemException.class, RemoteException.class})
      public ResponseEntity<String> handle(Exception ex) {
          // ...
      }
      

      ์œ„์™€ ๊ฐ™์ด ๋Œ€์ƒ Exception์„ @ExceptionHandler๋กœ ์ •์˜ํ•˜๊ณ  ์ผ๋ฐ˜์ ์ธ ์—๋Ÿฌ ์œ ํ˜•์ธ Exception์ด๋‚˜ ๋˜๋Š” ์ƒ์œ„์ธ Throwable์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

      @ControllerAdvice์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๊ธฐ

      @Controller์— ์ •์˜๋œ @ExceptionHandler๋Š” ํ•ด๋‹น controller์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.

      ๋ชจ๋“  Controller์— ๋Œ€ํ•ด ๋ฐœ์ƒํ•œ ์ „์—ญ ์—๋Ÿฌ์— ๋Œ€ํ•ด ์ฒ˜๋ฆฌํ•˜๋Š” @ExceptionHandler๋Š” @ControllerAdvice์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

      @Controller
      @ControllerAdvice
      public class GlobalExceptionController {
      
          // ...@ExceptionHandler
          public ResponseEntity<String> handle(IOException ex) {
              // ...
          }
      }
      

      ์œ„์™€ ๊ฐ™์ด @ControllerAdvice๋กœ ์„ ์–ธํ•œ controller๋‚ด์— ์ •์˜๋œ @ExceptionHandler๋Š” ๋ชจ๋“  controller๋ฅผ ๋Œ€์ƒ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค.

      controller ๋Œ€์ƒ์„ ์ขํ˜€์„œ ์ง€์ •ํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ ์•„๋ž˜์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

      // @RestController๋ฅผ ์‚ฌ์šฉํ•œ ๋ชจ๋“  controller ๋Œ€์ƒ@ControllerAdvice(annotations = RestController.class)
      public class ExampleAdvice1 {}
      
      // ํ•ด๋‹น ํŒจํ‚ค์ง€ ๋‚ด ๋ชจ๋“  controller ๋Œ€์ƒ@ControllerAdvice("org.example.controllers")
      public class ExampleAdvice2 {}
      
      // ํ•ด๋‹น ํด๋ž˜์Šค ํ•˜์œ„๋กœ ๊ตฌํ˜„๋œ controller ๋Œ€์ƒ@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
      public class ExampleAdvice3 {}
      
  • Infra/์šด์˜ (๊น€์ง€ํ›ˆ)

โš ๏ธ **GitHub.com Fallback** โš ๏ธ