<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ZINU</title>
    <link>https://pixx.tistory.com/</link>
    <description>좋은 성과를 얻으려면 한 걸음 한 걸음이 힘차고 충실하지 않으면 안 된다. -단테</description>
    <language>ko</language>
    <pubDate>Thu, 9 Apr 2026 00:36:46 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>지누박</managingEditor>
    <image>
      <title>ZINU</title>
      <url>https://tistory1.daumcdn.net/tistory/5271238/attach/84e7c104d68b4a158a426356523a2e6d</url>
      <link>https://pixx.tistory.com</link>
    </image>
    <item>
      <title>[Claude Code] Claude Code의 Commands vs Skills, 뭐가 다른가❓</title>
      <link>https://pixx.tistory.com/776</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/R2ex7/dJMcab4IVSN/kSuh1TLzw87s0km9UMThyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/R2ex7/dJMcab4IVSN/kSuh1TLzw87s0km9UMThyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/R2ex7/dJMcab4IVSN/kSuh1TLzw87s0km9UMThyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FR2ex7%2FdJMcab4IVSN%2FkSuh1TLzw87s0km9UMThyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;194&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude Code를 쓰다 보면 세 가지 설정 파일을 마주치게 됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CLAUDE.md&lt;/b&gt;&amp;nbsp;➡️ 매 세션마다 &lt;b&gt;자동으로 로드&lt;/b&gt;되는 &lt;u&gt;&lt;b&gt;프로젝트 규칙&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;.claude/commands/&lt;/b&gt; ➡️ 내가 &lt;u&gt;&lt;b&gt;직접 /명령어로 호출&lt;/b&gt;&lt;/u&gt;하는 커맨드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;.claude/skills/&lt;/b&gt; ➡️ Claude가 대화 흐름을 보고 자동으로 감지해서 쓰는 스킬&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 &lt;b&gt;Commands&lt;/b&gt;와 &lt;b&gt;Skills&lt;/b&gt;이 둘 다 슬래시 커맨드로 호출되니까 &quot;그냥 같은 거 아닌가?&quot; 싶었습니다. 실제로 원래는 별개 시스템이었는데 현재는 통합되어 둘 다 같은 /명령어 인터페이스로 작동합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 이 차이점을 직접 포트폴리오 프로젝트를 만들면서 겪은 경험을 바탕으로 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Commands&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Commands : 내가 직접 호출 하는 것&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;위치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;claude/commands/명령어이름.md&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 터미널에서 &lt;u&gt;&lt;b&gt;/명령어를 직접 입력했을 때만 실행&lt;/b&gt;&lt;/u&gt;됩니다. Claude가 &quot;이 상황이면 이 커맨드를 써야겠다&quot;고 &lt;s&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;판단&lt;/b&gt;&lt;/span&gt;&lt;/s&gt;해서 &lt;s&gt;자동으로 실행하지 않습니다.&lt;/s&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;Ex ) /push&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;## 절차
1. git status, git diff로 변경사항 분석
2. CLAUDE.md 커밋 컨벤션 참조해서 메시지 자동 생성
3. 생성된 메시지 확인 요청
4. git add -A &amp;amp;&amp;amp; git commit &amp;amp;&amp;amp; git push
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Commands를 쓰는 경우&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사이드이펙트가 있는 작업 (push, deploy, 파일 삭제)&lt;/li&gt;
&lt;li&gt;내가 타이밍을 직접 제어해야 하는 작업&lt;/li&gt;
&lt;li&gt;단순한 반복 작업 자동화&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Skills&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Skills: Claude가 자동으로 감지하는 것&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;위치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;.claude/skills/스킬이름/SKILL.md&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Skills&lt;/b&gt;는 YAML frontmatter의 description 필드를 보고 Claude가 &lt;b&gt;&quot;지금 이 스킬이 필요한 상황이다&lt;/b&gt;&quot;라고 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;판단&lt;/b&gt;&lt;/span&gt;하면 &lt;u&gt;&lt;b&gt;자동으로 로드&lt;/b&gt;&lt;/u&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 직접 호출할 수도 있지만, 핵심은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;자동 감지&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;Ex ) explain-code 스킬&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;---
name: explain-code
description: 코드 설명 요청 시 사용. &quot;어떻게 작동해?&quot;, 
             &quot;이 코드 설명해줘&quot; 같은 요청에 자동 감지.
---

코드를 설명할 때 항상:
1. 일상적인 비유로 시작
2. ASCII 다이어그램으로 흐름 표시
3. 단계별로 풀어서 설명
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 &lt;b&gt;&quot;이 코드 어떻게 작동해?&quot;&lt;/b&gt;라고 물으면 Claude가 &lt;u&gt;&lt;b&gt;explain-code 스킬을 자동으로 로드&lt;/b&gt;&lt;/u&gt;해서 그 방식대로 답변합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Skills를 쓰는 경우&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Claude가 알아서 판단해서 써줬으면 하는 작업&lt;/li&gt;
&lt;li&gt;지원 파일(스크립트, 템플릿)이 필요한 복잡한 작업&lt;/li&gt;
&lt;li&gt;여러 프로젝트에서 공통으로 쓰는 방법론&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;Skills YAML frontmatter 구조 &lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1774884759709&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
name: review-code          # 스킬 식별자 (필수)
description: |             # 자동 감지 트리거 (필수, 핵심)
  코드 리뷰 요청 시 사용.
  &quot;리뷰해줘&quot;, &quot;코드 봐줘&quot;, &quot;문제 있어?&quot; 같은
  요청에 자동 감지.
version: 1.0               # 버전 관리 (선택)
author: jinwoo             # 작성자 (선택)
tags: [review, quality]    # 분류용 태그 (선택)
---&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;b&gt;description이 핵심&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Claude는 이 필드를 보고 &quot;지금 이 스킬을 써야 하는 상황인가&quot;를 판단합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 가지 &lt;span style=&quot;color: #ee2323;&quot;&gt;주의할 점&lt;/span&gt;이 있습니다. &lt;b&gt;공식 문서에서도 Claude가 스킬을 undertrigger하는 경향이 있다고 인정합니다.&lt;/b&gt; 필요한 상황인데 스킬을 안 쓰는 경우입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 description은 소극적으로 쓰면 안 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1774885673929&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 소극적 (undertrigger 위험)
description: 코드 리뷰 스킬

# 적극적 (권장)
description: |
  코드 리뷰 요청 시 사용.
  &quot;리뷰해줘&quot;, &quot;코드 봐줘&quot;, &quot;문제 있어?&quot;, &quot;확인해줘&quot; 같은
  요청뿐 아니라 코드를 보여주면서 의견을 묻는 상황에서도 반드시 사용할 것.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Commands vs Skills 핵심 차이점&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 110px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 13.0233%; height: 22px;&quot;&gt;&lt;b&gt;위치&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.4884%; height: 22px;&quot;&gt;&lt;b&gt;.claude/commands/&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.3721%; height: 22px;&quot;&gt;&lt;b&gt;.claude/skills/&amp;lt;name&amp;gt;/&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 13.0233%; height: 22px;&quot;&gt;&lt;b&gt;파일명&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.4884%; height: 22px;&quot;&gt;&lt;b&gt;명령어.md&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.3721%; height: 22px;&quot;&gt;&lt;b&gt;SKILL.md (고정)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 13.0233%; height: 22px;&quot;&gt;&lt;b&gt;호출&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.4884%; height: 22px;&quot;&gt;&lt;b&gt;내가 직접 /명령어&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.3721%; height: 22px;&quot;&gt;&lt;b&gt;자동 감지 + 직접 호출&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 13.0233%; height: 22px;&quot;&gt;&lt;b&gt;지원 파일&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.4884%; height: 22px;&quot;&gt;&lt;b&gt;없음&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 43.3721%; height: 22px;&quot;&gt;&lt;b&gt;스크립트, 템플릿 등 가능&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;실제로 어떻게 구분해서 써야할까❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음엔 코드 리뷰도 Commands로 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 쓰다 보니 문제가 생겼습니다. /review를 타이핑해야 한다는 걸 매번 잊어버리니, &quot;이 코드 좀 봐줘&quot;라고 자연어로 물어보게 되고 &lt;b&gt;일반 답변&lt;/b&gt;이 나올 뿐 &lt;s&gt;내가 정해둔 리뷰 방식대로 동작&lt;/s&gt;하지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;b&gt;/push&lt;/b&gt;는 Commands가 딱 맞았습니다. Claude가 &quot;변경사항이 많아 보이니 자동으로 푸시할게요&quot;라고 하면 곤란하니까요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그때 판단 기준이 명확해졌습니다. &lt;b&gt;내가 타이밍을 제어해야 하면 Commands, Claude가 알아서 판단해줬으면 하면 Skills.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/push, /done 같은 사이드이펙트가 있는 작업은 내가 원할 때만 실행되어야 합니다. ➡️ &lt;b&gt;Commands&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&quot;리뷰해줘&quot;, &quot;이 코드 설명해줘&quot; 같은 요청은 슬래시 커맨드를 타이핑하지 않아도 Claude가 알아서 그 방식대로 답해줬으면 하는 작업입니다. ➡️ &lt;b&gt;Skills&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식 문서에서도&lt;b&gt; /commit, /deploy&lt;/b&gt; 같은 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;사이드이펙트&lt;/b&gt;&lt;/span&gt; 있는 작업은 &lt;b&gt;disable-model-invocation: true 설정&lt;/b&gt;으로 &lt;b&gt;&lt;u&gt;사용자만 호출 가능하게 하라고 권장&lt;/u&gt;&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;disable-model-invocation 예시 &lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1774884700475&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
name: push
description: 변경사항을 git push한다
disable-model-invocation: true  # 사용자만 호출 가능
---

## 절차
1. git status, git diff로 변경사항 분석
...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;disable-model-invocation: true&lt;/b&gt;를 설정하면 Claude가 &quot;지금 push하면 좋을 것 같은데요&quot;라며 자동으로 실행하는 걸 막습니다. 사이드이펙트 있는 커맨드엔 필수로 걸어두는 게 좋습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1496&quot; data-origin-height=&quot;768&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzV4S0/dJMcabp6K4L/L99JzhdZbKArDdqjAQCAk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzV4S0/dJMcabp6K4L/L99JzhdZbKArDdqjAQCAk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzV4S0/dJMcabp6K4L/L99JzhdZbKArDdqjAQCAk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzV4S0%2FdJMcabp6K4L%2FL99JzhdZbKArDdqjAQCAk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;618&quot; height=&quot;317&quot; data-origin-width=&quot;1496&quot; data-origin-height=&quot;768&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;처음에는 둘 다 슬래시 커맨드로 보여서 같은 거라고 생각했지만, 핵심 차이는 &lt;u&gt;&lt;b&gt;누가 호출하느냐&lt;/b&gt;&lt;/u&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내가 직접 호출 ➡️&amp;nbsp;&lt;b&gt;Commands&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Claude가 자동 감지 + 직접 호출 모두 ➡️&amp;nbsp;&lt;b&gt;Skills&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;규모가 작은 프로젝트 정도의 규모라면 Commands만으로도 충분합니다. Skills는 Claude가 자동으로 판단해서 실행해줬으면 하는 복잡한 워크플로우가 생겼을 때 도입하면 된다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AI</category>
      <category>claude code</category>
      <category>commands</category>
      <category>Skills</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/776</guid>
      <comments>https://pixx.tistory.com/776#entry776comment</comments>
      <pubDate>Tue, 31 Mar 2026 00:48:11 +0900</pubDate>
    </item>
    <item>
      <title>[AI] llmfit - 내 하드웨어에 맞는 LLM을 찾아주는 도구</title>
      <link>https://pixx.tistory.com/775</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;llm.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsbYfy/dJMcagLyaHC/ZIvXHZTsDypuWQk6U6y011/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsbYfy/dJMcagLyaHC/ZIvXHZTsDypuWQk6U6y011/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsbYfy/dJMcagLyaHC/ZIvXHZTsDypuWQk6U6y011/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsbYfy%2FdJMcagLyaHC%2FZIvXHZTsDypuWQk6U6y011%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;llm.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;로컬 LLM, 어떤 모델을 골라야 할까❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: oklch(0.373 0.034 259.733); text-align: start;&quot;&gt;로컬 LLM 시대가 본격화되면서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 가장 먼저 부딪히는 질문이 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;i&gt;&lt;b&gt; &quot;내 장비에서 어떤 모델이 실제로 돌아갈까?&quot; &lt;/b&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;막상 모델을 고르려 하면 선택지가 너무 많습니다. &lt;b&gt;어떤 모델이 내 환경에서 실제로 잘 돌아가는지&lt;/b&gt;는 직접 받아보기 전까지 알기가 어렵습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스펙 표를 봐도 감이 잘 안 오고, 받아보면 생각보다 느리거나 &lt;b&gt;메모리가 부족&lt;/b&gt;해서 &lt;s&gt;실행&lt;/s&gt;이 안 되기도 합니다. 여기서 이 문제를 해결해주는 기능이 최근에 등장했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 &quot;llmfit&quot;입니다. 본 글에서는 이 llmfit에 대한 기능을 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;llmfit이란❓&lt;/h3&gt;
&lt;figure id=&quot;og_1773569781890&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - AlexsJones/llmfit: Hundreds of models &amp;amp; providers. One command to find what runs on your hardware.&quot; data-og-description=&quot;Hundreds of models &amp;amp; providers. One command to find what runs on your hardware. - AlexsJones/llmfit&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/AlexsJones/llmfit&quot; data-og-url=&quot;https://github.com/AlexsJones/llmfit&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/p6Z0Y/dJMb8XR4kLY/gAIGd4WgtXytCVlUk4dkZ1/img.png?width=1200&amp;amp;height=600&amp;amp;face=988_118_1031_164,https://scrap.kakaocdn.net/dn/ItCZw/dJMb8867wgL/lpKyKV04BijJXXSJ4ExqcK/img.png?width=1200&amp;amp;height=600&amp;amp;face=988_118_1031_164&quot;&gt;&lt;a href=&quot;https://github.com/AlexsJones/llmfit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/AlexsJones/llmfit&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/p6Z0Y/dJMb8XR4kLY/gAIGd4WgtXytCVlUk4dkZ1/img.png?width=1200&amp;amp;height=600&amp;amp;face=988_118_1031_164,https://scrap.kakaocdn.net/dn/ItCZw/dJMb8867wgL/lpKyKV04BijJXXSJ4ExqcK/img.png?width=1200&amp;amp;height=600&amp;amp;face=988_118_1031_164');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - AlexsJones/llmfit: Hundreds of models &amp;amp; providers. One command to find what runs on your hardware.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Hundreds of models &amp;amp; providers. One command to find what runs on your hardware. - AlexsJones/llmfit&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;llmfit&lt;/b&gt;은 &lt;u&gt;내 하드웨어 스펙을 자동으로 감지&lt;/u&gt;하고, 수백 개의 LLM 모델 중 &lt;b&gt;&lt;u&gt;실제로 돌아가는 것들을 점수순&lt;/u&gt;으로 보여주는&lt;/b&gt; 터미널 도구입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;설치 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;macOS&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1773569963511&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install llmfit&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Linux나 Rust 환경&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1773569982335&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cargo install llmfit&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;llmfit 사용해보기&lt;/h3&gt;
&lt;pre id=&quot;code_1773570073272&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;llmfit&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단하게 llmfit을 터미널창에 입력하면 다음과 같은 화면이 나오게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;1280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EyQyd/dJMcafZ8vXX/9kDvFmkKIfBA8nrMIIrwv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EyQyd/dJMcafZ8vXX/9kDvFmkKIfBA8nrMIIrwv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EyQyd/dJMcafZ8vXX/9kDvFmkKIfBA8nrMIIrwv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEyQyd%2FdJMcafZ8vXX%2F9kDvFmkKIfBA8nrMIIrwv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;468&quot; data-origin-width=&quot;1694&quot; data-origin-height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상단에는 내 시스템 스펙이 자동으로 잡히고, 아래에는 모델 목록이 &lt;b&gt;점수(Score) 순&lt;/b&gt;으로 정렬됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 컬럼의 의미는 다음과 같습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 36.7432%; height: 227px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.2552%;&quot;&gt;&lt;b&gt;컬럼&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.8914%;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.2552%;&quot;&gt;&lt;b&gt; Score &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.8914%;&quot;&gt;&lt;b&gt; 내 하드웨어 기준 종합 점수 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.2552%;&quot;&gt;&lt;b&gt; tok/s &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.8914%;&quot;&gt;&lt;b&gt; 예상 초당 토큰 수 (속도) &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.2552%;&quot;&gt;&lt;b&gt; Quant &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.8914%;&quot;&gt;&lt;b&gt; 추천 양자화 방식 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.2552%;&quot;&gt;&lt;b&gt; Mem % &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.8914%;&quot;&gt;&lt;b&gt; 메모리 점유율 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 19.2552%;&quot;&gt;&lt;b&gt; Fit &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 49.8914%;&quot;&gt;&lt;b&gt; Perfect / Good / Margin &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Fit 등급&lt;/b&gt;이 핵심입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;  &lt;b&gt;Perfect&lt;/b&gt; &amp;mdash; 여유 있게 실행 가능&lt;/li&gt;
&lt;li&gt;  &lt;b&gt;Good&lt;/b&gt; &amp;mdash; 실행은 되지만 메모리 빡빡함&lt;/li&gt;
&lt;li&gt;  &lt;b&gt;Margin&lt;/b&gt; &amp;mdash; 메모리 거의 꽉 참, 다른 앱과 함께 쓰기 어려움&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;내 시스템 스펙 확인&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1773570259477&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;llmfit system&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;284&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcbZeI/dJMcagLx9zx/tiVG3rlCqDdv8IQSpk1Gz1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcbZeI/dJMcagLx9zx/tiVG3rlCqDdv8IQSpk1Gz1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcbZeI/dJMcagLx9zx/tiVG3rlCqDdv8IQSpk1Gz1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcbZeI%2FdJMcagLx9zx%2FtiVG3rlCqDdv8IQSpk1Gz1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;690&quot; height=&quot;248&quot; data-origin-width=&quot;790&quot; data-origin-height=&quot;284&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; CPU, RAM, GPU, VRAM&lt;/b&gt;을 자동으로 감지해서 보여줍니다. 따로 &lt;u&gt;&lt;b&gt;설정할 필요 없이 실행&lt;/b&gt;&lt;/u&gt;만 하면 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;원하는 모델 검색&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1773570538130&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;llmfit system&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1692&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLH2RU/dJMcagdH3Gm/5dnDIJzWutohNqrlEkYSx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLH2RU/dJMcagdH3Gm/5dnDIJzWutohNqrlEkYSx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLH2RU/dJMcagdH3Gm/5dnDIJzWutohNqrlEkYSx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLH2RU%2FdJMcagdH3Gm%2F5dnDIJzWutohNqrlEkYSx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;653&quot; height=&quot;167&quot; data-origin-width=&quot;1692&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모델명, 프로바이더, 파라미터 크기로 검색할 수 있어서 &quot;openai&quot; 처럼 입력하면 &lt;b&gt;관련 모델만 필터링&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;fit 상위 결과 보&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;1222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcGROY/dJMcajanszG/U9Gn1aV1F3QSKU3VURiihK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcGROY/dJMcajanszG/U9Gn1aV1F3QSKU3VURiihK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcGROY/dJMcajanszG/U9Gn1aV1F3QSKU3VURiihK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcGROY%2FdJMcajanszG%2FU9Gn1aV1F3QSKU3VURiihK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;612&quot; height=&quot;437&quot; data-origin-width=&quot;1710&quot; data-origin-height=&quot;1222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fit 등급이 &lt;b&gt;Perfect&lt;/b&gt;인 모델만 골라서 상위 5개를 보여줍니다. 메모리 여유가 있는 상태에서 안정적으로 실행 가능한 모델만 추리고 싶을 때 유용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;코딩 용도로 추천 받기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1773570584831&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;llmfit recommend --use-case coding --json --limit 5&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1773570438733&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
  &quot;models&quot;: [
    {
      &quot;best_quant&quot;: &quot;Q4_K_M&quot;,
      &quot;category&quot;: &quot;Coding&quot;,
      &quot;context_length&quot;: 262144,
      &quot;estimated_tps&quot;: 43.9,
      &quot;fit_level&quot;: &quot;Perfect&quot;,
      &quot;gguf_sources&quot;: [],
      &quot;is_moe&quot;: true,
      &quot;memory_available_gb&quot;: 16.0,
      &quot;memory_required_gb&quot;: 8.0,
      &quot;name&quot;: &quot;NVFP4/Qwen3-Coder-30B-A3B-Instruct-FP4&quot;,
      &quot;notes&quot;: [
        &quot;Unified memory: GPU and CPU share the same pool&quot;,
        &quot;MoE: 8/128 experts active (all share unified memory pool)&quot;,
        &quot;Baseline estimated speed: 43.9 tok/s&quot;
      ],
      &quot;parameter_count&quot;: &quot;15.6B&quot;,
      &quot;params_b&quot;: 15.58,
      &quot;provider&quot;: &quot;nvfp4&quot;,
      &quot;release_date&quot;: &quot;2025-08-05&quot;,
      &quot;run_mode&quot;: &quot;GPU&quot;,
      &quot;runtime&quot;: &quot;MLX&quot;,
      &quot;runtime_label&quot;: &quot;MLX&quot;,
      &quot;score&quot;: 92.5,
      &quot;score_components&quot;: {
        &quot;context&quot;: 100.0,
        &quot;fit&quot;: 100.0,
        &quot;quality&quot;: 85.0,
        &quot;speed&quot;: 100.0
      },
      &quot;use_case&quot;: &quot;Code generation and completion&quot;,
      &quot;utilization_pct&quot;: 50.0
    },
    {
      &quot;best_quant&quot;: &quot;Q4_K_M&quot;,
      &quot;category&quot;: &quot;Coding&quot;,
      &quot;context_length&quot;: 163840,
      &quot;estimated_tps&quot;: 34.2,
      &quot;fit_level&quot;: &quot;Perfect&quot;,
      &quot;gguf_sources&quot;: [],
      &quot;is_moe&quot;: true,
      &quot;memory_available_gb&quot;: 16.0,
      &quot;memory_required_gb&quot;: 8.0,
      &quot;name&quot;: &quot;RedHatAI/DeepSeek-Coder-V2-Lite-Instruct-FP8&quot;,
      &quot;notes&quot;: [
        &quot;Unified memory: GPU and CPU share the same pool&quot;,
        &quot;MoE: 6/64 experts active (all share unified memory pool)&quot;,
        &quot;Baseline estimated speed: 34.2 tok/s&quot;
      ],
      &quot;parameter_count&quot;: &quot;15.7B&quot;,
      &quot;params_b&quot;: 15.71,
      &quot;provider&quot;: &quot;redhatai&quot;,
      &quot;release_date&quot;: &quot;2024-07-17&quot;,
      &quot;run_mode&quot;: &quot;GPU&quot;,
      &quot;runtime&quot;: &quot;MLX&quot;,
      &quot;runtime_label&quot;: &quot;MLX&quot;,
      &quot;score&quot;: 90.1,
      &quot;score_components&quot;: {
        &quot;context&quot;: 100.0,
        &quot;fit&quot;: 100.0,
        &quot;quality&quot;: 86.0,
        &quot;speed&quot;: 85.6
      },
      &quot;use_case&quot;: &quot;Code generation and completion&quot;,
      &quot;utilization_pct&quot;: 50.0
    },
    {
      &quot;best_quant&quot;: &quot;Q2_K&quot;,
      &quot;category&quot;: &quot;Coding&quot;,
      &quot;context_length&quot;: 131072,
      &quot;estimated_tps&quot;: 62.3,
      &quot;fit_level&quot;: &quot;Perfect&quot;,
      &quot;gguf_sources&quot;: [
        {
          &quot;provider&quot;: &quot;bartowski&quot;,
          &quot;repo&quot;: &quot;bartowski/DeepSeek-Coder-V2-Lite-Instruct-GGUF&quot;
        }
      ],
      &quot;is_moe&quot;: true,
      &quot;memory_available_gb&quot;: 16.0,
      &quot;memory_required_gb&quot;: 8.0,
      &quot;name&quot;: &quot;deepseek-ai/DeepSeek-Coder-V2-Lite-Instruct&quot;,
      &quot;notes&quot;: [
        &quot;Unified memory: GPU and CPU share the same pool&quot;,
        &quot;MoE: 6/64 experts active (all share unified memory pool)&quot;,
        &quot;Best quantization for hardware: Q2_K (model default: Q4_K_M)&quot;,
        &quot;Baseline estimated speed: 62.3 tok/s&quot;
      ],
      &quot;parameter_count&quot;: &quot;16B&quot;,
      &quot;params_b&quot;: 15.7,
      &quot;provider&quot;: &quot;DeepSeek&quot;,
      &quot;release_date&quot;: null,
      &quot;run_mode&quot;: &quot;GPU&quot;,
      &quot;runtime&quot;: &quot;MLX&quot;,
      &quot;runtime_label&quot;: &quot;MLX&quot;,
      &quot;score&quot;: 89.5,
      &quot;score_components&quot;: {
        &quot;context&quot;: 100.0,
        &quot;fit&quot;: 100.0,
        &quot;quality&quot;: 79.0,
        &quot;speed&quot;: 100.0
      },
      &quot;use_case&quot;: &quot;Code generation and completion&quot;,
      &quot;utilization_pct&quot;: 50.0
    },
    {
      &quot;best_quant&quot;: &quot;Q4_K_M&quot;,
      &quot;category&quot;: &quot;Coding&quot;,
      &quot;context_length&quot;: 262144,
      &quot;estimated_tps&quot;: 22.4,
      &quot;fit_level&quot;: &quot;Marginal&quot;,
      &quot;gguf_sources&quot;: [],
      &quot;is_moe&quot;: true,
      &quot;memory_available_gb&quot;: 16.0,
      &quot;memory_required_gb&quot;: 15.6,
      &quot;name&quot;: &quot;lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-MLX-4bit&quot;,
      &quot;notes&quot;: [
        &quot;Unified memory: GPU and CPU share the same pool&quot;,
        &quot;MoE: 8/128 experts active (all share unified memory pool)&quot;,
        &quot;Baseline estimated speed: 22.4 tok/s&quot;
      ],
      &quot;parameter_count&quot;: &quot;30.5B&quot;,
      &quot;params_b&quot;: 30.53,
      &quot;provider&quot;: &quot;lmstudio-community&quot;,
      &quot;release_date&quot;: &quot;2025-07-31&quot;,
      &quot;run_mode&quot;: &quot;GPU&quot;,
      &quot;runtime&quot;: &quot;MLX&quot;,
      &quot;runtime_label&quot;: &quot;MLX&quot;,
      &quot;score&quot;: 79.7,
      &quot;score_components&quot;: {
        &quot;context&quot;: 100.0,
        &quot;fit&quot;: 50.0,
        &quot;quality&quot;: 92.0,
        &quot;speed&quot;: 56.0
      },
      &quot;use_case&quot;: &quot;Code generation and completion&quot;,
      &quot;utilization_pct&quot;: 97.5
    },
    {
      &quot;best_quant&quot;: &quot;Q4_K_M&quot;,
      &quot;category&quot;: &quot;Coding&quot;,
      &quot;context_length&quot;: 262144,
      &quot;estimated_tps&quot;: 22.4,
      &quot;fit_level&quot;: &quot;Marginal&quot;,
      &quot;gguf_sources&quot;: [],
      &quot;is_moe&quot;: true,
      &quot;memory_available_gb&quot;: 16.0,
      &quot;memory_required_gb&quot;: 15.6,
      &quot;name&quot;: &quot;lmstudio-community/Qwen3-Coder-30B-A3B-Instruct-MLX-5bit&quot;,
      &quot;notes&quot;: [
        &quot;Unified memory: GPU and CPU share the same pool&quot;,
        &quot;MoE: 8/128 experts active (all share unified memory pool)&quot;,
        &quot;Baseline estimated speed: 22.4 tok/s&quot;
      ],
      &quot;parameter_count&quot;: &quot;30.5B&quot;,
      &quot;params_b&quot;: 30.53,
      &quot;provider&quot;: &quot;lmstudio-community&quot;,
      &quot;release_date&quot;: &quot;2025-08-01&quot;,
      &quot;run_mode&quot;: &quot;GPU&quot;,
      &quot;runtime&quot;: &quot;MLX&quot;,
      &quot;runtime_label&quot;: &quot;MLX&quot;,
      &quot;score&quot;: 79.7,
      &quot;score_components&quot;: {
        &quot;context&quot;: 100.0,
        &quot;fit&quot;: 50.0,
        &quot;quality&quot;: 92.0,
        &quot;speed&quot;: 56.0
      },
      &quot;use_case&quot;: &quot;Code generation and completion&quot;,
      &quot;utilization_pct&quot;: 97.5
    }
  ],
  &quot;system&quot;: {
    &quot;available_ram_gb&quot;: 6.15,
    &quot;backend&quot;: &quot;Metal&quot;,
    &quot;cpu_cores&quot;: 8,
    &quot;cpu_name&quot;: &quot;Apple M1&quot;,
    &quot;gpu_count&quot;: 1,
    &quot;gpu_name&quot;: &quot;Apple M1&quot;,
    &quot;gpu_vram_gb&quot;: 16.0,
    &quot;gpus&quot;: [
      {
        &quot;backend&quot;: &quot;Metal&quot;,
        &quot;count&quot;: 1,
        &quot;name&quot;: &quot;Apple M1&quot;,
        &quot;unified_memory&quot;: true,
        &quot;vram_gb&quot;: 16.0
      }
    ],
    &quot;has_gpu&quot;: true,
    &quot;total_ram_gb&quot;: 16.0,
    &quot;unified_memory&quot;: true
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON으로 출력되기 때문에 스크립트나 에이전트에서 파싱해서 활용하기도 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;마무리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 LLM을 처음 써보려는 분이라면, 모델 고르기 전에 llmfit부터 실행해보시길 추천합니다.&amp;nbsp; 다운로드 전에 내 환경에 맞는 모델을 미리 파악할 수 있어서 불필요한 시행착오를 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #666666;&quot;&gt; 참고: &lt;a style=&quot;color: #666666;&quot; href=&quot;https://github.com/AlexsJones/llmfit&quot;&gt;llmfit GitHub&lt;/a&gt; &lt;/span&gt;&lt;/b&gt;&lt;/p&gt;</description>
      <category>AI</category>
      <category>llmfit</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/775</guid>
      <comments>https://pixx.tistory.com/775#entry775comment</comments>
      <pubDate>Sun, 15 Mar 2026 18:55:58 +0900</pubDate>
    </item>
    <item>
      <title>[Java] LocalDateTime vs Instant, 어떤 상황에서 써야 할까?</title>
      <link>https://pixx.tistory.com/774</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;java.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxQjs1/dJMcajam7rF/XcWqBu3VkuORnt8tVTKyF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxQjs1/dJMcajam7rF/XcWqBu3VkuORnt8tVTKyF1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxQjs1/dJMcajam7rF/XcWqBu3VkuORnt8tVTKyF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxQjs1%2FdJMcajam7rF%2FXcWqBu3VkuORnt8tVTKyF1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;java.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;프로젝트를 시작할 때 엔티티의 날짜 타입으로 뭘 선언할지 고민한 적이 있을 것입니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;주변 코드나 레퍼런스를 보면 LocalDateTime, ZonedDateTime을 쓰는 경우가 대부분입니다. &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;그런데 Instant를 알고 난 뒤 한 가지 의문이 생겼습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&quot;LocalDateTime이 정말 맞는 선택인가?&quot; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;본 글에서는 두 타입의 차이와 어떤 상황에서 무엇을 선택해야 하는지 정리합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;LocalDateTime이란❓&lt;/h3&gt;
&lt;pre id=&quot;code_1773499395844&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LocalDateTime now = LocalDateTime.now();&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;LocalDateTime&lt;/b&gt;은 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;날짜&lt;/span&gt;와 &lt;span style=&quot;color: #006dd7;&quot;&gt;시간 정보&lt;/span&gt;를 가지고 있지만 &lt;s&gt;타임존(TimeZone) 정보&lt;/s&gt;는 없는&lt;/b&gt; 타입입니다. 이름에 Local이 붙은 이유가 여기 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;i&gt;&quot;내가 있는 곳의 시간&quot;&amp;nbsp;&lt;/i&gt;을&amp;nbsp;표현하는&amp;nbsp;타입이지만,&amp;nbsp;그&amp;nbsp;&lt;s&gt;&lt;i&gt;&quot;내가 있는 곳&quot;&lt;/i&gt;&lt;/s&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;이&amp;nbsp;어디인지는&amp;nbsp;타입&amp;nbsp;자체가&amp;nbsp;알지&amp;nbsp;못합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt; LocalDateTime = &lt;span style=&quot;color: #f89009;&quot;&gt;벽시계&lt;/span&gt; (타임존 정보 없음, 서버 환경에 종속)&lt;/b&gt; &lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;LocalDateTime.now()&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1773499473450&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 서버 타임존이 Asia/Seoul 이면
LocalDateTime.now(); // &amp;rarr; 2026-03-14T15:00:00

// 서버 타임존이 UTC 이면
LocalDateTime.now(); // &amp;rarr; 2026-03-14T06:00:00&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LocalDateTime.now()&lt;/b&gt;는 내부적으로 &lt;u&gt;&lt;b&gt;JVM이 실행되는 서버의 타임존&lt;/b&gt;&lt;/u&gt;을 기준으로 시각을 만듭니다. 즉, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;서버 환경&lt;/b&gt;&lt;/span&gt;에 따라 같은 코드가 다른 값을 만들어냅니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;LocalDate &amp;amp; LocalTime&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1773499530913&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LocalDate date = LocalDate.now();                      // 날짜만: 2026-03-14
LocalTime time = LocalTime.now();                      // 시간만: 15:00:00
LocalDateTime dateTime = LocalDateTime.of(date, time); // 날짜 + 시간 조합&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Instant란❓&lt;/h3&gt;
&lt;pre id=&quot;code_1773499701539&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Instant now = Instant.now();
// 출력: 2026-03-14T06:00:00Z
// Z는 UTC를 의미합니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Instant&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;UTC(협정 세계시) 기준의 절대 시각&lt;/b&gt;&lt;/u&gt;을 나타내는 타입입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;내부적으로 1970년 1월 1일 00:00:00 UTC(Unix Epoch)로부터 경과한 시간을 나노초 단위로 저장합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1773499733718&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 서버 타임존이 Asia/Seoul 이든 UTC 이든
Instant.now(); // &amp;rarr; 2024-03-14T06:00:00Z (항상 UTC 기준&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;LocalDateTime&lt;/b&gt;과 달리 &lt;s&gt;&lt;b&gt;서버 타임존에 영향&lt;/b&gt;&lt;/s&gt;받지 않습니다. 서울 서버에서 찍든, UTC 서버에서 찍든 같은 시점이면 같은 값입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;Instant = &lt;span style=&quot;color: #f89009;&quot;&gt;절대시각&lt;/span&gt; (UTC 기준, 서버 환경에 무관)&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;ZonedDateTime이란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ZonedDateTime&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;날짜 + 시간 + 타임존(ZoneId)&lt;/b&gt;&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;을 모두 가지고 있는 타입입니다. 쉽게 말하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;LocalDateTime&lt;/b&gt;에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;타임존 정보가 추가&lt;/b&gt;된 형태입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1773503142070&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;ZonedDateTime now = ZonedDateTime.now(ZoneId.of(&quot;Asia/Seoul&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 코드의 경우 다음과 같은 출력이 나오게 됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;2026-03-14T15:00:00+09:00[Asia/Seoul]&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시간 + 오프셋(+09:00) + 타임존(Asia/Seoul) 모두 포함&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote style=&quot;color: #666666; text-align: left;&quot; data-ke-style=&quot;style2&quot;&gt;즉&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Instant&lt;/b&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ZonedDateTime&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;같은 시점을 다르게 표현하는 것&lt;/b&gt;입니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;그럼 ZonedDateTime을 저장용으로 쓰면 안될까❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;쓸 수는 있지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Instant&lt;/b&gt;보다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;복잡&lt;/b&gt;합니다.&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773503142071&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Instant       &amp;rarr; UTC 기준 단순 저장, 조회 시 원하는 타임존으로 변환
ZonedDateTime &amp;rarr; 타임존 정보까지 저장, DB 매핑 시 추가 고려사항 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;저장용&lt;/b&gt;으로는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Instant&lt;/b&gt;가 더 단순하고 명확합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ZonedDateTime&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;특정 타임존 기준으로 사용자에게 보여줄 때&lt;/b&gt;&amp;nbsp;사용하는 것이 적합합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1773503142071&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;entity.setCreatedAt(Instant.now());

// 한국 사용자에게 표시
ZonedDateTime seoul = entity.getCreatedAt()
        .atZone(ZoneId.of(&quot;Asia/Seoul&quot;));

// 미국 사용자에게 표시
ZonedDateTime la = entity.getCreatedAt()
        .atZone(ZoneId.of(&quot;America/Los_Angeles&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;잘못 선택하면 생기는 일&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; LocalDateTime&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773500700374&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Column
private LocalDateTime createdAt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;만약 서버 타임존이 바뀐다면 어떻게 될까요?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;예를 들어 기존에 국내 &lt;b&gt;온프레미스 서버&lt;/b&gt;(Asia/Seoul, UTC+9)에서 운영하다가 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Docker&lt;/b&gt; 또는 &lt;b&gt;AWS EC2&lt;/b&gt;로 이전하면서 &lt;u&gt;&lt;b&gt;서버 타임존이 UTC로 변경&lt;/b&gt;&lt;/u&gt;됐다면 다음과 같은 문제가 발생합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773500800529&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;LocalDateTime.now(); // &amp;rarr; 2026-03-14T15:00:00

// 이후: 서버 타임존 UTC로 변경
LocalDateTime.now(); // &amp;rarr; 2026-03-14T06:00:0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB에 저장된 기존 데이터는 그대로 &lt;b&gt;15:00:00&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 타임존 변경 이후 저장된 데이터는 &lt;b&gt;06:00:00&lt;/b&gt;으로 들어갑니다. &lt;b&gt;&lt;u&gt;같은 시점인데 9시간 차이&lt;/u&gt;가 생겨버립니다.&lt;/b&gt; 더 문제인 건 이게 &lt;b&gt;배포 직후 바로 못 잡는다&lt;/b&gt;는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션은 &lt;b&gt;정상 동작&lt;/b&gt;하고, &lt;s&gt;에러 로그&lt;/s&gt;도 없습니다. 데이터가 어느 정도 쌓이고 나서야 &quot;어? 시간이 이상한데?&quot; 하고 뒤늦게 발견하게 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Instant&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773500910153&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 서버 타임존이 Asia/Seoul 이든 UTC 이든
Instant.now(); // &amp;rarr; 2026-03-14T06:00:00Z (항상 UTC 기준)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;b&gt;Instant&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;UTC 기준 절대시각으로 저장&lt;/b&gt;&lt;/u&gt;하기 때문에 &lt;b&gt;서버 타임존이 바뀌어도 저장되는 값&lt;/b&gt;이 &lt;s&gt;달라지지 않습니다.&lt;/s&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;언제 뭘 써야 하는가❓&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Instant&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;created_at, updated_at&lt;/b&gt; 같은 서버 기록용 시각&lt;/li&gt;
&lt;li&gt;서버&amp;nbsp;환경이&amp;nbsp;바뀔&amp;nbsp;가능성이&amp;nbsp;있을&amp;nbsp;때&amp;nbsp;(온프레미스&amp;nbsp;&amp;rarr;&amp;nbsp;클라우드&amp;nbsp;이전&amp;nbsp;등)&lt;/li&gt;
&lt;li&gt;글로벌&amp;nbsp;서비스,&amp;nbsp;멀티&amp;nbsp;타임존&amp;nbsp;환경&lt;/li&gt;
&lt;li&gt;두&amp;nbsp;시각&amp;nbsp;사이의&amp;nbsp;간격을&amp;nbsp;계산할&amp;nbsp;때&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;LocalDateTime&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자에게 보여주는 시각 (타임존 변환 후 표시용)&lt;/li&gt;
&lt;li&gt;비즈니스적으로 날짜 자체가 의미 있을 때
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;예) 예약일, 생년월일, 공시 기준일&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 타임존이 절대 바뀌지 않는 환경&lt;/b&gt; (국내 전용, 고정 온프레미스)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Instant로 저장하고 표시할 때 변환하는 패턴&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;AWS EC2, ECS, Docker&lt;/b&gt; &lt;b&gt;컨테이너&lt;/b&gt;의 &lt;u&gt;기본 타임존은 UTC&lt;/u&gt;입니다. &lt;/span&gt;&lt;span&gt;국내 서비스라도 &lt;b&gt;클라우드 인프라&lt;/b&gt;를 사용하는 순간 아래 상황이 발생할 수 있습니다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773502993090&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;서버 타임존: UTC
사용자 타임존: Asia/Seoul (UTC+9)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 경우 &lt;b&gt;LocalDateTime&lt;/b&gt;으로 저장하면 이전에 설명한 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;9시간 문제&lt;/b&gt;&lt;/span&gt;가 그대로 발생합니다. &lt;/span&gt;&lt;span&gt;&lt;u&gt;&lt;b&gt;Instant&lt;/b&gt;로 저장&lt;/u&gt;하고, &lt;u&gt;&lt;b&gt;사용자에게 보여줄 때 타임존을 적용&lt;/b&gt;&lt;/u&gt;해서 변환하는 패턴이 필요합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1773503046404&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 저장 (UTC 기준 절대시각으로 저장)
entity.setCreatedAt(Instant.now());

// 한국 사용자에게 표시
LocalDateTime display = entity.getCreatedAt()
        .atZone(ZoneId.of(&quot;Asia/Seoul&quot;))
        .toLocalDateTime();
// &amp;rarr; 2026-03-14T15:00:00&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Language/Java</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/774</guid>
      <comments>https://pixx.tistory.com/774#entry774comment</comments>
      <pubDate>Sun, 15 Mar 2026 00:53:19 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] POI명 vs 실제 주소: Tmap 경로 검색 400 에러 해결하기</title>
      <link>https://pixx.tistory.com/772</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트러블슈팅.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch7Ivk%2FdJMcacWg33U%2Fxk5KVRLdBtqBBLi76TKlAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;262&quot; height=&quot;262&quot; data-filename=&quot;트러블슈팅.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;개인 프로젝트의 마이페이지에서 경로 검색 기능을 개발하던 중, &lt;b&gt;Tmap 지오코딩 API&lt;/b&gt; 호출 시 &lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;400 Bad Request&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&amp;nbsp;에러&lt;/b&gt;&lt;/span&gt;가 발생했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;POI 검색 결과&lt;/b&gt;를 그대로 API에 전달하면서 &lt;b&gt;특수문자 인코딩 문제&lt;/b&gt;와 &lt;b&gt;POI명/주소 혼용 문제&lt;/b&gt;가 원인이었습니다. 본 글에서는 이 문제의 원인 분석과 UX를 고려한 해결 과정을 정리하고자 합니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;문제&amp;nbsp;상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;사용자가 &lt;b&gt;출발지&lt;/b&gt;와 &lt;b&gt;도착지&lt;/b&gt;를 입력하고 경로를 검색했을 때, &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt; 티맵 지오코딩 API&lt;/b&gt; &lt;/span&gt;호출 시 백엔드 서버에서 아래와 같은 에러 로그와 함께 경로 탐색에 실패하는 현상이 발생했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWmEVp/dJMcafZN0DZ/yG4kkZwC0M6BbQbpY0Gbk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWmEVp/dJMcafZN0DZ/yG4kkZwC0M6BbQbpY0Gbk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWmEVp/dJMcafZN0DZ/yG4kkZwC0M6BbQbpY0Gbk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWmEVp%2FdJMcafZN0DZ%2FyG4kkZwC0M6BbQbpY0Gbk0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;392&quot; height=&quot;277&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1770817962686&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;org.springframework.web.reactive.function.client.WebClientResponseException$BadRequest: 
400 Bad Request from GET https://apis.openapi.sk.com/tmap/geo/fullAddrGeo&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;발생 지점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;티맵 주소 기반 &lt;b&gt;지오코딩 API&lt;/b&gt; 호출 시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;검색 키워드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지(송파구 잠실동), 목적지(&lt;u&gt;&lt;b data-index-in-node=&quot;30&quot; data-path-to-node=&quot;7,1,0&quot;&gt;강남역[2호선]&lt;/b&gt;&lt;/u&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;원인&amp;nbsp;분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 특수문자 인코딩 문제&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; 티맵 지오코딩 API&lt;/b&gt;는&lt;b&gt; URL 파라미터로 &lt;span style=&quot;color: #006dd7;&quot;&gt;주소&lt;/span&gt;&lt;/b&gt;를 전달받는데, &lt;b&gt;대괄호([, ])&lt;/b&gt; 같은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;특수문자&lt;/b&gt;&lt;/span&gt;가&lt;s&gt;&lt;b&gt; 제대로 인코딩&lt;/b&gt;&lt;/s&gt;되지 않으면 서버가 요청을 &lt;b&gt;거부&lt;/b&gt;합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, 장소명에 포함된 &lt;b&gt;[ , ]와 같은 특수문자&lt;/b&gt;가 URL 파라미터로 전달되는 과정에서 &lt;s&gt;&lt;b&gt;인코딩 처리가 규격&lt;/b&gt;&lt;/s&gt;에 맞지 않아 티맵 API 서버에서 &lt;b&gt;잘못된 요청(Bad Request)&lt;/b&gt;으로 처리된 것 이었습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. API 성격에 맞지 않는 파라미터 전달 &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;티맵의 &lt;b&gt;fullAddrGeo API&lt;/b&gt;는 정제된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;법정 주소&lt;/b&gt;나&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;도로명 주소&lt;/b&gt;를 기반으로 좌표를 변환합니다.&lt;/li&gt;
&lt;li&gt;그러나 사용자가 선택한&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;강남역[2호선]&lt;/b&gt;은 주소가 아닌&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;장소명(POI)&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터&lt;/b&gt;&lt;/u&gt;입니다. ➡️&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;인코딩 실패&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1770818869964&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;SK open API&quot; data-og-description=&quot;puzzle 장소 혼잡도 실시간 장소 혼잡도&quot; data-og-host=&quot;openapi.sk.com&quot; data-og-source-url=&quot;https://openapi.sk.com/products/detail?linkMenuSeq=25&quot; data-og-url=&quot;https://openapi.sk.com/products/detail?linkMenuSeq=25&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://openapi.sk.com/products/detail?linkMenuSeq=25&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://openapi.sk.com/products/detail?linkMenuSeq=25&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;SK open API&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;puzzle 장소 혼잡도 실시간 장소 혼잡도&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;openapi.sk.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 SK open API docs를 보면 다음과 같이 나와있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[SK Open API 공식 가이드 발췌]&lt;br /&gt;&lt;br /&gt;- 기능 설명: &quot;지번 주소 또는 새주소(도로명 주소) 전체를 텍스트로 입력해 이를 분석하여 좌표로 변환&lt;br /&gt;- &quot;Request 필수 파라미터 (fullAddr): &quot;지번 주소 또는 도로명 주소 전체를 지정&quot; (예: 서울시 중구 을지로)&lt;br /&gt;&lt;br /&gt;주의 사항: &quot;주소 입력 시 UTF-8 기반의 URL 인코딩 처리 필수&quot;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 입력값의 제한&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;가이드에 명시된 대로 해당 API는 &lt;b&gt;주소(Address)&lt;/b&gt;를 입력받도록 설계되어 있습니다. 하지만 제가 전송한 데이터는 &lt;b&gt;강남역[2호선]&lt;/b&gt;과 같은 &lt;b&gt;장소명(POI)&lt;/b&gt;이었으며, 이는 API의 명확한 &lt;s&gt;사용 목적에서 벗어난 파라미터&lt;/s&gt;였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;인코딩 규격 위반&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;가이드에서는 &lt;b data-index-in-node=&quot;18&quot; data-path-to-node=&quot;8,1,0&quot;&gt;UTF-8 기반 URL 인코딩&lt;/b&gt;을 필수 조건으로 내걸고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특수문자&lt;/b&gt;가 포함된 장소명을 별도의 &lt;s&gt;정제&lt;/s&gt;나 &lt;s&gt;인코딩&lt;/s&gt; 없이 전송할 경우, API 서버는 이를 유효하지 않은 요청(Malformed Request)으로 간주하여 400 Bad Request를 반환하게 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;결론: POI명 vs 실제 주소 &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근본적인 문제는 &lt;b&gt;&quot;강남역[2호선]&quot;이 주소가 아니라 POI(Point of Interest) 이름&lt;/b&gt;이라는 점입니다. 따라서 결국 데이터 흐름의 구조적인 문제를 해결해야 함을 확인했습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;❌ &lt;b&gt;잘못된 흐름&lt;/b&gt;: 강남역[2호선] ➡️ 지오코딩 API ➡️ 400 에러&lt;/li&gt;
&lt;li&gt;✅ &lt;b&gt;올바른 흐름&lt;/b&gt;: POI 검색 ➡️ 실제 주소 획득 ➡️ 지오코딩 API ➡️ 성공&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;해결&amp;nbsp;방법&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1 단계 : POI 검색 결과에서 전체 주소 활용&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;POI 검색 API의 응답에는 장소명과 함께 실제 주소 정보가 포함되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lG73B/dJMcac24pDN/LJg11Kg8WmhOZWDjljMPK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lG73B/dJMcac24pDN/LJg11Kg8WmhOZWDjljMPK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lG73B/dJMcac24pDN/LJg11Kg8WmhOZWDjljMPK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlG73B%2FdJMcac24pDN%2FLJg11Kg8WmhOZWDjljMPK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;431&quot; height=&quot;218&quot; data-origin-width=&quot;431&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;POI 검색 API는 &lt;b&gt;장소명(name)&lt;/b&gt;과 함께 해당 장소의 정확한 &lt;b&gt;주소 정보&lt;/b&gt;를 함께 제공합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; name&lt;/b&gt;은 &lt;b&gt;사용자가 읽기 쉬운 형태&lt;/b&gt;이지만, &lt;u&gt;&lt;b&gt;특수문자([2호선])가 포함&lt;/b&gt;&lt;/u&gt;되어 있고 모호할 수 있습니다. 반면 fullAddress는 시/도부터 상세 주소까지 포함된 완전한 형태로, 지오코딩 API가 정확하게 처리할 수 있는 형식입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;수정 전&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5UPtg/dJMcabXpTFT/PZYsgKhtbtVC3K6vrgKxYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5UPtg/dJMcabXpTFT/PZYsgKhtbtVC3K6vrgKxYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5UPtg/dJMcabXpTFT/PZYsgKhtbtVC3K6vrgKxYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5UPtg%2FdJMcabXpTFT%2FPZYsgKhtbtVC3K6vrgKxYK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;562&quot; height=&quot;203&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POI 목록에서 장소를 선택하면 &lt;b&gt;name 필드(예: &quot;강남역[2호선]&quot;)&lt;/b&gt;를 &lt;b&gt;그대로 입력창에 저장&lt;/b&gt;하고 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값을 그대로 &lt;b&gt;지오코딩 API에 전달&lt;/b&gt;하면 특수문자로 인한 URL 인코딩 문제와 함께, &quot;강남역&quot;이라는 모호한 정보만으로는 정확한 좌표를 얻기 어려워 &lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;400 에러&lt;/span&gt;&lt;/b&gt;가 발생했습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;수정 후&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjyglT/dJMcagqS9Ob/4YbIzKKC4DeO1XOw0BWfs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjyglT/dJMcagqS9Ob/4YbIzKKC4DeO1XOw0BWfs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjyglT/dJMcagqS9Ob/4YbIzKKC4DeO1XOw0BWfs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjyglT%2FdJMcagqS9Ob%2F4YbIzKKC4DeO1XOw0BWfs0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;207&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;name 대신 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;fullAddress&lt;/b&gt;&lt;/span&gt;를 사용하도록 변경했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 &quot;&lt;b&gt;서울특별시 강남구 역삼동&lt;/b&gt;&quot;과 같이 &lt;s&gt;특수문자&lt;/s&gt;가 없고 &lt;b&gt;행정구역 정보가 모두 포함된 정확한 주소&lt;/b&gt;가 지오코딩 API로 전달되어, 정상적으로 좌표 변환이 이루어집니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;수정 후 화면&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c28sB6/dJMb99SPNo0/BB7Z38iTYUV4hJP61s3BC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c28sB6/dJMb99SPNo0/BB7Z38iTYUV4hJP61s3BC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c28sB6/dJMb99SPNo0/BB7Z38iTYUV4hJP61s3BC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc28sB6%2FdJMb99SPNo0%2FBB7Z38iTYUV4hJP61s3BC1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;552&quot; height=&quot;325&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1120&quot; data-origin-height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 POI 리스트에서 &quot;강남역[2호선]&quot;을 선택하면 아래와 같이 &lt;b&gt;자연스럽게 fullAddress로 바뀌는 것&lt;/b&gt;을 볼 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이후 경로를 검색하면 정상적으로 경로가 나오게됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;  새로운 문제 : UX 저하&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 해결되었지만, 새로운 이슈가 발생했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용자가 기대하는 것&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력창에 &lt;b&gt;&quot;강남역&quot;&lt;/b&gt; 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제로 보이는 것&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력창에 &lt;b&gt;&quot;서울특별시 강남구 역삼동&quot;&lt;/b&gt; 표시&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 경험이 크게 저하되었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;최종 해결책 : Label과 Value 분리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;프론트엔드에서 &lt;u&gt;&lt;b&gt;표시용 데이터(Label)&lt;/b&gt;&lt;/u&gt;와 &lt;u&gt;&lt;b&gt;실제 사용 데이터(Value)&lt;/b&gt;&lt;/u&gt;를 분리하여 관리하는 방식으로 개선했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 상태 구조 개선&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;178&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXvoS7/dJMcabXpTQZ/aLjoTYXfsStB3sNERlz0Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXvoS7/dJMcabXpTQZ/aLjoTYXfsStB3sNERlz0Qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXvoS7/dJMcabXpTQZ/aLjoTYXfsStB3sNERlz0Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXvoS7%2FdJMcabXpTQZ%2FaLjoTYXfsStB3sNERlz0Qk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;171&quot; data-origin-width=&quot;604&quot; data-origin-height=&quot;178&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존에는 &lt;b&gt;단순히 문자열 하나만 저장&lt;/b&gt;했기 때문에, &lt;b&gt;&quot;사용자에게 보여줄 값&quot;&lt;/b&gt;과 &lt;b&gt;&quot;API에 전달할 값&quot;&lt;/b&gt;을 &lt;s&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;동시에 관리&lt;/b&gt;&lt;/span&gt;&lt;/s&gt;할 수 없었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;상태를 &lt;b&gt;객체 형태로 변경&lt;/b&gt;하여 &lt;b&gt;name(화면 표시용)&lt;/b&gt;과 &lt;b&gt;address(API 전송용)&lt;/b&gt;를 &lt;b&gt;별도로 저장&lt;/b&gt;할 수 있도록 개선했습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. POI 선택 시 두 값 모두 저장&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/po4Pp/dJMcadOpJV8/3CDAD4jge1kURkdfGf6Jz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/po4Pp/dJMcadOpJV8/3CDAD4jge1kURkdfGf6Jz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/po4Pp/dJMcadOpJV8/3CDAD4jge1kURkdfGf6Jz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpo4Pp%2FdJMcadOpJV8%2F3CDAD4jge1kURkdfGf6Jz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;306&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 POI 목록에서 장소를 선택하면, &lt;b&gt;두 가지 정보를 동시에 저장&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt; name&lt;/b&gt;&lt;/span&gt;에는 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;&quot;강남역[2호선]&quot;&lt;/b&gt;&lt;/span&gt;처럼 &lt;b&gt;사용자가 선택한 장소명을 저장&lt;/b&gt;하여 입력창에 표시하고, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;address&lt;/b&gt;&lt;/span&gt;에는 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&quot;서울특별시 강남구 역삼동 &quot;&lt;/span&gt;처럼 정확한 주소를 저장하여 나중에 API 호출 시 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 &lt;b&gt;UX는 유지하면서 기술적 정확성도 확보&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. UI와 API 호출 분리&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eAj8yg/dJMcajul1Hy/Gn3K3oPGBcV70pNfTZctn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eAj8yg/dJMcajul1Hy/Gn3K3oPGBcV70pNfTZctn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eAj8yg/dJMcajul1Hy/Gn3K3oPGBcV70pNfTZctn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeAj8yg%2FdJMcajul1Hy%2FGn3K3oPGBcV70pNfTZctn0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;283&quot; data-origin-width=&quot;614&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력창(&amp;lt;input&amp;gt;)의 value는 startInfo.name을 사용하여 사용자에게 &lt;b&gt;친숙한 장소명(&quot;강남역[2호선]&quot;)&lt;/b&gt;을 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, 검색 버튼을 클릭했을 때는 &lt;b&gt;startInfo.address&lt;/b&gt;를 전달하여&lt;b&gt; 백엔드가 정확한 주소로 지오코딩을 수행&lt;/b&gt;할 수 있도록 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 &lt;b&gt;화면에 보이는 값&lt;/b&gt;과 &lt;b&gt;실제 처리되는 값&lt;/b&gt;을 분리함으로써, 사용자 경험과 기술적 요구사항을 모두 충족시킬 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4. 사용자가 직접 입력한 경우 처리&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;176&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jqmaj/dJMcacvhTN1/ENXhS6cQ2xuFLYh3W5BtQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jqmaj/dJMcacvhTN1/ENXhS6cQ2xuFLYh3W5BtQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jqmaj/dJMcacvhTN1/ENXhS6cQ2xuFLYh3W5BtQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJqmaj%2FdJMcacvhTN1%2FENXhS6cQ2xuFLYh3W5BtQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;493&quot; height=&quot;176&quot; data-origin-width=&quot;493&quot; data-origin-height=&quot;176&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 &lt;b&gt;사용자가 POI 목록&lt;/b&gt;에서 &lt;s&gt;&lt;b&gt;선택&lt;/b&gt;&lt;/s&gt;하지 않고 &lt;b&gt;직접 &quot;강남역&quot;이라고 입력한 후 바로 검색 버튼&lt;/b&gt;을 누를 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 &lt;u&gt;&lt;b&gt;address는 비어있고 name만 존재&lt;/b&gt;&lt;/u&gt;하게 됩니다. || 연산자를 사용하여 address가 있으면 우선 사용하고, 없으면 name을 대신 사용하도록 fallback 처리를 추가했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 통해 POI 선택과 직접 입력 두 가지 입력 방식을 모두 지원할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;최종 수정 후 화면&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NSziu/dJMcaaqGsnX/QVFZ6klEqu5iDVydHqfHM1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NSziu/dJMcaaqGsnX/QVFZ6klEqu5iDVydHqfHM1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NSziu/dJMcaaqGsnX/QVFZ6klEqu5iDVydHqfHM1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNSziu%2FdJMcaaqGsnX%2FQVFZ6klEqu5iDVydHqfHM1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;328&quot; height=&quot;409&quot; data-origin-width=&quot;686&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 POI 리스트에서 &quot;강남역[2호선]&quot;을 선택하면 &lt;b&gt;화면에는 사용자 친화적인 &lt;u&gt;장소명이 그대로 표시&lt;/u&gt;&lt;/b&gt;되고, &lt;b&gt;백엔드로는 정확한 fullAddress가 전달&lt;/b&gt;되어 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;정상적으로 지오코딩이 수행&lt;/b&gt;&lt;/span&gt;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;핵심 교훈&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. &lt;b&gt;외부 API 연동 시 데이터 검증 필수&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 API는 예상치 못한 입력에 민감합니다. 특수문자, 인코딩, 데이터 형식 등을 철저히 검증해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;b&gt;POI명 &amp;ne; 주소&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;POI명: 사용자가 인식하기 쉬운 장소 이름 (&quot;강남역&quot;, &quot;스타벅스&quot;)&lt;/li&gt;
&lt;li&gt;주소: 시스템이 처리할 수 있는 정확한 위치 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘의 차이를 명확히 이해하고 적절히 변환해야 합니다.&lt;/p&gt;</description>
      <category>Trouble Shooting</category>
      <category>geocoding</category>
      <category>tmap</category>
      <category>지오코딩</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/772</guid>
      <comments>https://pixx.tistory.com/772#entry772comment</comments>
      <pubDate>Wed, 11 Feb 2026 22:07:04 +0900</pubDate>
    </item>
    <item>
      <title>[트러블슈팅] Next.js + Zustand 새로고침 시 로그인 상태 유실 문제 해결하기 (onRehydrateStorage )</title>
      <link>https://pixx.tistory.com/771</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트러블슈팅.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch7Ivk%2FdJMcacWg33U%2Fxk5KVRLdBtqBBLi76TKlAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;262&quot; height=&quot;262&quot; data-filename=&quot;트러블슈팅.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인 프로젝트를 진행하던 중 마이페이지에서 &lt;b&gt;새로고침 시&lt;/b&gt; &lt;b&gt;로그인 상태가 유실&lt;/b&gt;되어 &lt;b&gt;강제로 로그인 페이지로 리다이렉트&lt;/b&gt;되는 문제가 발생했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인에 성공한 후 메인 페이지에서는 &lt;b&gt;인증 상태가 정상적으로 유지&lt;/b&gt;되었지만, 페이지에서 새로고침을 하면 localStorage에 유효한 &lt;b&gt;토큰이 남아있음에도 불구&lt;/b&gt;하고 &lt;b&gt;사용자를 로그아웃시키는 현상&lt;/b&gt;이었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서는 이러한 문제에 대한 원인 분석과 해결 과정을 기록하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;문제&amp;nbsp;상황&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;문제 현상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로그인이 성공하여 메인 페이지에서는 인증 상태가 잘 유지되지만, &lt;b&gt;마이페이지에서 새로고침을 하면 &lt;span style=&quot;color: #ee2323;&quot;&gt;강제&lt;/span&gt;로 로그인 페이지로 리다이렉트&lt;/b&gt;됨.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 경험&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로고침할 때마다 다시 로그인해야 하는 치명적인 불편함 발생.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;원인&amp;nbsp;분석&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제의 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;523&quot; data-origin-height=&quot;324&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdTgmg/dJMcabXpqaP/HNVCDL30Invf1W4K70NwA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdTgmg/dJMcabXpqaP/HNVCDL30Invf1W4K70NwA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdTgmg/dJMcabXpqaP/HNVCDL30Invf1W4K70NwA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdTgmg%2FdJMcabXpqaP%2FHNVCDL30Invf1W4K70NwA1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;496&quot; height=&quot;307&quot; data-origin-width=&quot;523&quot; data-origin-height=&quot;324&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;핵심 원인&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt; Zustand의 메모리 기반 특성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Zustand는 기본적으로 &lt;u&gt;&lt;b&gt;메모리 기반 상태 관리 라이브러리&lt;/b&gt;&lt;/u&gt;입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;persist 미들웨어&lt;/b&gt;를 사용하면&lt;b&gt; localStorage에 상태를 저장&lt;/b&gt;하여 &lt;b&gt;새로고침 후에도 데이터를 유지&lt;/b&gt;할 수 있지만, &lt;/span&gt;&lt;span&gt;페이지가 새로고침되는 순간 Zustand 스토어는 일단 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;초기값(memberId: null)으로 시작&lt;/b&gt;&lt;/span&gt;됩니다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt; Hydration 복구 지연&lt;/b&gt; &lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 사이드에서 실행될 때, &lt;b&gt;Zustand&lt;/b&gt;의 &lt;b&gt;&lt;code&gt;persist&lt;/code&gt; 미들웨어&lt;/b&gt;가 &lt;b&gt;로컬스토리지에서 데이터를 읽어와 상태를 복구(Hydration)&lt;/b&gt;하는 데 &lt;b&gt;수 밀리초의 시간이 소요&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Race Condition (경쟁 상태)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제는 상태가 복구되기도&lt;span&gt;&amp;nbsp;&lt;/span&gt;전에&amp;nbsp;useEffect 내의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;인증 체크 로직이 먼저 실행&lt;/b&gt;&lt;/u&gt;된다는 점입니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1770739543852&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;t=0ms  : 페이지 새로고침
       &amp;rarr; Zustand 스토어 초기화: memberId = null

t=1ms  : useEffect 실행
       &amp;rarr; if (!memberId) 조건 충족
       &amp;rarr; router.push('/login') &amp;lt;--

t=5ms  : localStorage 복구 완료
       &amp;rarr; memberId = &quot;user123&quot; (하지만 이미 늦음)

t=10ms : /login 페이지로 이동 완료&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;즉, &lt;b&gt;localStorage&lt;/b&gt;에 유효한 토큰이 있음에도 불구하고 &lt;u&gt;&lt;b&gt;복구되기 전&lt;/b&gt;&lt;/u&gt;에 &lt;b&gt;검증 로직이 실행&lt;/b&gt;되어 &lt;/span&gt;&lt;span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;사용자를 강제로 로그아웃시키는 현상&lt;/b&gt;&lt;/span&gt;이 발생한 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;Hydration이란❓&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Hydration은 Next.js와 같은 SSR/SSG 프레임워크에서 발생하는 &lt;b&gt;서버 렌더링 HTML&lt;/b&gt;과 &lt;b&gt;클라이언트 자바스크립트&lt;/b&gt;를 &lt;u&gt;&lt;b&gt;연결하는 과정&lt;/b&gt;&lt;/u&gt;입니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/drryGP/dJMcajgNc9R/pvOV2dKtSLMfhMoQZD631K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/drryGP/dJMcajgNc9R/pvOV2dKtSLMfhMoQZD631K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/drryGP/dJMcajgNc9R/pvOV2dKtSLMfhMoQZD631K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdrryGP%2FdJMcajgNc9R%2FpvOV2dKtSLMfhMoQZD631K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;523&quot; height=&quot;257&quot; data-origin-width=&quot;621&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Zustand의 &lt;b&gt;persist 미들웨어&lt;/b&gt;는 &lt;b&gt;4번 Hydration 단계&lt;/b&gt;에서 &lt;b&gt;localStorage&lt;/b&gt;의 데이터를 읽어와 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;전역 상태를 복구&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정은 비동기적이며 수 밀리초가 소요됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;유효한 인증 정보&lt;/b&gt;가 있음에도 &lt;b&gt;복구되기 전&lt;/b&gt;에 &lt;b&gt;검증 로직이 실행&lt;/b&gt;되어 &lt;b&gt;사용자를 로그아웃시키는 현상&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;해결&amp;nbsp;방법&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전략: Rehydration 완료를 보장하는 가드 패턴&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Zustand&lt;/b&gt;의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;onRehydrateStorage 라이프사이클 훅&lt;/b&gt;&lt;/span&gt;을 활용하여 &lt;b&gt;복구 완료 시점을 &lt;u&gt;명시적으로 추적&lt;/u&gt;&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;onRehydrateStorage 라이프사이클 훅이란❓&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;onRehydrateStorage&lt;/b&gt;는 Zustand의&amp;nbsp;&lt;b&gt;persist 미들웨어&lt;/b&gt;가 제공하는&amp;nbsp;&lt;u&gt;&lt;b&gt;라이프사이클 콜백 함수&lt;/b&gt;&lt;/u&gt;입니다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Storage&lt;/b&gt;에서 &lt;b&gt;저장된 상태&lt;/b&gt;를 읽어와&amp;nbsp;&lt;b&gt;Zustand 스토어&lt;/b&gt;에 &lt;b&gt;복구(rehydrate)하는 과정&lt;/b&gt;의&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;시작&lt;/b&gt;&lt;/span&gt;과&amp;nbsp;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;완료 시점&lt;/b&gt;&lt;/span&gt;을&amp;nbsp;&lt;b&gt;감지&lt;/b&gt;할 수 있게 해주는 훅입니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;[Step 1] Store에 Hydration 상태 플래그 추가&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;onRehydrateStorage&lt;/code&gt;를 이용해 &lt;b&gt;복구가 끝난 시점&lt;/b&gt;을 &lt;b&gt;전역 상태로 관리&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckvAHI/dJMcahDjqXM/3CeBkekiAkpxbMfAOr38o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckvAHI/dJMcahDjqXM/3CeBkekiAkpxbMfAOr38o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckvAHI/dJMcahDjqXM/3CeBkekiAkpxbMfAOr38o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckvAHI%2FdJMcahDjqXM%2F3CeBkekiAkpxbMfAOr38o0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;463&quot; height=&quot;472&quot; data-origin-width=&quot;569&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Store&lt;/b&gt;에 &lt;b&gt;Hydration 완료 여부&lt;/b&gt;를 추적하는 &lt;b&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;_hasHydrated 플래그&lt;/span&gt;를 추가&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;onRehydrateStorage 라이프사이클 훅&lt;/b&gt;은 localStorage에서 &lt;b&gt;데이터 복구가 완료되는 시점&lt;/b&gt;에 &lt;b&gt;자동으로 호출&lt;/b&gt;되며, 이때 &lt;code&gt;&lt;b&gt;setHasHydrated(true)&lt;/b&gt;&lt;/code&gt;를 실행하여 &lt;b&gt;복구 완료 상태를 전역적으로 알립니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 플래그를 통해 컴포넌트들은 &lt;i&gt;&lt;b&gt;&quot;아직 복구 중인지&lt;/b&gt;&lt;b&gt;&quot;&lt;/b&gt;&lt;/i&gt; 혹은 &lt;i&gt;&lt;b&gt;&quot;복구가 끝났는지&quot; &lt;/b&gt;&lt;/i&gt;를 정확히 판단할 수 있게 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;[Step 2] 컴포넌트에 가드 로직 적용&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/em6Nf9/dJMcacIN9KF/V2ca0YbtBf1ZBy9TjQUGGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/em6Nf9/dJMcacIN9KF/V2ca0YbtBf1ZBy9TjQUGGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/em6Nf9/dJMcacIN9KF/V2ca0YbtBf1ZBy9TjQUGGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fem6Nf9%2FdJMcacIN9KF%2FV2ca0YbtBf1ZBy9TjQUGGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;462&quot; height=&quot;502&quot; data-origin-width=&quot;462&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포넌트에서 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;_hasHydrated 플래그&lt;/b&gt;&lt;/span&gt;를 활용하여 &lt;b&gt;2단계 가드 로직을 구현&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;첫 번째 가드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hydration이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;완료&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;되지 않았다면 인증 검증을 유예하고 &lt;u&gt;&lt;b&gt;조기 반환&lt;/b&gt;&lt;/u&gt;합니다.&lt;/li&gt;
&lt;li&gt;이를 통해 복구 전의 null 상태를 &quot;인증 실패&quot;로 &lt;b&gt;오판하는 것을 방지&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;두 번째 가드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hydration &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;완료&lt;/b&gt;&lt;/span&gt; 후에만 실행되며, 이 시점에서 &lt;b&gt;memberId&lt;/b&gt;가 없다면 &lt;u&gt;&lt;b&gt;진짜 미인증 상태&lt;/b&gt;&lt;/u&gt;이므로 로그인 페이지로 &lt;b&gt;리다이렉트&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &amp;nbsp;해결&amp;nbsp;방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Next.js 환경에서 &lt;b&gt;Zustand persist&lt;/b&gt;를 사용할 때 발생하는 &lt;b&gt;Hydration Race Condition&lt;/b&gt;은 예상치 못한 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;UX 문제를 야기&lt;/b&gt;&lt;/span&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 트러블슈팅을 통해 &lt;b&gt;onRehydrateStorage 라이프사이클 훅&lt;/b&gt;과 &lt;b&gt;_hasHydrated 플래그&lt;/b&gt;를 활용한 가드 패턴으로 이 문제를 근본적으로 해결할 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 사용자는 새로고침 시에도 &lt;b&gt;안정적으로 로그인 상태를 유지&lt;/b&gt;할 수 있게 되었으며,&lt;s&gt;&lt;b&gt; 불필요한 재로그인&lt;/b&gt;&lt;/s&gt; 없이 원활한 서비스 이용이 가능해졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 상태 관리에서 &lt;b&gt;Hydration 타이밍을 명시적으로 제어&lt;/b&gt;하는 것의 중요성을 다시 한번 체감할 수 있었던 경험이었습니다.&lt;/p&gt;</description>
      <category>Trouble Shooting</category>
      <category>hydration</category>
      <category>Next.js</category>
      <category>onRehydrateStorage</category>
      <category>Zustand</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/771</guid>
      <comments>https://pixx.tistory.com/771#entry771comment</comments>
      <pubDate>Tue, 10 Feb 2026 23:38:27 +0900</pubDate>
    </item>
    <item>
      <title>[트러블 슈팅] TMAP API 다중 경로 조회 : Mono.zip으로 동시 요청 처리하기</title>
      <link>https://pixx.tistory.com/769</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;트러블슈팅.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ch7Ivk/dJMcacWg33U/xk5KVRLdBtqBBLi76TKlAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fch7Ivk%2FdJMcacWg33U%2Fxk5KVRLdBtqBBLi76TKlAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;262&quot; height=&quot;262&quot; data-filename=&quot;트러블슈팅.png&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;400&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인 지도 API 기반 토이 프로젝트인 &lt;b&gt;&quot;안심 맵(Ansim Map)&quot;&lt;/b&gt; 을 개발하던 중, TMAP API 사용 과정에서 &lt;b&gt;단일 경로만 반환되는 파라미터 제약&lt;/b&gt; 이슈를 발견했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자에게 &lt;b&gt;&quot;최적 경로&quot;&lt;/b&gt;와 &lt;b&gt;&quot;안전한 대로 우선 경로&quot;&lt;/b&gt;를 모두 제공하여 선택권을 주려는 프로젝트의 핵심 기능이 구현 불가능한 상황이었고, 이를 &lt;b&gt;Spring WebFlux의 Mono.zip을 활용한 병렬 요청 처리&lt;/b&gt;로 해결했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서는 문제 상황 분석부터 해결 과정, 그리고 실제 코드 적용까지의 트러블 슈팅 전 과정을 정리하고자 합니다.&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;  문제 상황&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인 토이 프로젝트에서 &lt;b&gt;TMAP 자동차 경로 API&lt;/b&gt;를 사용하던 중, &lt;u&gt;&lt;b&gt;사용자에게 여러 경로 옵션을 제공할 수 없다&lt;/b&gt;&lt;/u&gt;는 문제에 직면했습니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;발생한 이슈&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;TMAP API는 &lt;b&gt;한 번의 요청당 하나의 경로만 반환&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;사용자가 &quot;최적 경로 A&quot;와 &quot;최적 경로 B&quot;를 비교할 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기존 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kGbP0/dJMcaa5e6MA/5w2tfml4m2rpHOyIZpXzk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kGbP0/dJMcaa5e6MA/5w2tfml4m2rpHOyIZpXzk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kGbP0/dJMcaa5e6MA/5w2tfml4m2rpHOyIZpXzk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkGbP0%2FdJMcaa5e6MA%2F5w2tfml4m2rpHOyIZpXzk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;730&quot; height=&quot;222&quot; data-origin-width=&quot;783&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;  원인 분석&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;a href=&quot;https://tmapapi.tmapmobility.com/main.html#webservice/docs/tmapRouteDoc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;TMAP API 공식 문서&lt;/a&gt;&lt;/b&gt;를 확인한 결과 searchOption 파라미터는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw37K8/dJMcaiIV3H0/7JcuTCxYZaRbtLv256oLaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw37K8/dJMcaiIV3H0/7JcuTCxYZaRbtLv256oLaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw37K8/dJMcaiIV3H0/7JcuTCxYZaRbtLv256oLaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw37K8%2FdJMcaiIV3H0%2F7JcuTCxYZaRbtLv256oLaK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;729&quot; height=&quot;217&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;searchOption 파라미터 명세&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; &lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;타입&lt;/span&gt;&lt;span&gt;: Number (단일 숫자 값)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;설명&lt;/span&gt;&lt;span&gt;: 경로 탐색 옵션 &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`0`&lt;/span&gt;&lt;span&gt;: 교통최적+추천(기본값)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`1`&lt;/span&gt;&lt;span&gt;: 교통최적+무료우선&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`4`&lt;/span&gt;&lt;span&gt;: 교통최적+고속도로우선&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`10`&lt;/span&gt;&lt;span&gt;: 최단거리+유/무료&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`19`&lt;/span&gt;&lt;span&gt;: 교통최적+어린이보호구역 회피 &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;기타 옵션...&lt;/span&gt;&lt;/span&gt; &lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;발견한 제약 사항&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;searchOption 파라미터&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;&lt;span&gt;하나의 숫자 값(단일 값)&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;&lt;span&gt;만 받는 구조&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;배열이나 여러 값을 동시에 전달할 수 있는 방법이 없음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결론&lt;/b&gt;: 다중 경로를 얻으려면 &lt;u&gt;&lt;b&gt;여러 번 요청&lt;/b&gt;&lt;/u&gt;해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;  해결 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Spring WebFlux&lt;/b&gt;의 &lt;b&gt;Mono.zip&lt;/b&gt;을 활용하여 두 개의 API 요청을 &lt;b&gt;동시에 실행&lt;/b&gt;하고, 결과를 &lt;b&gt;리스트로 묶어 반환&lt;/b&gt;하도록 구조를 변경했습니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;핵심 아이디어&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;단일 경로가 아닌 다중경로 &lt;b&gt;최적 경로(searchOption=0)&lt;/b&gt;와 &lt;b&gt;대로 우선 경로(searchOption=4)&lt;/b&gt; 요청을 동시에 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Mono.zip&lt;/b&gt;으로 두 비동기 작업을 병렬 실행&lt;/li&gt;
&lt;li&gt;두 결과를 &lt;b&gt;List&lt;/b&gt;로 묶어서 프론트엔드에 전달&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;코드 수정&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;499&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cW2ixI/dJMcagRWaqe/duGDWOJ1iIVKfviKEOAddk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cW2ixI/dJMcagRWaqe/duGDWOJ1iIVKfviKEOAddk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cW2ixI/dJMcagRWaqe/duGDWOJ1iIVKfviKEOAddk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcW2ixI%2FdJMcagRWaqe%2FduGDWOJ1iIVKfviKEOAddk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;419&quot; data-origin-width=&quot;857&quot; data-origin-height=&quot;499&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;✅ 해결 결과&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Before (단일 경로)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;tmp.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biKXjq/dJMcacBZHyE/Fupj9n7X9uaqt8uTLmWqPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biKXjq/dJMcacBZHyE/Fupj9n7X9uaqt8uTLmWqPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biKXjq/dJMcacBZHyE/Fupj9n7X9uaqt8uTLmWqPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiKXjq%2FdJMcacBZHyE%2FFupj9n7X9uaqt8uTLmWqPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;760&quot; height=&quot;430&quot; data-filename=&quot;tmp.png&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;After (다중 경로 배열)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;tmp.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;1136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pljns/dJMcah4m9V6/wkKMUm3MlKaX9IWqJyDYb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pljns/dJMcah4m9V6/wkKMUm3MlKaX9IWqJyDYb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pljns/dJMcah4m9V6/wkKMUm3MlKaX9IWqJyDYb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpljns%2FdJMcah4m9V6%2FwkKMUm3MlKaX9IWqJyDYb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;646&quot; height=&quot;815&quot; data-filename=&quot;tmp.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;1136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예시에서는 2개의 경로 옵션(최적, 대로 우선)였지만, &lt;b&gt;실제 프로젝트에서는 사용자에게 더 다양한 선택지를 제공하기 위해 &lt;span style=&quot;color: #009a87;&quot;&gt;7개&lt;/span&gt;의 경로 옵션을 동시에 조회&lt;/b&gt;하도록 확장했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Mono.zip&lt;/b&gt;의 장점은 요청 개수가 늘어나도 &lt;u&gt;&lt;b&gt;동일한 패턴으로 확장이 가능&lt;/b&gt;&lt;/u&gt;하다는 점입니다. 2개든 7개든 모든 요청이 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;병렬로 처리&lt;/b&gt;&lt;/span&gt;되어 응답 시간은 가장 느린 단일 요청과 비슷한 수준으로 유지됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;  참고 자료&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://tmapapi.tmapmobility.com/main.html#webservice/docs/tmapRouteDoc&quot;&gt;TMAP API 경로 안내 공식 문서&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Mono.html#zip-reactor.core.publisher.Mono-reactor.core.publisher.Mono-&quot;&gt;Spring WebFlux Mono.zip Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;  핵심 포인트&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;TMAP API는 단건 요청만 지원&lt;/b&gt; - 다중 경로는 여러 번 호출 필요&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Mono.zip 활용&lt;/b&gt;으로 동시 요청 처리하여 성능 최적화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;searchOption 0(최적) + 4(대로 우선)&lt;/b&gt; 조합으로 사용자 선택권 확보&lt;/li&gt;
&lt;li&gt;반환 타입을 List로 변경하여 프론트엔드 통합 용이&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Trouble Shooting</category>
      <category>Tmap api</category>
      <category>Troubleshooting</category>
      <category>트러블 슈팅</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/769</guid>
      <comments>https://pixx.tistory.com/769#entry769comment</comments>
      <pubDate>Fri, 6 Feb 2026 00:25:33 +0900</pubDate>
    </item>
    <item>
      <title>[Spring boot] HandlerMethodArgumentResolver 이해하고 활용하기</title>
      <link>https://pixx.tistory.com/767</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1AqzH%2FbtsMyTT86M1%2FV8DfRaXFjDMumvvn5knww0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;163&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;웹&amp;nbsp;애플리케이션을&amp;nbsp;개발하다&amp;nbsp;보면&amp;nbsp;&lt;b&gt;컨트롤러&lt;/b&gt;에서&amp;nbsp;&lt;b&gt;반복적으로&amp;nbsp;수행&lt;/b&gt;하는&amp;nbsp;작업들이&amp;nbsp;있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;헤더에서 토큰을 꺼내서 파싱&lt;/li&gt;
&lt;li&gt;쿠키나 세션에서 사용자 정보 가져오기&lt;/li&gt;
&lt;li&gt;특정 헤더 값을 객체로 변환하기&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;b&gt;스프링 시큐리티&lt;/b&gt;를 사용할 때, 인증된 사용자 정보가 &lt;b&gt;SecurityContext&lt;/b&gt;의 &lt;b&gt;Principal&lt;/b&gt;에 담기는데, 이를 꺼내는 작업도 매번 반복됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;543&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kwIiZ/dJMb99SLWrI/Vo0wEdxWgCTwErYeSaaoN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kwIiZ/dJMb99SLWrI/Vo0wEdxWgCTwErYeSaaoN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kwIiZ/dJMb99SLWrI/Vo0wEdxWgCTwErYeSaaoN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkwIiZ%2FdJMb99SLWrI%2FVo0wEdxWgCTwErYeSaaoN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;543&quot; height=&quot;286&quot; data-origin-width=&quot;543&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이런 코드가 모든 컨트롤러 메서드마다 반복된다면 코드 중복이 심해지고 유지보수가 어려워집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;span&gt;이때 사용할 수 있는 것이 바로 &lt;/span&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;HandlerMethodArgumentResolver&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다. &lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;오늘은 이 &lt;b&gt;HandlerMethodArgumentResolver&lt;/b&gt;에 대해서 공부한 내용을 정리하고자 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;HandlerMethodArgumentResolver란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HandlerMethodArgumentResolver&lt;/b&gt;는 스프링 MVC에서&lt;b&gt; 컨트롤러 메서드&lt;/b&gt;의 &lt;u&gt;&lt;b&gt;파라미터를 유연하게 처리&lt;/b&gt;&lt;/u&gt;할 수 있게 해주는 인터페이스입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;69&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRgWVv/dJMcabwg1ZT/uqSY8KTHxwItY95g6ZV6WK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRgWVv/dJMcabwg1ZT/uqSY8KTHxwItY95g6ZV6WK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRgWVv/dJMcabwg1ZT/uqSY8KTHxwItY95g6ZV6WK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRgWVv%2FdJMcabwg1ZT%2FuqSY8KTHxwItY95g6ZV6WK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;878&quot; height=&quot;69&quot; data-origin-width=&quot;878&quot; data-origin-height=&quot;69&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 Spring 공식 Docs를 보면 다음과 같이 설명하고 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;주어진 요청&lt;/b&gt;의 &lt;b&gt;컨텍스트 내&lt;/b&gt;에서 &lt;u&gt;&lt;b&gt;메서드 매개변수&lt;/b&gt;&lt;/u&gt;를 &lt;u&gt;&lt;b&gt;인자 값으로 변환&lt;/b&gt;&lt;/u&gt;하기 위한 전략 인터페이스&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;HTTP 요청&lt;/b&gt;이 들어왔을 때 &lt;u&gt;&lt;b&gt;컨트롤러 메서드의 파라미터에 어떤 값을 넣어줄지 결정&lt;/b&gt;&lt;/u&gt;하는 역할을 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;동작 흐름&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&amp;nbsp; 클라이언트 HTTP 요청&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ⬇️&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt; DispatcherServlet이 요청 수신 &lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ⬇️&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt; 적절한 컨트롤러 메서드 찾기 &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ⬇️&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt;&lt;span&gt;&lt;span&gt; ArgumentResolver가 파라미터 분석 및 값 주입 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ⬇️&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;5.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;컨트롤러 메서드 실행&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;인터페이스 구조&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HandlerMethodArgumentResolver&lt;/b&gt;는 &lt;b&gt;두 개의 핵심 메서드&lt;/b&gt;로 구성되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;470&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dt572N/dJMcai9XFyr/ko6JZMo2vuIeBIGOsHR890/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dt572N/dJMcai9XFyr/ko6JZMo2vuIeBIGOsHR890/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dt572N/dJMcai9XFyr/ko6JZMo2vuIeBIGOsHR890/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdt572N%2FdJMcai9XFyr%2Fko6JZMo2vuIeBIGOsHR890%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;695&quot; height=&quot;470&quot; data-origin-width=&quot;695&quot; data-origin-height=&quot;470&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;supportsParameter()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt; 해당 &lt;b&gt;Resolver&lt;/b&gt;가 &lt;b&gt;특정 메서드 파라미터를 처리할 수 있는지 여부&lt;/b&gt;를 결정합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파라미터의 어노테이션, 타입, 이름 등을 검사하여 처리 가능 여부를 판단합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;를 반환하면&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt; 이 Resolver가 해당 파라미터를 처리&lt;/b&gt;&lt;/span&gt;하게 되며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;false&lt;/b&gt;&lt;/span&gt;를 반환하면 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;다른 Resolver가 처리를 시도&lt;/b&gt;&lt;/span&gt;합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스프링은 등록된 모든 Resolver를 순회하며 supportsParameter()가 true를 반환하는 첫 번째 Resolver를 사용합니다. &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;resolveArgument()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;supportsParameter()`가 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;를 반환한 경우, &lt;b&gt;실제로 파라미터&lt;/b&gt;에&lt;u&gt;&lt;b&gt; 주입할 값을 생성하고 반환&lt;/b&gt;&lt;/u&gt;합니다.&lt;/li&gt;
&lt;li&gt;HTTP 요청 정보(NativeWebRequest)를 활용하여 &lt;b&gt;헤더, 쿠키, 세션 등에서 필요한 데이터를 추출&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;생성된 객체는 컨트롤러 메서드의 해당 파라미터에 &lt;b&gt;자동으로 주입&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;예외 발생 시 적절한 예외 처리를 통해 클라이언트에게 의미 있는 오류 응답을 제공해야 합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;구현 단계&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1단계 : 커스텀 어노테이션 정의&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 컨트롤러 파라미터에 붙일 &lt;b&gt;어노테이션&lt;/b&gt;을 만듭니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;134&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpQqZU/dJMcadgyCks/mxCkFlKIbYIruzw4hejl9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpQqZU/dJMcadgyCks/mxCkFlKIbYIruzw4hejl9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpQqZU/dJMcadgyCks/mxCkFlKIbYIruzw4hejl9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpQqZU%2FdJMcadgyCks%2FmxCkFlKIbYIruzw4hejl9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;574&quot; height=&quot;134&quot; data-origin-width=&quot;574&quot; data-origin-height=&quot;134&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;@Target(ElementType.PARAMETER)&lt;/i&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메서드 파라미터에만 사용 가능하도록 제한&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;i&gt;@Retention(RetentionPolicy.RUNTIME)&lt;/i&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;런타임 시점에도 어노테이션 정보를 유지&lt;/b&gt;하여 리플렉션으로 읽을 수 있게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2단계 : HandlerMethodArgumentResolver 구현&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 파라미터 값을 주입하는 &lt;b&gt;Resolver&lt;/b&gt;를 구현합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;537&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKJes6/dJMcai9XFz7/LIsr45wQXEawVePcF1OFMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKJes6/dJMcai9XFz7/LIsr45wQXEawVePcF1OFMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKJes6/dJMcai9XFz7/LIsr45wQXEawVePcF1OFMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKJes6%2FdJMcai9XFz7%2FLIsr45wQXEawVePcF1OFMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;734&quot; height=&quot;537&quot; data-origin-width=&quot;734&quot; data-origin-height=&quot;537&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;supportsParameter()&amp;nbsp;메서드&lt;/i&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;@LoginUser 어노테이션이 붙어있는지 확인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;파라미터 타입이 &quot;&lt;b&gt;String&lt;/b&gt;&quot;인지 확인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;두 조건을 &lt;b&gt;모두 만족&lt;/b&gt;하면 이 &lt;u&gt;&lt;b&gt;Resolver가 처리&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;span style=&quot;color: #000000;&quot;&gt; resolveArgument() 메서드&lt;/span&gt;&lt;/i&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;SecurityContext&lt;/b&gt;에서 &lt;b&gt;현재 인증 정보&lt;/b&gt;를 가져옴&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;JWT 필터에서 이미 검증을 마치고 &quot;SecurityContext&quot;`에 저장한 인증 정보&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&quot;&lt;b&gt;Authentication&lt;/b&gt;&quot; 객체에서 사용자 &lt;u&gt;&lt;b&gt;이메일(또는 식별자)을 추출&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;해당 값을 &lt;b&gt;컨트롤러 메서드의 파라미터로 주입 &lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3단계 : WebMvcConfigurer에&amp;nbsp;Resolver&amp;nbsp;등록&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만든&lt;b&gt; Resolver를 스프링에 등록&lt;/b&gt;해야 실제로 동작합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/can25V/dJMcahDfc5D/unixaKRCUg2sy1YYFmdfhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/can25V/dJMcahDfc5D/unixaKRCUg2sy1YYFmdfhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/can25V/dJMcahDfc5D/unixaKRCUg2sy1YYFmdfhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcan25V%2FdJMcahDfc5D%2FunixaKRCUg2sy1YYFmdfhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;208&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;WebMvcConfigurer&lt;/b&gt; 인터페이스의 &lt;b&gt;addArgumentResolvers() 메서드&lt;/b&gt;를 오버라이드하여 우리가&lt;b&gt; 만든 Resolver를 등록&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 이제 스프링이 컨트롤러 메서드를 호출할 때 &lt;b&gt;우리가 만든 Resolver를 사용&lt;/b&gt;하게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4단계 : 컨트롤러에서 사용&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;Before : Resolver 사용 전&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ol5xZ/dJMcai3cfRt/Ru24zGM9eNLKvKsQlRM9J1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ol5xZ/dJMcai3cfRt/Ru24zGM9eNLKvKsQlRM9J1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ol5xZ/dJMcai3cfRt/Ru24zGM9eNLKvKsQlRM9J1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fol5xZ%2FdJMcai3cfRt%2FRu24zGM9eNLKvKsQlRM9J1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;517&quot; height=&quot;282&quot; data-origin-width=&quot;517&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;문제점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;헤더 파싱 코드가 매번 반복됨&lt;/li&gt;
&lt;li&gt;토큰 검증 로직이 컨트롤러에 노출됨&lt;/li&gt;
&lt;li&gt;코드가 길어지고, 가독성 하락&lt;/li&gt;
&lt;li&gt;인증 로직 변경 시 모든 컨트롤러 수정이 필&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;After : Resolver 사용&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;173&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brTZxX/dJMcaaD9j0N/k7DT9mvIII7iUsdvUdYG8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brTZxX/dJMcaaD9j0N/k7DT9mvIII7iUsdvUdYG8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brTZxX/dJMcaaD9j0N/k7DT9mvIII7iUsdvUdYG8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrTZxX%2FdJMcaaD9j0N%2Fk7DT9mvIII7iUsdvUdYG8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;544&quot; height=&quot;173&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;173&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 로그아웃 엔드포인트를 보면 &lt;b&gt;@LoginUser&amp;nbsp;어노테이션&lt;/b&gt; 하나로 인증된 사용자의 이메일을 바로 받아올 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;동작 흐름&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클라이언트가 JWT 토큰과 함께 /logout 요청&lt;/li&gt;
&lt;li&gt;Spring Security Filter에서 JWT 검증 및 &lt;b&gt;&quot;SecurityContext&quot;&lt;/b&gt;에 &lt;b&gt;인증 정보 저장&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;컨트롤러 호출 &lt;u&gt;&lt;b&gt;전&lt;/b&gt;&lt;/u&gt; &lt;b&gt;LoginUserArgumentResolver가 동작&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&quot;SecurityContext&quot;에서 이메일 추출하여 파라미터에 주입&lt;/li&gt;
&lt;li&gt;컨트롤러 메서드 실행&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;추가 활용 방안 1&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이메일 대신&lt;u&gt;&lt;b&gt; User 객체 전체를 주입&lt;/b&gt;&lt;/u&gt;하고 싶다면 다음과 같이 수정할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;575&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biAaYU/dJMcaajQrgH/9Jny8t2kCGxvuB4WPiEAw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biAaYU/dJMcaajQrgH/9Jny8t2kCGxvuB4WPiEAw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biAaYU/dJMcaajQrgH/9Jny8t2kCGxvuB4WPiEAw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiAaYU%2FdJMcaajQrgH%2F9Jny8t2kCGxvuB4WPiEAw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;648&quot; height=&quot;494&quot; data-origin-width=&quot;754&quot; data-origin-height=&quot;575&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;컨트롤러에서의 사용&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;146&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ub1vm/dJMcaivnaRU/hk99Jo99BKxklXVyRyHJPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ub1vm/dJMcaivnaRU/hk99Jo99BKxklXVyRyHJPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ub1vm/dJMcaivnaRU/hk99Jo99BKxklXVyRyHJPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fub1vm%2FdJMcaivnaRU%2Fhk99Jo99BKxklXVyRyHJPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;516&quot; height=&quot;146&quot; data-origin-width=&quot;516&quot; data-origin-height=&quot;146&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;추가 활용 방안 2&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 로그인하지 않아도 되는 엔드포인트&lt;/b&gt;에서 사용하려면&lt;b&gt;&amp;nbsp;&lt;u&gt;null을 허용하도록 구현&lt;/u&gt;&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;277&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cRN6e2/dJMcacoqmVS/IZH96DqpkT7APaPS6FzQmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cRN6e2/dJMcacoqmVS/IZH96DqpkT7APaPS6FzQmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cRN6e2/dJMcacoqmVS/IZH96DqpkT7APaPS6FzQmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcRN6e2%2FdJMcacoqmVS%2FIZH96DqpkT7APaPS6FzQmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;607&quot; height=&quot;277&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;277&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;컨트롤러에서의 사용&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BHY0Q/dJMcahDfcPs/CmTipBTugE93ScfPBZNRf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BHY0Q/dJMcahDfcPs/CmTipBTugE93ScfPBZNRf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BHY0Q/dJMcahDfcPs/CmTipBTugE93ScfPBZNRf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBHY0Q%2FdJMcahDfcPs%2FCmTipBTugE93ScfPBZNRf1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;546&quot; height=&quot;159&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;159&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;마무리&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;HandlerMethodArgumentResolver&lt;/b&gt;를 활용하면 다음과 같은 이점을 얻을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;코드 중복 제거&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복되는 인증 코드를 한 곳에서 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;관심사 분리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비즈니스 로직과 인증 로직을 명확히 분리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가독성 향상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨트롤러가 비즈니스 로직에만 집중&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;유지보수 용이&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증 로직 변경 시 Resolver만 수정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명확한 의도&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@LoginUser 어노테이션으로 &quot;이 API는 로그인 필요&quot;를 명시&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;다만, 다음과 같은 단점도 고려해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;학습 곡선&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스프링 내부 동작 원리에 대한 이해 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디버깅 복잡도&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행 흐름 추적이 어려울 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테스트 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단위 테스트 작성 시 추가 설정 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 고려&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;DB 조회가 필요한 경우 캐싱 전략 필수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;스프링이 제공하는 확장 포인트를 잘 활용하면 더 깔끔하고 유지보수하기 좋은 코드를 작성할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 특히 인증/인가 로직처럼 모든 엔드포인트에서 반복되는 코드가 있다면, `HandlerMethodArgumentResolver`를 적극 활용해보는 것도 좋은 방법이라고 생각합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;물론 프로젝트의 규모와 팀의 상황에 따라 적절히 판단하여 사용하는 것이 중요할 것 같습니다. 작은 프로젝트에서는 오히려 과도한 추상화가 될 수 있으니, 반복 코드가 실제로 문제가 될 때 도입하는 것이 좋을 것 같다는 생각이 듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt; 이번 글을 통해 &lt;b&gt;HandlerMethodArgumentResolver&lt;/b&gt;의 동작 원리와 활용 방법을 정리해볼 수 있었습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;참고 자료&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;&lt;a style=&quot;color: #666666;&quot; href=&quot;https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/method/support/HandlerMethodArgumentResolver.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Spring Framework 공식 문서 - HandlerMethodArgumentResolver]&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-framework/reference/web/webmvc.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;[Spring MVC 공식 가이드]&lt;/span&gt;&lt;/a&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Framework/Spring\Spring boot</category>
      <category>HandlerMethodArgumentResolver</category>
      <category>Resolver</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/767</guid>
      <comments>https://pixx.tistory.com/767#entry767comment</comments>
      <pubDate>Sun, 1 Feb 2026 22:58:28 +0900</pubDate>
    </item>
    <item>
      <title>[Next.js] layout.tsx를 Providers로 감싸야 하는 이유</title>
      <link>https://pixx.tistory.com/766</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;nextjs.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mirtH/dJMcabptORZ/XyB0IZEuaEYkSkYBoskaQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mirtH/dJMcabptORZ/XyB0IZEuaEYkSkYBoskaQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mirtH/dJMcabptORZ/XyB0IZEuaEYkSkYBoskaQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmirtH%2FdJMcabptORZ%2FXyB0IZEuaEYkSkYBoskaQ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;nextjs.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Next.js(&lt;b&gt;App Router&lt;/b&gt;)로 개발을 하다 보면 Context API, Query Client, 또는 Theme Provider를 설정할 때 한 번쯤 이런 에러를 마주치게 됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt; &quot;Error: Next.js Server Components do not support Context.&quot; &lt;/b&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;보통 layout.tsx에 바로 Provider를 작성하려 할 때 발생합니다. 이번 글에서는 왜 layout.tsx를 별도의 Providers 컴포넌트로 감싸야 하는지, 그 구조적 이유와 이점에 대해서 공부한 내용을 정리해보고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;왜 에러가 날까❓&lt;/h3&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;Next.js의&lt;b&gt; App Router&lt;/b&gt;는 기본적으로&lt;b&gt; 모든 컴포넌트를 &lt;u&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;서버 컴포넌트&lt;/span&gt;(Server Components)로 간주&lt;/u&gt;&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;하지만 React Context, Redux, React Query, Theme Provider 같은 &lt;b&gt;상태 관리 라이브러리&lt;/b&gt;들은 클라이언트 사이드에서만 동작합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;이들은 React의 &lt;b&gt;useState, useEffect 같은 훅을 사용&lt;/b&gt;하기 때문입니다. 여기서 문제가 발생합니다. layout.tsx는 기본적으로 Server Component인데, 클라이언트 전용 기능을 직접 사용할 수 없습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;즉, layout.tsx는 애플리케이션의 뼈대를 담당하는 서버 컴포넌트인데, 여기에 직접 &lt;b&gt;createContext&lt;/b&gt;나 &lt;b&gt;Provider&lt;/b&gt;를 넣으면 &quot;서버 컴포넌트에서 클라이언트 기능을 쓰려고 하네?&quot;라며 에러를 뱉는 것입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;해결책: Providers 컴포넌트 분리&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해&lt;b&gt; 별도의 providers.tsx 파일&lt;/b&gt;을 만들고&lt;u&gt;&lt;b&gt; 'use client' 지시어를 추가&lt;/b&gt;&lt;/u&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 하면 &lt;b&gt;해당 컴포넌트&lt;/b&gt;와 &lt;b&gt;그 자식들만 클라이언트&lt;span style=&quot;color: #006dd7;&quot;&gt; 컴포넌트로 동작&lt;/span&gt;&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;구현 순서&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,0,0&quot;&gt;providers.tsx 생성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상단에 'use client' 지시어를 붙여 이 컴포넌트가 &lt;b&gt;클라이언트 사이드에서 동작함을 선언&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;13,1,0&quot;&gt;layout.tsx에서 주입&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버 컴포넌트인 레이아웃에서 위에서 만든 &lt;b&gt;Providers로 {children}을 감쌉니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◽&lt;i&gt;&lt;b&gt;app/providers.tsx&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bS7Bq8/dJMcai9U5FV/eIZkPwfjEuw71AKY3YYXN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bS7Bq8/dJMcai9U5FV/eIZkPwfjEuw71AKY3YYXN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bS7Bq8/dJMcai9U5FV/eIZkPwfjEuw71AKY3YYXN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbS7Bq8%2FdJMcai9U5FV%2FeIZkPwfjEuw71AKY3YYXN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;625&quot; height=&quot;375&quot; data-origin-width=&quot;625&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;◽&lt;i&gt;&lt;b&gt;app/ layout.tsx&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6POoO/dJMcabbV8BF/5tVOO81KHjM0HjGlQEWeh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6POoO/dJMcabbV8BF/5tVOO81KHjM0HjGlQEWeh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6POoO/dJMcabbV8BF/5tVOO81KHjM0HjGlQEWeh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6POoO%2FdJMcabbV8BF%2F5tVOO81KHjM0HjGlQEWeh0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;368&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;이 패턴의 장점&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 서버 컴포넌트의 이점 유지&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;layout.tsx 자체를&lt;b&gt; 'use client'&lt;/b&gt;로 바꿀 수도 있지만, 그렇게 되면 레이아웃과 그 하위의&lt;b&gt; 모든 컴포넌트가 서버 컴포넌트&lt;/b&gt;로서의 이점(SEO 최적화, 번들 사이즈 감소 등)을 잃게 됩니다.&lt;/li&gt;
&lt;li&gt;Providers로만&amp;nbsp; 감싸면, &lt;b data-index-in-node=&quot;133&quot; data-path-to-node=&quot;18&quot;&gt;레이아웃은 서버 컴포넌트로 남기면서 내부의 상태만 클라이언트에서 관리&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. Children은 서버 컴포넌트일 수 있다.&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;클라이언트 컴포넌트(Providers)의 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;children으로 전달되는 서버 컴포넌트&lt;/b&gt;&lt;/span&gt;는 여전히 &lt;u&gt;&lt;b&gt;서버 컴포넌트로 동작&lt;/b&gt;&lt;/u&gt;한다&quot;는 특성 덕분입니다.&lt;/li&gt;
&lt;li&gt;따라서 전체 페이지를 감싸더라도 각 페이지(page.tsx) 안의 로직들은 여전히 서버에서 빠르게 처리될 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt; 관심사의 분리&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전역 상태 관리 로직을 별도 파일로 분리하여 코드 가독성과 유지보수성이 향상됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt; 일관된 상태 유지 &lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전역 상태(Redux, React Query, Auth 등)는 &lt;b&gt;앱 전체에서 공유&lt;/b&gt;되어야 합니다.&lt;/li&gt;
&lt;li&gt;layout.tsx는 페이지가 바뀌어도 리렌더링되지 않고 &lt;b&gt;유지&lt;/b&gt;되는 특성이 있어, 이곳에 Provider를 배치하는 것이 상태를 유실하지 않는 가장 안정적인 방법입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;children은 어떻게 서버 컴포넌트로 유지될까❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;여기서 저는 한 가지 의문이 생겼습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Providers가 &lt;b&gt;클라이언트 컴포넌트('use client')&lt;/b&gt;라면, 그 안에 감싸진 자식들도 전부 클라이언트 컴포넌트가 되는 것 아닌가?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;결론부터 말하자면 이는 &quot;아니다&quot;라는게 맞습니다. 그 이유에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Composition Pattern이란?&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;React의 &lt;b&gt;Composition Pattern&lt;/b&gt;은 컴포넌트를 import해서 직접 사용하는 것과&lt;b&gt; props(children)로 전달받아 사용&lt;/b&gt;하는 것을 구분합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;Import 방식 (서버 -&amp;gt; 클라이언트 변환됨) ❌&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FyO5o/dJMcaaxlgdA/j9jzAi0iF6obibdOKKexg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FyO5o/dJMcaaxlgdA/j9jzAi0iF6obibdOKKexg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FyO5o/dJMcaaxlgdA/j9jzAi0iF6obibdOKKexg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFyO5o%2FdJMcaaxlgdA%2Fj9jzAi0iF6obibdOKKexg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;608&quot; height=&quot;274&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트 컴포넌트가 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;서버 컴포넌트&lt;/b&gt;&lt;/span&gt;를 &lt;b&gt;직접 import&lt;/b&gt;하면, &lt;u&gt;&lt;b&gt;서버 컴포넌트도 클라이언트 컴포넌트로 변환&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;Composition 방식 (서버 컴포넌트 유지) ✅&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;249&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c68hdF/dJMcagK6oMT/leKviZD3JWagi2lPQU8N3K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c68hdF/dJMcagK6oMT/leKviZD3JWagi2lPQU8N3K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c68hdF/dJMcagK6oMT/leKviZD3JWagi2lPQU8N3K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc68hdF%2FdJMcagK6oMT%2FleKviZD3JWagi2lPQU8N3K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;534&quot; height=&quot;203&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;249&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;263&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnNQi7/dJMcafemnR6/iLYMKcT3wG64aaSt9FoVSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnNQi7/dJMcafemnR6/iLYMKcT3wG64aaSt9FoVSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnNQi7/dJMcafemnR6/iLYMKcT3wG64aaSt9FoVSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnNQi7%2FdJMcafemnR6%2FiLYMKcT3wG64aaSt9FoVSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;518&quot; height=&quot;263&quot; data-origin-width=&quot;518&quot; data-origin-height=&quot;263&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 ServerComponent는 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;서버에서 먼저 렌더링&lt;/b&gt;&lt;/span&gt;되고, &lt;b&gt;그 결과가 ClientComponent에 props로 전달&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;왜 이런 차이가 생길까❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;◽Composition Pattern&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;서버&lt;/b&gt;: layout.tsx가 실행됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버&lt;/b&gt;: &amp;lt;ServerComponent /&amp;gt;가 렌더링됨 &amp;rarr; RSC Payload 생성&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버&lt;/b&gt;: 렌더링 결과를 children props로 전달&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라이언트&lt;/b&gt;: ClientComponent가 받은 children을 그대로 표시&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;◽Import Pattern&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트&lt;/b&gt;: ClientComponent가 실행됨&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라이언트&lt;/b&gt;: ServerComponent를 import했으므로 여기서 렌더링해야 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과&lt;/b&gt;: 서버 컴포넌트가 클라이언트에서 실행됨 (변환됨)&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;따라서, 클라이언트 컴포넌트(Providers)의 children으로 전달되는 서버 컴포넌트는 여전히 서버 컴포넌트로 동작합니다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;!-- Server 영역 --&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;layout.tsx&lt;/b&gt;를 Providers로 감싸는 패턴은 &lt;b&gt;Next.js App Router&lt;/b&gt;에서 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;서버&lt;/b&gt;&lt;/span&gt;와 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;클라이언트&lt;/span&gt;&lt;/b&gt;의 장점을 모두 살리는 핵심 패턴입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;b&gt;Composition Pattern&lt;/b&gt; 덕분에 전역 상태 관리와 서버 사이드 렌더링을 동시에 활용할 수 있고, 성능 최적화와 개발 경험 모두를 향상시킬 수 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Framework/Next.js</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/766</guid>
      <comments>https://pixx.tistory.com/766#entry766comment</comments>
      <pubDate>Tue, 27 Jan 2026 02:15:44 +0900</pubDate>
    </item>
    <item>
      <title>국내외 지도 API 비교해보기 (구글, 네이버, 카카오)</title>
      <link>https://pixx.tistory.com/765</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;map.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ortEZ/dJMcaa48T0F/3aRN5eL4TvwwdBbysKENzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ortEZ/dJMcaa48T0F/3aRN5eL4TvwwdBbysKENzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ortEZ/dJMcaa48T0F/3aRN5eL4TvwwdBbysKENzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FortEZ%2FdJMcaa48T0F%2F3aRN5eL4TvwwdBbysKENzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;map.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트를 하다보면 지도를 사용해야할 경우가 있습니다. 토이 프로젝트를 진행하면서 지도 API를 사용해야 했는데, 본 글에서는 여러 지도 API들을 비교하면서 각각의 특징과 장단점을 정리해보고자 합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 환경은 백엔드 Spring Boot, 프론트엔드 React + Next.js를 기준으로 작성했습니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;1. Google Maps API&lt;/h3&gt;
&lt;figure id=&quot;og_1769006305516&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Google Maps Platform - 3D 지도 및 지리 공간 분석&quot; data-og-description=&quot;상세한 지리 공간 데이터와 예측 가능한 가격으로 차량 공유 및 배송 서비스를 지원하세요. 이 모든 작업을 차량, 자산, 기기를 동적으로 추적하면서 수행할 수 있습니다.&quot; data-og-host=&quot;mapsplatform.google.com&quot; data-og-source-url=&quot;https://mapsplatform.google.com/&quot; data-og-url=&quot;https://mapsplatform.google.com/intl/ko_kr/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eTOwn/dJMb8PGqcbF/FyxPu9Dyk5NrpdPTPxaUk1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/gYA5a/dJMb8QL53D6/gOBWU0JZBS3O6gEEpqWz3k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ymevT/dJMb8QL53D7/bTrkaVtKabbwh9P9sXwDw1/img.png?width=1831&amp;amp;height=1831&amp;amp;face=0_0_1831_1831&quot;&gt;&lt;a href=&quot;https://mapsplatform.google.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mapsplatform.google.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eTOwn/dJMb8PGqcbF/FyxPu9Dyk5NrpdPTPxaUk1/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/gYA5a/dJMb8QL53D6/gOBWU0JZBS3O6gEEpqWz3k/img.png?width=1200&amp;amp;height=675&amp;amp;face=0_0_1200_675,https://scrap.kakaocdn.net/dn/ymevT/dJMb8QL53D7/bTrkaVtKabbwh9P9sXwDw1/img.png?width=1831&amp;amp;height=1831&amp;amp;face=0_0_1831_1831');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Google Maps Platform - 3D 지도 및 지리 공간 분석&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;상세한 지리 공간 데이터와 예측 가능한 가격으로 차량 공유 및 배송 서비스를 지원하세요. 이 모든 작업을 차량, 자산, 기기를 동적으로 추적하면서 수행할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mapsplatform.google.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Google Maps API&lt;/b&gt;는 전 세계에서 가장 널리 사용되는 지도 서비스입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 강력한 기능&lt;/b&gt;과 &lt;b&gt;방대한 데이터&lt;/b&gt;를 자랑하며, 글로벌 서비스 개발에 필수적인 선택지입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 전세계 커버리지&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;전 세계&lt;/b&gt; &lt;b&gt;거의 모든 지역&lt;/b&gt;의 지도 데이터 제공&lt;/li&gt;
&lt;li&gt;위성 이미지, 스트리트 뷰 등 다양한 뷰 옵션&lt;/li&gt;
&lt;li&gt;실시간 교통 정보, 대중교통 정보 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;풍부한 키능&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Places API: 장소 검색, 상세 정보, 리뷰 등&lt;/li&gt;
&lt;li&gt;Directions API: 경로 탐색 (자동차, 도보, 대중교통, 자전거)&lt;/li&gt;
&lt;li&gt;Geocoding API: 주소-좌표 변환&lt;/li&gt;
&lt;li&gt;Distance Matrix API: 여러 출발지-목적지 간 거리/시간 계산&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전세계 데이터 품질: 해외 지역 정보의 정확도와 최신성이 뛰어남&lt;/li&gt;
&lt;li&gt;안정적인 인프라: 구글의 강력한 서버 인프라로 다운타임이 거의 없음&lt;/li&gt;
&lt;li&gt;풍부한 레퍼런스: 전 세계적으로 사용되어 문제 해결이 쉬움&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;국내 지리 정보 한계: 한국 지도의 정확도가 네이버, 카카오 대비 떨어짐&lt;/li&gt;
&lt;li&gt;국내 길찾기 부정확: 한국 내 경로 탐색의 정확도가 낮음 (도로 상황 반영 미흡)&lt;/li&gt;
&lt;li&gt;가격 정책: 무료 크레딧 초과 시 비용이 빠르게 증가&lt;/li&gt;
&lt;li&gt;한글 문서 부족: 대부분의 문서가 영문으로 작성됨&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;2. Naver Map API&lt;/h3&gt;
&lt;figure id=&quot;og_1769006792968&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;NAVER CLOUD PLATFORM&quot; data-og-description=&quot;cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification&quot; data-og-host=&quot;www.ncloud.com&quot; data-og-source-url=&quot;https://www.ncloud.com/v2/product/applicationService/maps&quot; data-og-url=&quot;https://www.ncloud.com&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bh847e/dJMb9b3L8Tc/KH3gaoHqSmz3U0I0vOXas0/img.jpg?width=526&amp;amp;height=274&amp;amp;face=0_0_526_274,https://scrap.kakaocdn.net/dn/iYtm0/dJMb9iaLcpK/fCWBBbO91FVLqv7eL2rVJk/img.png?width=826&amp;amp;height=826&amp;amp;face=0_0_826_826,https://scrap.kakaocdn.net/dn/flTX3/dJMb9iIBbGr/YGkAncV1s34eozW6PqPsAk/img.png?width=826&amp;amp;height=826&amp;amp;face=0_0_826_826&quot;&gt;&lt;a href=&quot;https://www.ncloud.com/v2/product/applicationService/maps&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.ncloud.com/v2/product/applicationService/maps&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bh847e/dJMb9b3L8Tc/KH3gaoHqSmz3U0I0vOXas0/img.jpg?width=526&amp;amp;height=274&amp;amp;face=0_0_526_274,https://scrap.kakaocdn.net/dn/iYtm0/dJMb9iaLcpK/fCWBBbO91FVLqv7eL2rVJk/img.png?width=826&amp;amp;height=826&amp;amp;face=0_0_826_826,https://scrap.kakaocdn.net/dn/flTX3/dJMb9iIBbGr/YGkAncV1s34eozW6PqPsAk/img.png?width=826&amp;amp;height=826&amp;amp;face=0_0_826_826');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;NAVER CLOUD PLATFORM&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;cloud computing services for corporations, IaaS, PaaS, SaaS, with Global region and Security Technology Certification&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.ncloud.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 네이버 지도 API&lt;/b&gt;는 &lt;b&gt;국내에서 가장 정확&lt;/b&gt;하고 &lt;b&gt;상세한 지도 데이터를 제공&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 가장 많이 사용하는 API이며, &lt;b&gt;한국 서비스 개발에 최적화&lt;/b&gt;되어 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt; 국내 최고 수준의 정확&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한국 지역 도로, 건물, 지형 정보의 정확도가 매우 높음&lt;/li&gt;
&lt;li&gt;실시간 교통 정보 (네이버만의 강점)&lt;/li&gt;
&lt;li&gt;최신 건물 및 도로 정보 빠른 반영&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt; 개발자 친화적 &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한글로 작성된 상세한 문서&lt;/li&gt;
&lt;li&gt;다양한 예제 코드 제공&lt;/li&gt;
&lt;li&gt;빠른 기술 지원 &lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;국내 데이터 압도적 정확도&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;훌륭한 문서화&lt;/b&gt;: docs가 정말 자세하게 되어 있어 개발이 편함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;넉넉한 무료 한도&lt;/b&gt;: 월 10,000,000건 무료 (대부분의 프로젝트에 충분)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실시간 교통 정보&lt;/b&gt;: 네이버만의 차별화된 강점&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지도 커스터마이징&lt;/b&gt;: 다양한 스타일과 옵션 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;키워드 검색 불가&lt;/b&gt;: 장소 검색 시 주소로만 검색 가능 (키워드 검색 불가)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해외 데이터 제한&lt;/b&gt;: 해외 지역 정보는 구글 대비 부족&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;3. Kakao Map API&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://apis.map.kakao.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://apis.map.kakao.com/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오 지도 API는 &lt;b&gt;강력한 장소 검색 기능&lt;/b&gt;으로 유명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오의 방대한&lt;b&gt; POI(Point of Interest) 데이터&lt;/b&gt;를 활용할 수 있어, &lt;u&gt;&lt;b&gt;장소 기반 서비스에 최적&lt;/b&gt;&lt;/u&gt;입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt;&lt;span&gt; 강력한 장소 검색 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;키워드 검색 API 제공 (네이버와의 가장 큰 차이점)&lt;/li&gt;
&lt;li&gt;카테고리별 장소 검색&lt;/li&gt;
&lt;li&gt;카카오플레이스 데이터 연동&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&lt;span&gt; 카카오 생태계 통합 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;카카오톡 공유 기능 연동&lt;/li&gt;
&lt;li&gt;카카오내비 연동&lt;/li&gt;
&lt;li&gt;카카오모빌리티 데이터 활용&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;키워드 검색 강력&lt;/b&gt;: &quot;강남역 카페&quot;, &quot;근처 편의점&quot; 같은 자연어 검색 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;풍부한 POI 데이터&lt;/b&gt;: 카카오플레이스의 방대한 장소 정보&lt;/li&gt;
&lt;li&gt;&lt;b&gt;카카오 생태계&lt;/b&gt;: 카카오톡, 카카오내비와의 자연스러운 연동&lt;/li&gt;
&lt;li&gt;&lt;b&gt;직관적인 API&lt;/b&gt;: 사용하기 쉬운 RESTful API 구조&lt;/li&gt;
&lt;li&gt;&lt;b&gt;장소 상세 정보&lt;/b&gt;: 영업시간, 리뷰, 사진 등 풍부한 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;일일 쿼터 제한&lt;/b&gt;: 1일 300,000건으로 네이버 대비 적음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해외 데이터&lt;/b&gt;: 해외 지역 정보는 제한적&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;4. OSM (OpenStreetMap)&lt;/h3&gt;
&lt;figure id=&quot;og_1769007109427&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;오픈스트리트맵 이용하기&quot; data-og-description=&quot;전 세계의 지리공간 정보를 날것 그대로 보고, 원하는 대로 조작하고, 복잡한 저작권 문제 없이 (&amp;lsquo;ⓒOpenStreetMap 기여자&amp;rsquo;만 적어서) 배포하는 것은 오픈스트리트맵만의 특권입니다.&quot; data-og-host=&quot;osm.kr&quot; data-og-source-url=&quot;https://osm.kr/usage/&quot; data-og-url=&quot;https://osm.kr/usage/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bcmH6L/dJMb85vITbV/tzTkoQxWNtiSlvRl1a2crk/img.png?width=2350&amp;amp;height=910&amp;amp;face=0_0_2350_910,https://scrap.kakaocdn.net/dn/5qkW4/dJMb86OVQPh/A0mKVMCZkS7AqSBvCjmcMK/img.png?width=2350&amp;amp;height=910&amp;amp;face=0_0_2350_910&quot;&gt;&lt;a href=&quot;https://osm.kr/usage/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://osm.kr/usage/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bcmH6L/dJMb85vITbV/tzTkoQxWNtiSlvRl1a2crk/img.png?width=2350&amp;amp;height=910&amp;amp;face=0_0_2350_910,https://scrap.kakaocdn.net/dn/5qkW4/dJMb86OVQPh/A0mKVMCZkS7AqSBvCjmcMK/img.png?width=2350&amp;amp;height=910&amp;amp;face=0_0_2350_910');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;오픈스트리트맵 이용하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;전 세계의 지리공간 정보를 날것 그대로 보고, 원하는 대로 조작하고, 복잡한 저작권 문제 없이 (&amp;lsquo;ⓒOpenStreetMap 기여자&amp;rsquo;만 적어서) 배포하는 것은 오픈스트리트맵만의 특권입니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;osm.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;OpenStreetMap&lt;/b&gt;은 &lt;b&gt;오픈소스 기반의 무료 지도 서비스&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뮤니티가 직접 데이터를 만들고 관리하며, &lt;b&gt;완전히 무료&lt;/b&gt;로 사용할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; 오픈소스 기반 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전 무료 사용 (상업적 이용 포함)&lt;/li&gt;
&lt;li&gt;데이터 직접 수정 및 기여 가능&lt;/li&gt;
&lt;li&gt;다양한 오픈소스 라이브러리 활용 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; OSRM (Open Source Routing Machine) 연동 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무료 길찾기 기능&lt;/li&gt;
&lt;li&gt;거리 행렬 계산&lt;/li&gt;
&lt;li&gt;경로 최적화&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;완전 무료&lt;/b&gt;: 사용량 제한 없이 무료&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오픈소스&lt;/b&gt;: 코드와 데이터를 자유롭게 사용 및 수정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 기여&lt;/b&gt;: 직접 지도 데이터를 수정하고 개선 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;라이선스 자유&lt;/b&gt;: 상업적 이용에도 제약이 거의 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;국내 정확도&lt;/b&gt;: 상용 서비스 대비 데이터 정확도가 낮음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 최신성&lt;/b&gt;: 실시간 업데이트가 느림&lt;/li&gt;
&lt;li&gt;&lt;b&gt;안정성&lt;/b&gt;: 자체 서버 구축 필요 시 인프라 관리 부담&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기능 제한&lt;/b&gt;: 상용 API만큼 다양한 기능 제공 어려움&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한글 지원&lt;/b&gt;: 한글 문서와 지원이 부족&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;5. Mapbox API&lt;/h3&gt;
&lt;figure id=&quot;og_1769007231511&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Mapbox | Maps, Navigation, Search, and Data&quot; data-og-description=&quot;APIs and SDKs for AI-powered maps, location search, turn-by-turn navigation, and geospatial data in mobile or web apps. Get started for free.&quot; data-og-host=&quot;www.mapbox.com&quot; data-og-source-url=&quot;https://www.mapbox.com/&quot; data-og-url=&quot;https://www.mapbox.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ce1YJY/dJMb85WNhSU/2NDorOblgZXm5D3f05a8m0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bh9XlZ/dJMb86nRzmZ/OiQJzTF0HNnPSD1JL2HZM0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/t2YFv/dJMb87NQl6H/DhMntzaIhub2fm6u5ZCzu0/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260&quot;&gt;&lt;a href=&quot;https://www.mapbox.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.mapbox.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ce1YJY/dJMb85WNhSU/2NDorOblgZXm5D3f05a8m0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/bh9XlZ/dJMb86nRzmZ/OiQJzTF0HNnPSD1JL2HZM0/img.jpg?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/t2YFv/dJMb87NQl6H/DhMntzaIhub2fm6u5ZCzu0/img.jpg?width=2400&amp;amp;height=1260&amp;amp;face=0_0_2400_1260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Mapbox | Maps, Navigation, Search, and Data&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;APIs and SDKs for AI-powered maps, location search, turn-by-turn navigation, and geospatial data in mobile or web apps. Get started for free.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.mapbox.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mapbox는 &lt;b&gt;데이터 시각화&lt;/b&gt;와 &lt;b&gt;커스터마이징&lt;/b&gt;에 특화된 지도 서비스입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;다양한 테마&lt;/b&gt;의 &lt;b&gt;지도 디자인&lt;/b&gt;이 필요한 경우 최고의 선택입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style1&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;강력한 커스터마이&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Mapbox Studio를 통한 직관적인 스타일 편집&lt;/li&gt;
&lt;li&gt;실시간 데이터 시각화&lt;/li&gt;
&lt;li&gt;3D 지형, 건물 렌더링&lt;/li&gt;
&lt;li&gt;애니메이션 효과&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터 시각&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;히트맵, 클러스터링&lt;/li&gt;
&lt;li&gt;대용량 데이터 처리&lt;/li&gt;
&lt;li&gt;실시간 데이터 업데이트&lt;/li&gt;
&lt;li&gt;벡터 타일 기반 렌더링&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;최고 수준의 커스터마이징&lt;/b&gt;: 지도 스타일을 완전히 자유롭게 변경 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 시각화&lt;/b&gt;: 복잡한 데이터를 아름답게 표현&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능&lt;/b&gt;: 벡터 타일 기반으로 빠른 로딩과 부드러운 인터랙션&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3D 지원&lt;/b&gt;: 3D 건물, 지형 표현 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발자 경험&lt;/b&gt;: 잘 설계된 API와 풍부한 문서&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;text-align: left;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;국내 데이터 제한&lt;/b&gt;: 한국 지역 상세 정보 부족&lt;/li&gt;
&lt;li&gt;&lt;b&gt;높은 비용&lt;/b&gt;: 무료 티어 이후 비용이 높은 편&lt;/li&gt;
&lt;li&gt;&lt;b&gt;러닝 커브&lt;/b&gt;: 고급 기능 사용 시 학습 시간 필요&lt;/li&gt;
&lt;li&gt;&lt;b&gt;한글 지원&lt;/b&gt;: 한글 문서 부족&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;어떤 API를 선택해야할까❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 제가 실제로 프로젝트를 진행하며 경험한 내용을 바탕으로 작성한 &lt;b&gt;개인적인 의견&lt;/b&gt;입니다. 정답이 있는 것이 아니며, 프로젝트의 특성과 요구사항에 따라 최적의 선택은 달라질 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;프로젝트 상황별 추천&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;◽비용이 가장 중요하다면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;OSM (OpenStreetMap)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전 무료로 사용할 수 있어 초기 스타트업이나 토이 프로젝트에 적합합니다.&lt;/li&gt;
&lt;li&gt;다만 개발 리소스와 시간 투자가 필요하다는 점을 고려해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;◽  국내 서비스를 개발한다면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;Naver Map API&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;제가 가장 많이 사용하는 선택입니다.&lt;/li&gt;
&lt;li&gt;국내 데이터 정확도가 압도적이고, 한글 문서가 잘 되어 있어 개발 속도가 빠릅니다.&lt;/li&gt;
&lt;li&gt;월 1천만 건의 넉넉한 무료 한도도 큰 장점입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;◽장소 검색이 핵심 기능이라면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;Kakao Map API&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;강남역 맛집&quot;, &quot;근처 카페&quot; 같은 키워드 검색이 필요하다면 카카오가 최선의 선택입니다.&lt;/li&gt;
&lt;li&gt;네이버는 주소 기반 검색만 지원하므로 장소 검색 기능에서는 카카오를 따라갈 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;◽ 글로벌 서비스를 개발한다면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;Google Maps API&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;해외 지역 정보가 필요하다면 구글 외에는 대안이 없습니다.&lt;/li&gt;
&lt;li&gt;전 세계 데이터 품질과 안정성은 구글이 압도적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;◽데이터 시각화가 중요하다면&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;rarr; &lt;b&gt;Mapbox API&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대시보드나 분석 툴처럼 데이터를 지도 위에 시각화해야 한다면 Mapbox의 강력한 커스터마이징 기능이 빛을 발합니다.&lt;/li&gt;
&lt;li&gt;3D 표현이나 독특한 스타일이 필요한 경우에도 최적입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;</description>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/765</guid>
      <comments>https://pixx.tistory.com/765#entry765comment</comments>
      <pubDate>Thu, 22 Jan 2026 00:05:17 +0900</pubDate>
    </item>
    <item>
      <title>[Spring boot] 우리가 보낸 객체는 어떻게 서버까지 흘러갈까? (직렬화와 역직렬화)</title>
      <link>https://pixx.tistory.com/764</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1AqzH%2FbtsMyTT86M1%2FV8DfRaXFjDMumvvn5knww0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;163&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;웹 개발을 하다 보면 프론트엔드에서 서버로 데이터를 보내고 받는 일이 일상적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt; 그런데 우리가 JavaScript 객체로 다루던 데이터가 어떻게 서버까지 전달되고, 다시 객체로 돌아오는 걸까요? 이 과정의 핵심에는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;직렬화(Serialization)&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;와&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;역직렬화(Deserialization)&lt;/b&gt;라는 개념이 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 직렬화의 필요성과 어떻게 직렬화가 되는지에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;프론트엔드에서의 객체 관리&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;프론트엔드에서의 객체 관리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프론트엔드에서는 HTTP 요청을 다음과 같이 객체 형태로 관리합니다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;const httpRequestMessage = {
    headers: {
        'Content-Type': 'application/json',
        'Content-Length': 20,
        'Accept': '*/*'
    },
    body: {
        userId: &quot;abc&quot;,
        password: &quot;1234&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 요청을 보낼 때는 &lt;b&gt;axios&lt;/b&gt; 같은 라이브러리를 사용해 간단하게 처리합니다.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;await axios.post(`${BASE_URL}/auth/signup`, {
    userId: &quot;abc&quot;,
    password: &quot;1234&quot;
});&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;네트워크를 통한 전송 : 문자열로의 변환&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 &lt;b&gt;실제로 서버로 요청&lt;/b&gt;이 전송될 때는 다음과 같은 &lt;b&gt;문자열 형태&lt;/b&gt;로 변환됩니다.&lt;/p&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;POST /auth/signup HTTP/1.1
Content-Type: application/json
Content-Length: 20

{&quot;userId&quot;: &quot;abc&quot;, &quot;password&quot;: &quot;1234&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;왜 문자열로 변환해야 할까요❓&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;네트워크를 통해 데이터를 전송하려면 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;반드시 연속된 바이트 스트림(문자열)&lt;/b&gt;&lt;/span&gt;이어야 하기 때문입니다. &lt;b&gt;객체 형태&lt;/b&gt;는 &lt;b&gt;개발자가 조작&lt;/b&gt;하기 편하도록 만든 &lt;b&gt;추상화&lt;/b&gt;일 뿐, &lt;u&gt;&lt;b&gt;실제 전송 시에는 문자열로 변환&lt;/b&gt;&lt;/u&gt;되어야 합니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;객체를 그대로 보낼 수 없는 이유&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&amp;nbsp;메모리 구조의 이해&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;RAM은 거대한 배열&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;JavaScript에서 &lt;b&gt;객체를 생성&lt;/b&gt;하면 이는 &lt;b&gt;메모리 상&lt;/b&gt;에 다음과 같이 흩어져 저장됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;groovy&quot;&gt;&lt;code&gt;스택: httpRequestMessage &amp;rarr; 주소 1000
힙(1000): { headers: 주소 2000, body: 주소 3000 }
힙(2000): { 'Content-Type': 'application/json', ... }
힙(3000): { userId: &quot;abc&quot;, password: &quot;1234&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체의 실제 데이터는 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;힙(Heap) 영역 곳곳&lt;/b&gt;&lt;/span&gt;에 흩어져 있고, &lt;b&gt;각각은 메모리 주소로 참조&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주소를 보내면 안 되는 이유&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;code&gt;httpRequestMessage&lt;/code&gt;의 주소(예: &lt;b&gt;1000&lt;/b&gt;)를 &lt;b&gt;그대로 네트워크를 통해 서버&lt;/b&gt;로 보낸다면 어떻게 될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;서버&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;자신의 메모리 주소 1000번지를 참조&lt;/b&gt;&lt;/u&gt;하게 되고, 이는 브라우저가 보낸 데이터와는 &lt;b&gt;전혀 다른 데이터&lt;/b&gt;입니다. 각 컴퓨터는 독립적인 메모리 공간을 가지고 있기 때문에, &lt;b&gt;메모리 주소는 해당 프로세스 내에서만 의미&lt;/b&gt;가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론적으로,&lt;/b&gt;&amp;nbsp;메모리 상에 흩어져 있는 데이터를 모두 모아서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하나의 연속된 문자열&lt;/b&gt;&lt;/span&gt;로 만들어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;직렬화 &amp;amp; 역직렬화&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;직렬화 : 객체를 문자열로&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직렬화는 메모리 상에 흩어져 있는 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;객체&lt;/b&gt;&lt;/span&gt;를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;일렬로 나열된 문자열&lt;/b&gt;&lt;/span&gt;로 변환하는 과정입니다.&lt;/p&gt;
&lt;pre class=&quot;haskell&quot;&gt;&lt;code&gt;// 객체 (메모리 여기저기 흩어져 있음)
const data = { userId: &quot;abc&quot;, password: &quot;1234&quot; };

// 직렬화 (연속된 문자열)
const serialized = JSON.stringify(data);
// '{&quot;userId&quot;:&quot;abc&quot;,&quot;password&quot;:&quot;1234&quot;}'&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문자열은 결국 &lt;b&gt;2진수의 연속체(바이트열)&lt;/b&gt;로 변환되어 네트워크를 통해 전송됩니다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;01010000 01001111 01010011 01010100 00100000 00101111 ...
P        O        S        T        (space)  /        ...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;405&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xBkot/dJMcag5jUkV/xqdajSrqHldKxkSXfGoSQk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xBkot/dJMcag5jUkV/xqdajSrqHldKxkSXfGoSQk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xBkot/dJMcag5jUkV/xqdajSrqHldKxkSXfGoSQk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxBkot%2FdJMcag5jUkV%2FxqdajSrqHldKxkSXfGoSQk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;737&quot; height=&quot;257&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;405&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림에서 볼 수 있듯이 Binary Encoder를 하면 &lt;u&gt;&lt;b&gt;문자열은 2진수의 연속체&lt;/b&gt;&lt;/u&gt;인것을 알 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;역직렬화 :&lt;span&gt;&amp;nbsp;문자열을 다시 객체로&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에서는 받은 &lt;b&gt;바이트열을 먼저 문자열로 복원&lt;/b&gt;하고, 이를 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;다시 객체로 변환&lt;/b&gt;&lt;/span&gt;합니다. 이것이 바로 &lt;b&gt;역직렬화&lt;/b&gt;입니다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;// 서버에서 받은 문자열
const received = '{&quot;userId&quot;:&quot;abc&quot;,&quot;password&quot;:&quot;1234&quot;}';

// 역직렬화 (다시 객체로)
const data = JSON.parse(received);
// { userId: &quot;abc&quot;, password: &quot;1234&quot; }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역직렬화를 통해 연속된 바이트열을 다시 메모리의 힙 영역 곳곳에 퍼트려 &lt;b&gt;객체 구조를 복원&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;객체로 다루지 않으면 어떻게 될까❓&lt;/h3&gt;
&lt;pre class=&quot;oxygene&quot;&gt;&lt;code&gt;// 이런 식으로 파싱해야 합니다
const rawString = 'POST /auth/signup HTTP/1.1\nContent-Type: application/json\n\n{&quot;userId&quot;:&quot;abc&quot;}';

// HTTP 메서드 추출
const method = rawString.slice(0, rawString.indexOf(' '));

// URL 추출
const urlStart = rawString.indexOf(' ') + 1;
const urlEnd = rawString.indexOf(' ', urlStart);
const url = rawString.slice(urlStart, urlEnd);

// 헤더 파싱
const headerSection = rawString.slice(rawString.indexOf('\n') + 1, rawString.indexOf('\n\n'));
// ... 계속 문자열 조작&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 C언어에서 네트워크 프로토콜을 다루는 것처럼 매우 번거롭습니다. 반면 객체로 다루면 다음과 같이 간단하게 데이터에 접근 할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;httpRequestMessage.headers['Content-Type']&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;직렬화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리 상에 흩어져 있는 객체를 연속된 &lt;b&gt;문자열(바이트열)로 변환&lt;/b&gt;하는 과정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체 ➡️ 문자열&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;역직렬화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연속된 문자열(바이트열)을 다시 메모리 상의 &lt;b&gt;객체로 복원&lt;/b&gt;하는 과정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문자열 ➡️ 객체&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면, 네트워크 통신에서 직렬화와 역직렬화가 필요한 이유는 다음과 같습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;네트워크는 연속된 &lt;b&gt;바이트 스트림만 전송&lt;/b&gt;할 수 있습니다&lt;/li&gt;
&lt;li&gt;메모리 주소는 각 프로세스마다 독립적이어서 &lt;s&gt;&lt;b&gt;그대로 전송&lt;/b&gt;&lt;/s&gt;할 수 없습니다&lt;/li&gt;
&lt;li&gt;개발자는 &lt;b&gt;객체 형태로 데이터를 다루는 것이 훨씬 편리&lt;/b&gt;합니다&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 직렬화와 역직렬화는 &lt;b&gt;개발 편의성&lt;/b&gt;과 &lt;b&gt;네트워크 전송 요구사항&lt;/b&gt; 사이의 완벽한 타협점인 셈입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;예시 코드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 실제로 클라이언트에서 보낸 데이터가 서버에서 어떻게 받고, 어떻게 직렬화,역직렬화가 되는 지 코드로 살펴보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1768297100316&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package com.example.serialization.controller;

import com.example.serialization.dto.SignupRequest;
import com.example.serialization.dto.SignupResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Arrays;

@RestController
@RequestMapping(&quot;/auth&quot;)
public class AuthController {

    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * [POST] 직렬화(Serialization) 과정 확인
     * 클라이언트가 보낸 데이터가 어떻게 이진수 연속체로 변하는지 보여줍니다.
     */
    @PostMapping(&quot;/signup&quot;)
    public void showSerialization(@RequestBody SignupRequest request,
                                  @RequestHeader(value = &quot;Content-Type&quot;) String contentType) throws Exception {

        String jsonBody = objectMapper.writeValueAsString(request);
        String rawHttpRequest = &quot;POST /auth/signup HTTP/1.1\n&quot; +
                &quot;Content-Type : &quot; + contentType + &quot;\n\n&quot; +
                jsonBody;

        byte[] bytes = rawHttpRequest.getBytes(StandardCharsets.UTF_8);
        StringBuilder binaryStream = new StringBuilder();
        for (byte b : bytes) {
            binaryStream.append(String.format(&quot;%8s&quot;, Integer.toBinaryString(b &amp;amp; 0xFF)).replace(' ', '0'));
        }

        System.out.println(&quot;\n[클라이언트에서 보낸 데이터 (Raw 문자열)]&quot;);
        System.out.println(rawHttpRequest);

        System.out.println(&quot;\n[서버가 수신한 데이터 (직렬화된 이진수 연속체)]&quot;);
        System.out.println(binaryStream.toString());

        System.out.println( );
    }

    /**
     * [GET] 역직렬화(Deserialization) 과정 확인
     * 수신한 문자열이 어떻게 다시 Java 객체로 복원되는지 보여줍니다.
     */
    @GetMapping(&quot;/user-info&quot;)
    public void showDeserialization() throws Exception {
        // 서버가 수신한 데이터라고 가정 (Raw 문자열)
        String receivedRaw = &quot;{\&quot;userId\&quot;:\&quot;testUser\&quot;,\&quot;password\&quot;:\&quot;password123\&quot;}&quot;;

        // 역직렬화 진행 (문자열 -&amp;gt; 객체)
        SignupRequest restoredObj = objectMapper.readValue(receivedRaw, SignupRequest.class);

        System.out.println(&quot;\n[서버가 수신한 데이터 (Raw 문자열)]&quot;);
        System.out.println(receivedRaw);

        System.out.println(&quot;\n[역직렬화된 후 객체 (Java Object)]&quot;);
        System.out.println(&quot;객체 정보: &quot; + restoredObj);

    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 데이터의 출발: 클라이언트에서의 직렬화&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클라이언트가&lt;/b&gt; &lt;b&gt;객체를 전송&lt;/b&gt;하면, 네트워크를 타고 가기 위해 데이터는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;이진수(Binary)&lt;/b&gt;&lt;/span&gt;의 형태로 바뀝니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caMZYw/dJMcacaLAOe/kF1khaVo7upyIk0i8AeKsK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caMZYw/dJMcacaLAOe/kF1khaVo7upyIk0i8AeKsK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caMZYw/dJMcacaLAOe/kF1khaVo7upyIk0i8AeKsK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcaMZYw%2FdJMcacaLAOe%2FkF1khaVo7upyIk0i8AeKsK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;64&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 로그를 보면 알 수 있듯이, 클라이언트에서 보낸 &lt;b&gt;객체&lt;/b&gt;는 서버에 도착할 때 &lt;b&gt;&lt;s&gt;우리가 읽을 수 없는&lt;/s&gt;&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b data-index-in-node=&quot;55&quot; data-path-to-node=&quot;5,2&quot;&gt;바이트(이진수) 문자열&lt;/b&gt;&lt;/span&gt;로 보내진 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터는 오직 이 '0'과 '1'의 조합만을 이해하며 데이터를 주고받습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 텍스트로의 변환 (JSON)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1768299027541&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;01010000010011110101001101010100001000000010111101100001011101010111010001101000001011110111001101101001011001110110111001110101011100000010000001001000010101000101010001010000001011110011000100101110001100010000101001000011011011110110111001110100011001010110111001110100001011010101010001111001011100000110010100100000001110100010000001100001011100000111000001101100011010010110001101100001011101000110100101101111011011100010111101101010011100110110111101101110000010100000101001111011001000100111010101110011011001010111001001001001011001000010001000111010001000100111010001100101011100110111010001010101011100110110010101110010001000100010110000100010011100000110000101110011011100110111011101101111011100100110010000100010001110100010001001110000011000010111001101110011011101110110111101110010011001000011000100110010001100110010001001111101&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 바이트 문자열은 위와 같습니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cjO7kF/dJMcadHtrLv/WvKRYXIKRdiWlWWwUlEYc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cjO7kF/dJMcadHtrLv/WvKRYXIKRdiWlWWwUlEYc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cjO7kF/dJMcadHtrLv/WvKRYXIKRdiWlWWwUlEYc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcjO7kF%2FdJMcadHtrLv%2FWvKRYXIKRdiWlWWwUlEYc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;725&quot; height=&quot;263&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버는 수신한 이진 데이터를 설정된 &lt;b&gt;인코딩(UTF-8)&lt;/b&gt;에 맞춰 우리가 읽을 수 있는 &lt;b&gt;텍스트로 해석&lt;/b&gt;합니다. 이것이 바로 &lt;b&gt;HTTP Body&lt;/b&gt;에 담긴 &lt;u&gt;&lt;b&gt;JSON 문자열&lt;/b&gt;&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;120&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RJSoq/dJMcaiPxA2u/392H1XA6Bhk24OGZ1oFSHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RJSoq/dJMcaiPxA2u/392H1XA6Bhk24OGZ1oFSHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RJSoq/dJMcaiPxA2u/392H1XA6Bhk24OGZ1oFSHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRJSoq%2FdJMcaiPxA2u%2F392H1XA6Bhk24OGZ1oFSHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;375&quot; height=&quot;120&quot; data-origin-width=&quot;375&quot; data-origin-height=&quot;120&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;바이트&amp;nbsp;데이터&lt;/b&gt;&lt;/span&gt;를&amp;nbsp;&lt;b&gt;문자열로&amp;nbsp;변환&lt;/b&gt;하니,&amp;nbsp;이제야&amp;nbsp;비로소&amp;nbsp;우리가&amp;nbsp;의도했던&amp;nbsp;&lt;b&gt;데이터의&amp;nbsp;형태&lt;/b&gt;가&amp;nbsp;보이기&amp;nbsp;시작합니다.&amp;nbsp;하지만&amp;nbsp;아직은&amp;nbsp;단순한&amp;nbsp;'글자'일&amp;nbsp;뿐,&amp;nbsp;자바가&amp;nbsp;다룰&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;&lt;s&gt;&lt;b&gt;'객체'&lt;/b&gt;&lt;/s&gt;는&amp;nbsp;아닙니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3.&lt;span&gt; 서버에서의 역직렬화 (Java Object)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 Spring의 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;ObjectMapper&lt;/b&gt;&lt;/span&gt;가 이 &lt;b&gt;JSON 문자열을 분석&lt;/b&gt;하여 실제 자바 클래스인 &lt;b&gt;SignupRequest 객체에 값을 채워넣습니다.&lt;/b&gt; 이 과정을 &lt;b&gt;역직렬화(Deserialization)&lt;/b&gt;라고 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;63&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lvuDf/dJMcafL54d9/CwdhkpBdylkAQPcKBsKA8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lvuDf/dJMcafL54d9/CwdhkpBdylkAQPcKBsKA8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lvuDf/dJMcafL54d9/CwdhkpBdylkAQPcKBsKA8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlvuDf%2FdJMcafL54d9%2FCwdhkpBdylkAQPcKBsKA8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;509&quot; height=&quot;63&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;63&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보시다시피 최종적으로는 &lt;b&gt;클라이언트가 보낸 데이터&lt;/b&gt;가 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자바 객체 형태로 복원&lt;/b&gt;&lt;/span&gt;된 것을 알 수 있습니다. 이제 개발자는 request.getUserId()와 같은 메서드를 통해 데이터를 자유롭게 사용할 수 있게 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Boot는 내부적으로 &lt;b data-index-in-node=&quot;20&quot; data-path-to-node=&quot;8,0&quot;&gt;Jackson&lt;/b&gt;이라는 강력한 라이브러리를 사용하여 이 복잡한 과정을 처리합니다. 덕분에 우리는 바이트 단위의 데이터를 고민할 필요 없이 @RequestBody 어노테이션 하나로 편리하게 &lt;b&gt;객체&lt;/b&gt;를 받아볼 수 있는 것입니다.&lt;/p&gt;</description>
      <category>Framework/Spring\Spring boot</category>
      <category>Jackson</category>
      <category>ObjectMapper</category>
      <category>역직렬화</category>
      <category>직렬화</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/764</guid>
      <comments>https://pixx.tistory.com/764#entry764comment</comments>
      <pubDate>Tue, 13 Jan 2026 19:21:30 +0900</pubDate>
    </item>
    <item>
      <title>[Prometheus] 시계열 데이터 분석을 위한 Prometheus Query(promQL) 이해하기</title>
      <link>https://pixx.tistory.com/763</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/erxnNg/btsI7IhsBV2/etI7YN9kw84FbGI2xVkM4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/erxnNg/btsI7IhsBV2/etI7YN9kw84FbGI2xVkM4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/erxnNg/btsI7IhsBV2/etI7YN9kw84FbGI2xVkM4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FerxnNg%2FbtsI7IhsBV2%2FetI7YN9kw84FbGI2xVkM4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;336&quot; height=&quot;150&quot; data-origin-width=&quot;336&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;회사에서 모니터링 프로젝트를 하던 중 추이 분석 관련 그래프, 언제 트래픽이 있었는지 등 시계열 데이터를 조회하고 분석해야하는 상황이 있었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;저희 프로젝트는 sql-exporter를 사용해서 메트릭 데이터를 프로메테우스에 저장하고있어 이 메트릭 데이터를 효과적으로 질의할 수 있어야했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이때 활용했던 방법이 PromQL인데, 이번 글에서는 PromQL란 무엇인지, 주요 용도, 주요 사용되는 내장 함수 등을 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;PromQL (Prometheus Query Language)이란❓&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;PromQL이란?&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Prometheus&lt;/b&gt; 모니터링 시스템에서 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시계열 데이터&lt;/b&gt;&lt;/span&gt;를 &lt;b&gt;조회&lt;/b&gt;하고 &lt;b&gt;분석&lt;/b&gt;하기 위한 &lt;b&gt;전용 쿼리 언어&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SQL과 유사&lt;/b&gt;하게 &lt;b&gt;데이터를 질의&lt;/b&gt;하지만, &lt;u&gt;&lt;b&gt;시계열 데이터에 특화&lt;/b&gt;&lt;/u&gt;되어 있어 &lt;u&gt;&lt;b&gt;시간의 흐름에 따른 메트릭 변화&lt;/b&gt;&lt;/u&gt;를 효과적으로 분석할 수 있습니다.&lt;/li&gt;
&lt;li&gt;즉, &lt;span style=&quot;background-color: #ffffff; color: #242424; text-align: start;&quot;&gt;Promethues에서는&lt;b&gt; PromQL&lt;/b&gt;을 이용해서 &lt;b&gt;TSDB(Time Series Database)를 제어&lt;/b&gt;할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;데이터 구조&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Prometheus는 데이터를 저장할 때 다음과 같은 형식을 사용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1768116714845&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;metric_name{label1 = &quot;value1&quot;, label2 = &quot;value2&quot;,...}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,0&quot;&gt;메트릭 이름(Metric Name)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;측정하려는 값의&lt;b&gt; 본질&lt;/b&gt; (예: cpu_usage - 전체 CPU 사용량)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;레이블(Labels)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그 값의 &lt;b&gt;구체적인 속성&lt;/b&gt; (예: method=&quot;GET&quot;, status=&quot;200&quot;, instance=&quot;server-01&quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;레이블을 활용한 실제 예시&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;만약 웹 서버의 에러율을 분석하고 싶다면, 레이블을 통해 다음과 같이 필터링하거나 그룹화할 수 있습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 88px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 16.7053%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt;사용 목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.2404%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt;PromQL 예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.0542%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt;설명&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 16.7053%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt;특정 데이터 필터링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.2404%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt; http_requests_total{status=&quot;500&quot;} &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.0542%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt; 상태 코드가 500(에러)인 데이터만 골라냅니다. &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 16.7053%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt;다중 조건 필터링&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.2404%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt; http_requests_total{method=&quot;POST&quot;, env=&quot;prod&quot;} &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.0542%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt; 운영 환경(prod)이면서 POST 방식인 데이터만 조회합니다. &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 16.7053%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt;차원별 그룹화(집계)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.2404%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt; sum by (method) (http_requests_total) &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.0542%; height: 22px; text-align: center;&quot;&gt;&lt;b&gt; 모든 서버의 요청을 '메소드별'로 합산하여 보여줍니다. &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;PromQL의 주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 시계열 데이터 특화 &lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시간에 따라 변하는 데이터를 자연스럽게 다룰 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. 표현식 기반 &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수형 프로그래밍 스타일로 복잡한 쿼리를 &lt;b&gt;간결하게 작성&lt;/b&gt;할 수 있습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt; 레이블 기반 필터링 &lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; 다차원 데이터를 레이블&lt;/b&gt;을 통해 유연하게 &lt;b&gt;필터링&lt;/b&gt;하고 &lt;b&gt;그룹화&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;다차원 데이터 레이블&lt;/b&gt;이란❓&lt;br /&gt;&lt;br /&gt;- 레이블은 메트릭에 붙는 &lt;b&gt;키-값(Key-Value) 쌍&lt;/b&gt;으로, 데이터의 &lt;u&gt;&lt;b&gt;개별 속성을 정의&lt;/b&gt;&lt;/u&gt;하는 &lt;b&gt;다차원 식별자 역할&lt;/b&gt;을 합니다.&lt;br /&gt;- &lt;b&gt;동일한 메트릭&lt;/b&gt;(예: http_requests_total)이라도 &lt;b&gt;레이블(예: method, status, service)&lt;/b&gt;에 따라 데이터를 다각도로 쪼개거나 합쳐서 분석할 수 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt; 실시간 쿼리 &lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; 실시간으로 데이터를 조회&lt;/b&gt;하고 계산할 수 있어 즉각적인 모니터링이 가능합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;PromQL의 장단점&lt;/h3&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;장점&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;강력한 시계열 데이터 분석 능력&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;시간의 흐름&lt;/b&gt;에 따른 &lt;b&gt;데이터 변화&lt;/b&gt;를 &lt;b&gt;쉽게 추적하고 분석&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;i&gt; 증가율, 평균, 백분위수&lt;/i&gt; 등 다양한 통계를 &lt;b&gt;간단한 함수로 계산&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt; 직관적인 레이블 기반 필터링&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 차원의 데이터를 &lt;b&gt;레이블&lt;/b&gt;을 통해&lt;b&gt; 자유롭게 필터링&lt;/b&gt;하고 &lt;b&gt;그룹화&lt;/b&gt;할 수 있어, &lt;u&gt;&lt;b&gt;복잡한 조건의 데이터도 명확하게 조회&lt;/b&gt;&lt;/u&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt; 풍부한 내장 함수&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;집계, 변환, 예측 등 &lt;u&gt;&lt;b&gt;다양한 내장 함수를 제공&lt;/b&gt;&lt;/u&gt;하여 &lt;b&gt;복잡한 계산도 간단하게 수행&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt;&lt;span&gt; 시각화 도구와의 뛰어난 통합&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Grafana, Prometheus UI 등 주요 모니터링 대시보드 도구들과 완벽하게 통합되어 &lt;b&gt;즉시 시각화가 가능&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;5.&lt;span&gt;&lt;span&gt; 알림 규칙 설정 용이&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;임계값 기반 알림&lt;/b&gt;을 쉽게 설정할 수 있어, &lt;b&gt;시스템 이상 징후를 자동으로 감지&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;6.&lt;span&gt;&lt;span&gt; 클라우드 네이티브 생태계 표준&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Kubernetes, Docker&lt;/b&gt; 등 현대적인 인프라 환경에서 널리 채택된 &lt;b&gt;표준 쿼리 언어&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;text-align: center;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 초기 학습 곡선&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL에 익숙한 사용자라도 시계열 데이터 특유의 개념과 문법을 새로 학습해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. SQL과의 문법 차이&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기존 SQL 지식을 직접 활용하기 어렵고, 새로운 문법 체계에 적응이 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. 복잡한 쿼리의 성능 이슈&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 메트릭을 조인하거나 복잡한 계산을 수행할 때 성능 저하가 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4. 장기 데이터 보관의 어려움&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시계열 데이터의 특성상 데이터가 빠르게 증가하여 스토리지 관리와 비용 고려가 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;5. 제한적인 데이터 타입&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;주로 숫자형 메트릭 데이터만 다루며, 문자열이나 복잡한 데이터 구조 처리에는 제약이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;PromQL의 데이터 타입&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PromQL에서 다루는 데이터는 &lt;b&gt;크게 4가지 타입으로 분류&lt;/b&gt;됩니다.&amp;nbsp; 각 타입을 정확히 이해하면 복잡한 쿼리도 쉽게 작성할 수 있습니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. Instant Vector&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;정의&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; 같은 시점(동일한 타임스탬프)&lt;/b&gt;을 가진 &lt;b&gt;시계열 데이터의 집합&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;즉, 여러 시계열의&lt;b&gt; &quot;현재 순간&quot; 값&lt;/b&gt;들을 모아놓은 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 시계열마다&lt;span style=&quot;color: #006dd7;&quot;&gt; &lt;b&gt;가장 최근의 단일 값&lt;/b&gt;&lt;/span&gt;만을 가집니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;같은 타임스탬프를 공유&lt;/b&gt;하는 &lt;b&gt;여러 시계열로 구성&lt;/b&gt;됩니다&lt;/li&gt;
&lt;li&gt;그래프(Graph) 뷰에서 시간 흐름에 따라 &lt;b&gt;선으로 표시&lt;/b&gt;됩니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대부분의 PromQL 쿼리가 Instant Vector를 반환&lt;/b&gt;합니다&lt;/li&gt;
&lt;li&gt;레이블이 다르면 각각 별도의 시계열로 취급됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,0&quot;&gt;기본 예시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768118169150&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모든 HTTP 요청 메트릭의 현재 값
http_requests_total

# 레이블 필터링
http_requests_total{method=&quot;GET&quot;, status=&quot;200&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. Range Vector&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;정의&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 시간 범위 동안 기록된 시계열 데이터의 집합입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;현재를 기준&lt;/b&gt;으로 &lt;b&gt;과거 일정 기간&lt;/b&gt;의&lt;span style=&quot;color: #f89009;&quot;&gt; &lt;b&gt;데이터를 배열 형태&lt;/b&gt;&lt;/span&gt;로 가집니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;[5m]&lt;/span&gt;,&lt;/b&gt; &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;[1h]&lt;/span&gt;, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;[30d]&lt;/span&gt;&lt;/b&gt; 같은 &lt;u&gt;&lt;b&gt;시간 범위 선택자를 사용&lt;/b&gt;&lt;/u&gt;합니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;직접 그래프로 표시할 수 없습니다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;주로 &lt;b&gt;rate(), increase(), avg_over_time()&lt;/b&gt; 같은 함수의 입력값으로 사용됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,2,0&quot;&gt; 시간 범위 표기법&amp;nbsp;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;s - 초 (seconds)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;m - 분 (minutes)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;h - 시간 (hours)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;d - 일 (days)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;w - 주 (weeks)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;y - 년 (years)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;기본 예시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768118303376&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 최근 5분간의 HTTP 요청 데이터
http_requests_total[5m]

# 최근 1시간의 CPU 사용 데이터
cpu_usage_seconds[1h]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. Scalar (스칼라)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;정의&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; 시간 정보&lt;/b&gt;나 &lt;b&gt;레이블 정보&lt;/b&gt;가 없는 단순한 숫자(부동 소수점) 값입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;s&gt;특정 시계열에 속하지 않는&lt;/s&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;순수한 숫자&lt;/b&gt;&lt;/span&gt;입니다&lt;/li&gt;
&lt;li&gt;&lt;s&gt;&lt;b&gt;타임스탬프&lt;/b&gt;&lt;/s&gt;나 &lt;s&gt;&lt;b&gt;레이블&lt;/b&gt;&lt;/s&gt;을 가지지 않습니다&lt;/li&gt;
&lt;li&gt;쿼리 내에서 &lt;b&gt;상수로 사용되거나 연산에 활용&lt;/b&gt;됩니다&lt;/li&gt;
&lt;li&gt;일부 함수는 Scalar 값을 반환합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0&quot;&gt;기본 예시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768118402409&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 리터럴 숫자
100
3.14

# 연산에서 활용
memory_used_bytes / 1024 / 1024  # MB 단위 변환
cpu_usage_percent &amp;gt; 80  # 임계값 비교&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. String (문자열)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;정의&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순한 &lt;b data-index-in-node=&quot;8&quot; data-path-to-node=&quot;11,0,0&quot;&gt;문자열&lt;/b&gt; 값입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;특징&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 PromQL에서는 &lt;b&gt;매우 제한적으로 사용&lt;/b&gt;됩니다&lt;/li&gt;
&lt;li&gt;주로 함수의 인자나 레이블 값으로만 사용됩니다&lt;/li&gt;
&lt;li&gt;&lt;s&gt;&lt;b&gt;메트릭 값으로는 사용&lt;/b&gt;&lt;/s&gt;할 수 없습니다 (Prometheus는 숫자형 데이터만 저장)&lt;/li&gt;
&lt;li&gt;&lt;s&gt;&lt;b&gt;연산에 직접적으로 사용&lt;/b&gt;&lt;/s&gt;되지 않습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,0&quot;&gt;기본 예시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768118460390&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 레이블 필터링에서 사용
http_requests_total{method=&quot;GET&quot;}

# 정규표현식 매칭
http_requests_total{status=~&quot;5..&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;PromQL의 주요 내장 함수&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 증가율 계산 함수&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;rate() : 지정된 시간 범위 동안의 초당 평균 증가율을 계산&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;입력: &lt;b&gt;Range Vector&lt;/b&gt;&amp;nbsp;➡️ 출력: &lt;b&gt;Instant Vector &lt;/b&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768123525009&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 최근 5분간 초당 평균 요청 수
rate(http_requests_total[5m])

# 엔드포인트별 초당 요청 수
rate(http_requests_total[5m]) by (endpoint)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;사용 경우&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Counter 타입 메트릭의 증가율 계산&lt;/li&gt;
&lt;li&gt;알림 규칙 설정&lt;/li&gt;
&lt;li&gt;장기 추세 파악&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;irate() : 현재 순간의 즉시 증가율을 계산&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768123598004&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 현재 순간의 초당 요청 수
irate(http_requests_total[5m])&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 순간의 즉시 증가율을 계산합니다. 단, 최근 두 데이터 포인트만 사용됩니다.&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;rate() vs irate()&lt;/b&gt;&lt;/i&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;rate() : 완만한 그래프, 평균값, 알림용&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;irate() : 민감한 그래프, 즉각 반응, 실시간 모니터링용&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;increase() : 지정된 시간 범위 동안의 총 증가량을 계산&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768123717835&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 최근 1시간 동안의 총 요청 수
increase(http_requests_total[1h])&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 집계 함수&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;sum() : 메트릭 값들의 합계 계산&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;입력: &lt;b&gt;Instant Vector&lt;/b&gt;&amp;nbsp;➡️ 출력: &lt;b&gt;Instant Vector&lt;/b&gt; (또는 Scalar)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768123817679&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모든 인스턴스의 총 요청 수
sum(rate(http_requests_total[5m]))

# 엔드포인트별 총 요청 수
sum(rate(http_requests_total[5m])) by (endpoint)

# instance 레이블을 제외하고 합계
sum(rate(http_requests_total[5m])) without (instance)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;그룹화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;by (label)&lt;/b&gt;: 지정한 레이블로만 그룹화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;without (label)&lt;/b&gt;: 지정한 레이블을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제외&lt;/b&gt;&lt;/span&gt;하고 그룹화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;avg(), max(), min() : 평균, 최대값, 최소값을 계산 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768123936683&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 평균 CPU 사용률
avg(cpu_usage_percent) by (instance)

# 최대 메모리 사용량
max(memory_usage_bytes) by (instance)

# 최소 디스크 여유 공간
min(disk_free_bytes) by (mount_point)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;count() :&amp;nbsp; 메트릭 개수 계산&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;입력: &lt;b&gt;Instant Vector&lt;/b&gt; ➡️ 출력:&amp;nbsp;&lt;b&gt;Instant Vector&lt;/b&gt;&amp;nbsp;(또는 Scalar)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768124009118&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 정상 상태인 인스턴스 수
count(up == 1)

# 80% 이상 CPU를 사용하는 서버 개수
count(cpu_usage_percent &amp;gt; 80)&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;topk(), bottomk() :&amp;nbsp; 상위/하위 k개의 시계열 선택&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768124050297&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CPU 사용률 상위 5개 인스턴스
topk(5, cpu_usage_percent)

# 메모리 사용량 하위 3개 서버
bottomk(3, memory_usage_bytes)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. 시간 범위 함수&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;avg_over_time() : 시간 범위 내의 평균값을 계산&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;입력: &lt;b&gt;Renge&lt;/b&gt; &lt;b&gt;Vector&lt;/b&gt; ➡️ 출력:&amp;nbsp;&lt;b&gt;Instant Vector&lt;/b&gt;&amp;nbsp;(또는 Scalar)&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768124116270&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 최근 5분간 평균 CPU 사용률
avg_over_time(cpu_usage_percent[5m])

# 최근 1시간 평균 응답 시간
avg_over_time(http_response_time_seconds[1h])&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;max_over_time(), min_over_time() : 시간 범위 내의 최대/최소값 찾기&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768124156646&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 최근 1시간 최대 CPU 사용률 (피크)
max_over_time(cpu_usage_percent[1h])

# 최근 5분간 최대 응답 시간
max_over_time(http_request_duration_seconds[5m])&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. 백분위수 계산 함수&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;histogram_quantile() : 히스토그램 데이터에서 특정 백분위수 계산&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;입력: &lt;b&gt;Scalar(분위수)&lt;/b&gt;, &lt;b&gt;Instant Vector(히스토그램)&lt;/b&gt; ➡️ 출력: &lt;b&gt;Instant Vector&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre id=&quot;code_1768124221136&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 95 백분위수 응답 시간
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))

# 99 백분위수 응답 시간
histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m]))

# 엔드포인트별 95 백분위수
histogram_quantile(0.95, 
  sum(rate(http_request_duration_seconds_bucket[5m])) by (le, endpoint)
)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;le, endpoint란?
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;히스토그램의 각 구간 상한값을 나타내는 특수 레이블입니다. (0.1초, 0.5초, 1.0초 등).&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;histogram_quantile()&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;은 이 &lt;/span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`le`&lt;/span&gt;&lt;span&gt; 값들을 보고 백분위수를 계산하므로, &lt;/span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`sum`&lt;/span&gt;&lt;span&gt;으로 집계할 때 &lt;/span&gt;&lt;span style=&quot;color: #c678dd;&quot;&gt;`le`&lt;/span&gt;&lt;span&gt;를 제거하면 백분위수 계산이 불가능합니다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;5. 시간 관련 함수&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;offset : 특정 시간만큼 과거의 데이터 조회&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768124538556&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1시간 전 데이터
http_requests_total offset 1h

# 어제 같은 시간 데이터
http_requests_total offset 1d

# 현재와 1시간 전 비교
rate(http_requests_total[5m]) / rate(http_requests_total[5m] offset 1h)&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;6. 예측 함수&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;predict_linear() : 선형 회귀를 사용하여 미래 값을 예측&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768124566990&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 4시간 후 디스크 사용량 예측
predict_linear(node_filesystem_free_bytes[1h], 4 * 3600)

# 디스크가 가득 찰지 예측
predict_linear(node_filesystem_free_bytes[1h], 4 * 3600) &amp;lt; 0&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;7. 변환 함수&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;scalar() : 단일 값을 가진 Instant Vector를 Sclar로 변환&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768124595144&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Vector를 Scalar로 변환
scalar(sum(up))

# 조건부 비교에 활용
http_requests_total &amp;gt; scalar(sum(threshold_value))&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;PromQL의 주요 내장 함수 활용 예시&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시 1 : API 에러율 모니터링&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1768124654040&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 엔드포인트별 5xx 에러율
sum(rate(http_requests_total{status=~&quot;5..&quot;}[5m])) by (endpoint)
/
sum(rate(http_requests_total[5m])) by (endpoint)
* 100&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용 함수:&lt;/b&gt; rate(), sum(), by()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입 흐름&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;i&gt;http_requests_total[5m] &amp;rarr; Range Vector&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;rate(...) &amp;rarr; Instant Vector&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;sum(...) by (endpoint) &amp;rarr; Instant Vector&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;나누기 &amp;rarr; Instant Vector&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;* 100 &amp;rarr; Instant Vector (에러율 %)&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시 2 :&lt;span&gt; CPU 사용률 Top5&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1768124715364&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# CPU 사용률 상위 5개 서버
topk(5, 
  100 - (avg by (instance) (rate(node_cpu_seconds_total{mode=&quot;idle&quot;}[5m])) * 100)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용 함수:&lt;/b&gt; rate(), avg by(), topk()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입 흐름&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;i&gt;Range Vector &amp;rarr; rate() &amp;rarr; Instant Vector&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;avg by (instance) &amp;rarr; Instant Vector&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;100 - ... &amp;rarr; Instant Vector (CPU 사용률)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;topk(5, ...) &amp;rarr; Instant Vector (상위 5개)&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시 3 : 트래픽 급증 감지&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1768124755666&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 1시간 전 대비 트래픽 2배 이상 증가
sum(rate(http_requests_total[5m]))
/
sum(rate(http_requests_total[5m] offset 1h))
&amp;gt; 2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용 함수:&lt;/b&gt; rate(), sum(), offset&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입 흐름&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;i&gt;Range Vector &amp;rarr; rate() &amp;rarr; Instant Vector &amp;rarr; sum() &amp;rarr; Scalar&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;offset 1h &amp;rarr; 1시간 전 Scalar&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;나누기 &amp;rarr; Scalar&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&amp;gt; 2 &amp;rarr; Boolean&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시&lt;span&gt; 4 : 응답 시간 비교 (오늘 vs 어제)&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1768124809944&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 오늘과 어제 p95 응답 시간 차이
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
-
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m] offset 1d))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;사용 함수:&lt;/b&gt; rate(), histogram_quantile(), offset&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;타입 흐름&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;i&gt;Range Vector &amp;rarr; rate() &amp;rarr; Instant Vector&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;histogram_quantile() &amp;rarr; Instant Vector (p95)&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;offset 1d &amp;rarr; 어제 데이터&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;빼기 &amp;rarr; Instant Vector (차이)&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;데이터 타입 간 관계&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. Range Vector ➡️ Instant Vector 변환&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1768125110394&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Range Vector (그래프 표시 불가)
# 최근 5분간의 모든 데이터 포인트를 배열로 가짐
http_requests_total[5m]

# Instant Vector로 변환 (그래프 표시 가능)
rate(http_requests_total[5m])           # 초당 평균 증가율 계산
increase(http_requests_total[5m])       # 총 증가량 계산
avg_over_time(cpu_usage[5m])           # 5분간 평균값 계산
max_over_time(memory_usage[1h])        # 1시간 내 최대값 계산&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Range Vector&lt;/b&gt;는 &lt;b&gt;반드시 함수를 통해&lt;/b&gt; Instant Vector로 변환해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜냐하면, &lt;b&gt;Range Vector&lt;/b&gt;는 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;시간 범위 내 여러 개의 값(배열)&lt;/b&gt;&lt;/span&gt;을 가지므로 &lt;b&gt;&lt;s&gt;직접 그래프로 표시&lt;/s&gt;&lt;/b&gt;할 수 없습니다. &lt;b&gt;함수&lt;/b&gt;를 통해 이 값들을 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하나의 값으로 계산해야 시각화가 가능&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. Instant Vector ➡️ Scalar 변환&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;scalar() 함수 사용&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 사용 시기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;단일 시계열&lt;/b&gt;을&lt;b&gt; 숫자 값으로 변환&lt;/b&gt;하여 다른 계산에 활용할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768124952140&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Instant Vector &amp;rarr; Scalar
scalar(sum(up))

# 활용 예시: Scalar를 임계값으로 사용
http_requests_total &amp;gt; scalar(sum(threshold_value))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의‼️: scalar() 함수&lt;/b&gt;는 &lt;b&gt;정확히 1개의 시계열&lt;/b&gt;만 가진 &lt;b&gt;Vector에만 사용 가능&lt;/b&gt;합니다. 여러 시계열이 있으면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;에러 발생&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;레이블 없이 집계&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1768124967838&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sum(http_requests_total)      # &amp;rarr; Scalar
avg(cpu_usage_percent)        # &amp;rarr; Scalar
count(up == 1)                # &amp;rarr; Scalar&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;&lt;b&gt; 레이블을 지정&lt;/b&gt;&lt;/s&gt;하지 않고 집계하면 &lt;b&gt;모든 시계열이 하나로 합쳐져 &lt;span style=&quot;color: #f89009;&quot;&gt;자동&lt;/span&gt;으로 Scalar&lt;/b&gt;가 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. Scalar와 Vector 연산&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scalar는 Vector의 &lt;b&gt;각 시계열에 자동 적용&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vector와 Scalar를 연산하면, &lt;b&gt;Scalar 값(숫자)&lt;/b&gt;이 &lt;u&gt;&lt;b&gt;Vector의 모든 시계열에 동일하게 적용&lt;/b&gt;&lt;/u&gt;됩니다. 마치 반복문처럼 각 시계열마다 같은 연산을 수행하는 것과 같습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre id=&quot;code_1768124998664&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모든 시계열에 100 곱하기
cpu_usage * 100

# bytes를 MB로 변환
disk_usage_bytes / 1024 / 1024

# 임계값 비교
cpu_usage_percent &amp;gt; 80&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;활용 예시&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1768125257748&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 메모리 사용률을 퍼센트로 변환
(memory_used_bytes / memory_total_bytes) * 100
# 각 서버마다 (사용량 / 전체) * 100 계산

# 모든 응답 시간을 밀리초로 변환
http_response_time_seconds * 1000
# 각 엔드포인트의 응답 시간에 1000을 곱함&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;핵심은 바로 Scalar 하나가 Vector의 &lt;b&gt;모든 시계열&lt;/b&gt;에 &lt;b&gt;브로드캐스팅(broadcasting)&lt;/b&gt;된다는 것 입니다.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Monitoring</category>
      <category>prometheus</category>
      <category>promql</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/763</guid>
      <comments>https://pixx.tistory.com/763#entry763comment</comments>
      <pubDate>Sun, 11 Jan 2026 18:58:07 +0900</pubDate>
    </item>
    <item>
      <title>[Query DSL] Transform &amp;amp; GroupBy: 평면 조인 결과를 계층 구조로 쉽게 변환하기</title>
      <link>https://pixx.tistory.com/762</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYEJD5/btsJW9q2xVP/3z7K4CfFcopHz534g8dHtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYEJD5/btsJW9q2xVP/3z7K4CfFcopHz534g8dHtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYEJD5/btsJW9q2xVP/3z7K4CfFcopHz534g8dHtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYEJD5%2FbtsJW9q2xVP%2F3z7K4CfFcopHz534g8dHtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;351&quot; height=&quot;144&quot; data-origin-width=&quot;351&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JPA를 사용하다 보면 &lt;b&gt;게시글과 댓글&lt;/b&gt;, &lt;b&gt;주문과 주문&lt;/b&gt; 상품 같은 &lt;b&gt;1:N 관계를 조회&lt;/b&gt;해야 할 일이 정말 많습니다. 하지만 DB에서 조인(Join)을 하면 결과는 계층적 구조가 아닌 언제나 &lt;b&gt;평면적&lt;/b&gt;입니다.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;오늘은 이 간극을 메우기 위해 우리가 흔히 하던 'Map 노가다'를 버리고, QueryDSL의 &lt;b&gt;transform&lt;/b&gt;을 사용해 데이터를 가져오는 방법을 알아보겠습니다.&lt;br /&gt;&lt;br /&gt;즉,&amp;nbsp;연관관계가&amp;nbsp;있는&amp;nbsp;데이터를&amp;nbsp;조회할&amp;nbsp;때&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;평면적인(flat)&lt;/b&gt;&lt;/span&gt;&amp;nbsp;결과를&amp;nbsp;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;계층적인(hierarchical)&lt;/b&gt;&lt;/span&gt;&amp;nbsp;구조로&amp;nbsp;&lt;b&gt;변환&lt;/b&gt;해야 하는 경우가 자주 발생하는데, Map을 통한 수동 변환 작업은 번거롭고 실수하기 쉽습니다. QueryDSL의 &lt;b&gt;transform&lt;/b&gt;은 바로 이 문제를 해결해줍니다.&lt;br /&gt;&lt;br /&gt;이번&amp;nbsp;글에서는&amp;nbsp;회사에서&amp;nbsp;실제로&amp;nbsp;겪었던&amp;nbsp;사례를&amp;nbsp;바탕으로&amp;nbsp;QueryDSL의&amp;nbsp;transform&amp;nbsp;기능을&amp;nbsp;정리해보려&amp;nbsp;합니다.&amp;nbsp;보안상&amp;nbsp;실제&amp;nbsp;코드는&amp;nbsp;가져올&amp;nbsp;수&amp;nbsp;없어,&amp;nbsp;이해를&amp;nbsp;돕기&amp;nbsp;위한&amp;nbsp;간단한&amp;nbsp;예제&amp;nbsp;코드와&amp;nbsp;함께&amp;nbsp;설명하겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Qeury DSL - transform&amp;amp;groupBy란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;transform은 QueryDSL에서 제공하는 &lt;u&gt;&lt;b&gt;결과 변환 및 그룹핑 기능&lt;/b&gt;&lt;/u&gt;입니다. 하지만 Transform 혼자서는 아무것도 할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Transform의 핵심은 바로 &lt;b&gt;GroupBy&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;GroupBy와 관계&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1767948743271&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;.transform(
    groupBy(post.id).list(...)  // GroupBy가 핵심!
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;b&gt;transform()&lt;/b&gt;은&lt;b&gt; 쿼리 결과를 변환&lt;/b&gt;하는 프레임워크이고, &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;groupBy()&lt;/b&gt;는 &lt;b&gt;ResultTransformer의 구현체&lt;/b&gt;로서&lt;b&gt; 평면 데이터&lt;/b&gt;를 &lt;u&gt;&lt;b&gt;키 기준으로 묶는 역할&lt;/b&gt;&lt;/u&gt;을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Transform&lt;/b&gt;: 전체 변환 프레임워크&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GroupBy&lt;/b&gt;: 평면 데이터를 키 기준으로 묶는 핵심 메커니즘&lt;/li&gt;
&lt;li&gt;둘은 함께 사용되며, groupBy()가 transform()의 인자로 들어가는 구조입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주로 다음과 같은 상황에서 사용됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;1:N 관계의 데이터를 계층 구조로 변환&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;평면 쿼리 결과를 복잡한 DTO 구조로 매핑&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;그룹핑과 집계를 동시에 처리&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;QueryDSL 5.x부터 transform은 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;deprecated&lt;/b&gt;&lt;/span&gt;&amp;nbsp;되었습니다.&lt;br /&gt;&lt;br /&gt;공식 문서에서는 직접 구현을 권장하지만, 여전히 많은 프로젝트에서 사용되고 있으며 코드 간결성 측면에서 장점이 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;transform &amp;amp; groupBy 동작 원리&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, Post와 Comment의 &lt;b&gt;1:N 관계&lt;/b&gt;에서 &lt;b&gt;Post 목록을 조회&lt;/b&gt;하면서 &lt;b&gt;각 Post에 달린 Comment들을 함께 가져오고 싶을 때&lt;/b&gt;, 일반적인 JOIN 쿼리는 다음과 같은 평면 결과를 반환합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1767948001085&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Post1 - Comment1
Post1 - Comment2
Post2 - Comment3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 우리가 원하는 것은 다음과 같은 계층 구조입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1767948022966&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Post1
  - Comment1
  - Comment2
Post2
  - Comment3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 변환 작업을 &lt;b&gt;수동으로 처리&lt;/b&gt;하면 &lt;b&gt;코드가 복잡&lt;/b&gt;해지고 &lt;b&gt;실수&lt;/b&gt;하기 쉽습니다. QueryDSL의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;transform 기능&lt;/b&gt;&lt;/span&gt;은 바로 이 문제를 해결하기 위해 만들어졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt; Deprecated 배경과 대안&lt;br /&gt;&lt;br /&gt;&lt;span&gt;&lt;span style=&quot;color: #d19a66;&quot;&gt;QueryDSL&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span style=&quot;color: #d19a66;&quot;&gt;5.&lt;/span&gt;&lt;span&gt;x부터 transform은 deprecated 되었습니다&lt;/span&gt;&lt;span style=&quot;color: #abb2bf;&quot;&gt;.&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;이유&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;color: #61afef;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 복잡한 변환 로직을 라이브러리에 의존하는 것보다 &lt;/span&gt;&lt;/span&gt;&lt;span&gt; 명시적인 자바 코드로 구현하는 것이 유지보수에 유리하다는 판단&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;span style=&quot;color: #61afef;&quot;&gt;-&lt;/span&gt;&lt;span&gt; 성능 이슈나 예상치 못한 동작에 대한 제어가 어려움&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;color: #666666;&quot;&gt;하지만 여전히 많은 레거시 프로젝트에서 사용 중이며, 코드 간결성 측면에서는 여전히 장점이 있어 실무에서 유용합니다. &lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;GroupBy와 동작 원리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BroMf/dJMcabQqStV/aiY20kkzYtGhcXl5UWeeNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BroMf/dJMcabQqStV/aiY20kkzYtGhcXl5UWeeNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BroMf/dJMcabQqStV/aiY20kkzYtGhcXl5UWeeNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBroMf%2FdJMcabQqStV%2FaiY20kkzYtGhcXl5UWeeNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;664&quot; height=&quot;468&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;860&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;groupBy 주요 메서드&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. &lt;b&gt;groupBy(key)&lt;/b&gt;: 특정 필드를 기준으로 그룹핑&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;java&quot; style=&quot;color: #abb2bf; text-align: left;&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;groupBy(post.id)  // post.id로 그룹핑&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;데이터를 하나로 묶을 &lt;b&gt;부모의 고유 키&lt;/b&gt;를 지정합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보통 PK(Primary Key)인 &lt;b&gt;id&lt;/b&gt;를 기준으로 삼습니다.&lt;/li&gt;
&lt;li&gt;이 기준을 중심으로 여러 개의 Row가 &lt;b&gt;하나의 객체(Post)로 합쳐집니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;list(...) : 각 그룹을 List로 수집&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;groupBy(post.id).list(
    new QPostResponse(...)  // 각 그룹을 PostResponse로 변환
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;그룹핑된 데이터를 어떤 형태의 &lt;b&gt;결과 리스트&lt;/b&gt;로 만들지 정의합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;groupBy(post.id).list(...)라고 작성하면, 중복이 제거된 순수한 게시글 리스트가 반환됩니다.&lt;/li&gt;
&lt;li&gt;이때 &lt;b&gt;QDTO(QueryProjection)를 사용&lt;/b&gt;하면 &lt;u&gt;&lt;b&gt;생성자 파라미터에 맞춰 안전하게 매핑&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;list(expression) : 그룹 내 자식 Entity들을 List로 수집&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;gams&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;list(new QCommentDto(...))  // Comment들을 List&amp;lt;CommentDto&amp;gt;로&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;부모 객체 안에서 &lt;b&gt;자식 리스트를 수집&lt;/b&gt;할 때 사용합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조인으로 인해 불어난 Row들 중에서 &lt;b&gt;자식 데이터&lt;/b&gt;(Comment)들만 골라내어 부모 DTO의 List&amp;lt;CommentDto&amp;gt; 필드에 차곡차곡 채워줍니다.&lt;/li&gt;
&lt;li&gt;list(new QCommentDto(...))처럼 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;중첩해서 사용하면 계층 구조가 완성&lt;/b&gt;&lt;/span&gt;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;skipNulls() : null 값 자동 제외&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;lisp&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;list(new QCommentDto(...).skipNulls())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Left&amp;nbsp;Join&lt;/b&gt;으로&amp;nbsp;&lt;b&gt;자식&amp;nbsp;엔티티를&amp;nbsp;조회&lt;/b&gt;할 때, 자식 데이터가 없으면 comment.id, comment.content가 모두 &lt;b&gt;null&lt;/b&gt;이 되어 결과 리스트에 &lt;i&gt;&lt;b&gt;[CommentDto(null, null)] &lt;/b&gt;&lt;/i&gt;과 같은 형태로 담기게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;skipNulls()&lt;/b&gt;를 사용하면 이런&lt;b&gt; null 객체&lt;/b&gt;를 자동으로 필터링하여 빈 리스트([])를 반환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;transform 사용 이유&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 코드 간결성&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수동 그룹핑 코드를 작성하면 다음과 같은 작업이 필요합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;평면 DTO 정의&lt;/li&gt;
&lt;li&gt;Map을 사용한 그룹핑 로직 구현&lt;/li&gt;
&lt;li&gt;null 체크 및 중복 제거&lt;/li&gt;
&lt;li&gt;최종 결과 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Transform + GroupBy&lt;/b&gt;&lt;/span&gt;를 사용하면 이 모든 과정을 &lt;u&gt;&lt;b&gt;선언적으로 표현&lt;/b&gt;&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;가독성 향상&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비즈니스 로직&lt;/b&gt;과 &lt;b&gt;데이터 변환 로직&lt;/b&gt;이 &lt;b&gt;분리&lt;/b&gt;되어 코드의 의도가 명확해집니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lasso&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;// Transform + GroupBy: 의도가 명확
groupBy(post.id).list(
    new QPostResponse(
        post.id,
        post.title,
        list(new QCommentDto(...))
    )
)

// 수동 그룹핑: 구현 세부사항에 집중
Map&amp;lt;Long, PostResponse&amp;gt; map = new LinkedHashMap&amp;lt;&amp;gt;();
for (PostFlatDto row : flatResults) {
    PostResponse postRes = map.computeIfAbsent(...);
    if (row.getCommentId() != null) {
        postRes.getComments().add(...);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;주의사항 : 성능 고려 사항&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 메모리 내 그룹핑&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Transform&lt;/b&gt;은 DB에서 받은 &lt;b&gt;모든 평면 데이터&lt;/b&gt;를 &lt;u&gt;&lt;b&gt;메모리에 올린 후 그룹핑&lt;/b&gt;&lt;/u&gt;합니다.&lt;/li&gt;
&lt;li&gt;대량 데이터(수만 건 이상) 조회 시 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;OutOfMemoryError&lt;/span&gt; &lt;/b&gt;위험이 있습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 페이징 불가&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;groupBy().list()&lt;/b&gt;는 전체 데이터를 가져온 &lt;b&gt;후&lt;/b&gt; &lt;b&gt;그룹핑&lt;/b&gt;하므로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;DB 레벨 페이징이 불가능&lt;/b&gt;&lt;/span&gt;합니다.&lt;/li&gt;
&lt;li&gt;페이징이 필요한 경우 &lt;b&gt;Batch Size 조정&lt;/b&gt;이나 &lt;b&gt;별도 쿼리 분리&lt;/b&gt;를 고려해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. N+1 문제는 여전히 존재&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Transform은 &lt;b&gt;단순히 변환 로직&lt;/b&gt;일 뿐, &lt;u&gt;&lt;b&gt;Fetch Join 전략과는 별개&lt;/b&gt;&lt;/u&gt;입니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;따라서, 여전히 적절한 Join 전략이 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;groupBy &amp;amp; transform 사용 예시&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 엔티티 설계&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Post(게시물)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767949839314&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String title;

    @OneToMany(mappedBy = &quot;post&quot;)
    private List&amp;lt;Comment&amp;gt; comments = new ArrayList&amp;lt;&amp;gt;();

    public Post(String title) {
        this.title = title;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Comment(댓글)&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767949862694&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String content;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = &quot;post_id&quot;)
    private Post post;

    public Comment(String content, Post post) {
        this.content = content;
        this.post = post;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. DTO 설계&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1767949950410&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class PostResponse {
    private Long postId;
    private String title;
    private List&amp;lt;CommentDto&amp;gt; comments;

    @QueryProjection
    public PostResponse(Long postId, String title, List&amp;lt;CommentDto&amp;gt; comments) {
        this.postId = postId;
        this.title = title;
        this.comments = comments;
    }
}

@Data
public class CommentDto {
    private Long commentId;
    private String content;

    @QueryProjection
    public CommentDto(Long commentId, String content) {
        this.commentId = commentId;
        this.content = content;
    }
}

// 수동 그룹핑용 평면 DTO
@Data
@AllArgsConstructor
public class PostFlatDto {
    private Long postId;
    private String title;
    private Long commentId;
    private String content;
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. Transform 사용 vs 미사용 비교&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;Before : transform 미사용(수동 그룹핑)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767950024541&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Override
public List&amp;lt;PostResponse&amp;gt; searchBefore() {
    // 1. 평면 DTO로 조회
    List&amp;lt;PostFlatDto&amp;gt; flatResults = queryFactory
            .select(Projections.constructor(PostFlatDto.class,
                    post.id, post.title, comment.id, comment.content))
            .from(post)
            .leftJoin(post.comments, comment)
            .fetch();

    // 2. 메모리에서 수동 그룹핑
    Map&amp;lt;Long, PostResponse&amp;gt; map = new LinkedHashMap&amp;lt;&amp;gt;();
    for (PostFlatDto row : flatResults) {
        PostResponse postRes = map.computeIfAbsent(row.getPostId(),
                id -&amp;gt; new PostResponse(id, row.getTitle(), new ArrayList&amp;lt;&amp;gt;()));

        if (row.getCommentId() != null) {
            postRes.getComments().add(
                new CommentDto(row.getCommentId(), row.getContent())
            );
        }
    }
    return new ArrayList&amp;lt;&amp;gt;(map.values());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 데이터베이스에서 가져온 &lt;b&gt;평면적인 데이터&lt;/b&gt;를 자바 코드로 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;직접 조립&lt;/b&gt;&lt;/span&gt;하는 방식입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;Projections.constructor&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB의 Join 결과는 &lt;b&gt;게시글 1개&lt;/b&gt;에 &lt;b&gt;댓글이 3개&lt;/b&gt;라면 &lt;b&gt;총 3개의 행(Row)이 반환&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;이를 담기 위해 모든 필드가 펼쳐진 &lt;b&gt;PostFlatDto&lt;/b&gt;를 임시로 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;LinkedHashMap &amp;amp; computeIfAbsent&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;중복된 게시글 데이터를 통합하기 위해 Map을 사용합니다.&lt;/li&gt;
&lt;li&gt;게시글 ID가 &lt;b&gt;Map&lt;/b&gt;에 없으면 새로 만들고, 있으면 &lt;b&gt;기존 객체를 가져와 댓글만 리스트에 추가&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,0&quot;&gt;수동 Null 체크&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;leftJoin 시 댓글이 없는 경우 commentId가 &lt;b&gt;null&lt;/b&gt;로 들어오기 때문에, 이를 방어하는 if문 로직이 반드시 포함되어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;after : transform 사용(선언적 그룹핑)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767950075942&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Override
public List&amp;lt;PostResponse&amp;gt; searchAfter() {
    return queryFactory
            .from(post)
            .leftJoin(post.comments, comment)
            .transform(
                    groupBy(post.id).list(
                            new QPostResponse(
                                    post.id,
                                    post.title,
                                    list(new QCommentDto(
                                        comment.id, 
                                        comment.content
                                    ).skipNulls())
                            )
                    )
            );
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;QueryDSL의 transform을 사용하면 자바의 복잡한 컬렉션 가공 로직이 간단한 선언문으로 해결이 됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;groupBy(post.id)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;게시글 ID를 기준으로 행들을 묶겠다&quot;는 &lt;b&gt;기준&lt;/b&gt;을 세웁니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;list(new QPostResponse(...))&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;그룹핑된 덩어리를 &lt;b&gt;PostResponse 객체로 변환&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,2,0&quot;&gt;list(new QCommentDto(...))&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;게시글 내부의 댓글 리스트를 수집합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,1,1,0&quot;&gt;핵심 포인트&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;QueryDSL이 내부적으로 데이터를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자동으로 순회&lt;/b&gt;&lt;/span&gt;하며 CommentDto를 생성해 리스트에 넣어줍니다.&lt;/li&gt;
&lt;li&gt;개발자가 직접 for문을 돌리며 &lt;s&gt;&lt;b&gt;리스트에 데이터를 추가(add)할 필요&lt;/b&gt;&lt;/s&gt;가 전혀 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,3,0&quot;&gt;skipNulls()&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;댓글이 없는 경우 리스트에 null 요소가 들어가는 것을 방지하여, 깨끗한 빈 리스트([])를 보장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;transform 사용 코드와 미사용 코드의 응답결과를 보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;제목 없는 다이어그램.png&quot; data-origin-width=&quot;1450&quot; data-origin-height=&quot;1205&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biWmYv/dJMcafSQOey/y3fCKKEG1tK3s9SJfkZku1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biWmYv/dJMcafSQOey/y3fCKKEG1tK3s9SJfkZku1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biWmYv/dJMcafSQOey/y3fCKKEG1tK3s9SJfkZku1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiWmYv%2FdJMcafSQOey%2Fy3fCKKEG1tK3s9SJfkZku1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;675&quot; height=&quot;561&quot; data-filename=&quot;제목 없는 다이어그램.png&quot; data-origin-width=&quot;1450&quot; data-origin-height=&quot;1205&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 보면알 수 있듯이 미사용(before), 사용(after)의 응답 결과가 동일한 것을 알 수 있습니다. 이처럼 과정이 전혀 다름에도 같은 결과가 나오게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 두 가지 코드(transform 사용/미사용)를 비교해보면 그 차이가 극명하게 드러납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;먼저 &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;4&quot;&gt;transform을 사용하지 않을 때&lt;/b&gt;는 &lt;b&gt;계층 구조가 1단계(게시글-댓글)&lt;/b&gt;인 아주 단순한 상황임에도 불구하고, 데이터를 &lt;b&gt;재조합&lt;/b&gt;하기 위해 &lt;b&gt;Map&lt;/b&gt;과 &lt;b&gt;복잡한 반복문&lt;/b&gt;을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;직접 구현&lt;/b&gt;&lt;/span&gt;해야 합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이는 데이터 구조가 깊어지고 복잡해질수록 가독성을 해치고 유지보수를 어렵게 만드는 결정적인 원인이 됩니다. 또한, 데이터를 쿼리 단계에서 임시로 담아낼 별도의 &lt;b&gt;DTO(FlatDto)를 매번 생성&lt;/b&gt;해야 한다는 번거로움도 존재합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;반면 &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;5&quot;&gt;transform을 사용하면&lt;/b&gt; 아무리 복잡한 계층 구조라도 Map 가공 로직이나 수동 반복문 없이, &lt;b data-index-in-node=&quot;58&quot; data-path-to-node=&quot;5&quot;&gt;단순한 list() 중첩만으로 설계가 가능&lt;/b&gt;해집니다. 개발자는 더 이상 데이터를 어떻게 묶을지 고민하지 않고, 어떤 구조로 가져올지만 기술하면 됩니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;즉, '어떻게(How)'가 아닌 '&lt;b&gt;무엇을(What)'에 집중&lt;/b&gt;하게 됨으로써 코드의 간결함과 생산성을 동시에 챙길 수 있습니다.&lt;/p&gt;</description>
      <category>Framework/JPA</category>
      <category>groupby</category>
      <category>QueryDSL</category>
      <category>transform</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/762</guid>
      <comments>https://pixx.tistory.com/762#entry762comment</comments>
      <pubDate>Fri, 9 Jan 2026 20:29:30 +0900</pubDate>
    </item>
    <item>
      <title>[JPA]JPA IDENTITY 전략에서 쓰기 지연이 작동하지 않는 이유</title>
      <link>https://pixx.tistory.com/760</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;jpa logo.png&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;348&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wd3iA/btsIMiSaREt/x8M84ETAv1Z0yh8Kt6AQY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wd3iA/btsIMiSaREt/x8M84ETAv1Z0yh8Kt6AQY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wd3iA/btsIMiSaREt/x8M84ETAv1Z0yh8Kt6AQY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fwd3iA%2FbtsIMiSaREt%2Fx8M84ETAv1Z0yh8Kt6AQY0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;348&quot; height=&quot;348&quot; data-filename=&quot;jpa logo.png&quot; data-origin-width=&quot;348&quot; data-origin-height=&quot;348&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;회사에서 프로젝트를 하던 중, JPA 기본 키 생성 전략 중 하나인 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IDENTITY 전략&lt;/b&gt;&lt;/span&gt;을 사용했을 때,&lt;s&gt;&lt;b&gt; 쓰기 지연이 작동&lt;/b&gt;&lt;/s&gt;하지 않아 &lt;b&gt;대량의 데이터를 INSERT할 때 많은 양의 트래픽이 발생&lt;/b&gt;했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 왜 JPA IDENTITY 전략을 사용하면 &quot;쓰기 지연&quot;이 작동하지 않는지 공부한 내용을 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;JPA의 쓰기 지연(Transactional Write-behind)&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 JPA의 쓰기 지연에 대해서 살펴보겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;JPA는 기본적으로&lt;b&gt; 트랜잭션의 커밋 시점에 쿼리를 모아서 &lt;span style=&quot;color: #006dd7;&quot;&gt;한 번에&lt;/span&gt;&lt;/b&gt; 보냅니다. 이를&lt;b&gt; &quot;쓰기 지연&quot;&lt;/b&gt;이라고 부릅니다.&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;@Transactional
public void saveMembers() {
    Member member1 = new Member(&quot;회원1&quot;);
    Member member2 = new Member(&quot;회원2&quot;);
    Member member3 = new Member(&quot;회원3&quot;);

    entityManager.persist(member1);  // 쓰기 지연 저장소에 저장
    entityManager.persist(member2);  // 쓰기 지연 저장소에 저장
    entityManager.persist(member3);  // 쓰기 지연 저장소에 저장

    // 트랜잭션 커밋 시점에 3개의 INSERT 쿼리가 한 번에 실행됨
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;쓰기 지연의 동작 원리는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;463&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgsBOB/dJMcac9ARrt/kAFFkIXYp1C9jnph5SqCBk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgsBOB/dJMcac9ARrt/kAFFkIXYp1C9jnph5SqCBk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgsBOB/dJMcac9ARrt/kAFFkIXYp1C9jnph5SqCBk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgsBOB%2FdJMcac9ARrt%2FkAFFkIXYp1C9jnph5SqCBk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;845&quot; height=&quot;463&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;845&quot; data-origin-height=&quot;463&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;persist()&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;호출 시 엔티티를 &lt;b&gt;영속성 컨텍스트&lt;/b&gt;의 &lt;u&gt;&lt;b&gt;1차 캐시에 저장&lt;/b&gt;&lt;/u&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; PK를 키로 엔티티 객체를 저장 (예: {1: member1}) &lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;동시에 INSERT 쿼리를 쓰기 지연 SQL 저장소에 보관&lt;/li&gt;
&lt;li&gt;트랜잭션 커밋 시점에 모아둔 쿼리를 한 번에 데이터베이스로 전송&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 방식은 다음과 같은 장점을 제공합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 최적화&lt;/b&gt;: 여러 쿼리를 배치로 처리 가능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 호출 최소화&lt;/b&gt;: DB 왕복 횟수 감소&lt;/li&gt;
&lt;li&gt;&lt;b&gt;트랜잭션 일관성&lt;/b&gt;: 모든 변경사항을 한 번에 반영&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IDENTITY 전략이란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; IDENTITY 전략&lt;/b&gt;은 기본 키 생성을 데이터베이스에 위임하는 전략입니다. MySQL의 AUTO_INCREMENT, PostgreSQL의 SERIAL 등이 이에 해당합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1767868080687&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  // DB가 자동으로 생성

    private String name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기본 키 자동 생성(@GeneratedValue) 전략과 차이점&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;IDENTITY&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62.6744%;&quot;&gt;&lt;b&gt;데이터베이스 (AUTO_INCREMENT)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.4186%;&quot;&gt;&lt;b&gt;❌&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;SEQUENCE&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62.6744%;&quot;&gt;&lt;b&gt;데이터베이스 시퀀스&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.4186%;&quot;&gt;&lt;b&gt;✅&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;TABLE&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62.6744%;&quot;&gt;&lt;b&gt;별도 키 관리 테이블&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.4186%;&quot;&gt;&lt;b&gt;✅&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;AUTO&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 62.6744%;&quot;&gt;&lt;b&gt;DB에 따라 자동 선택&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 24.4186%;&quot;&gt;&lt;b&gt;DB 전략에 따름&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1767868046951&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JPA] Entity란 무엇일까❓(Entity: 데이터베이스와 자바 객체 간의 다리)&quot; data-og-description=&quot;자바 애플리케이션에서 데이터베이스와 상호작용할 때, Entity는 중요한 역할을 합니다.&amp;nbsp;JPA(Java Persistence API)에서 Entity는 데이터베이스의 테이블과 자바 클래스 간의 매핑을 정의하며, 데이터베&quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/260#%EA%B8%B0%EB%B3%B8%20%ED%82%A4%20%EC%9E%90%EB%8F%99%20%EC%83%9D%EC%84%B1(%40GeneratedValue)-1&quot; data-og-url=&quot;https://pixx.tistory.com/260&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/gvS3Z/hyZQ3DdQ0c/XhgrkHkokuxgWgEBfyn6Tk/img.png?width=348&amp;amp;height=348&amp;amp;face=0_0_348_348,https://scrap.kakaocdn.net/dn/Apwh1/hyZRjRYZN9/DbYvYrK0yxsRIbl8IK0Kpk/img.png?width=348&amp;amp;height=348&amp;amp;face=0_0_348_348,https://scrap.kakaocdn.net/dn/Tpu7B/hyZRhmkhwX/CKvZbkBE0TWyUFzwTYH081/img.png?width=543&amp;amp;height=361&amp;amp;face=0_0_543_361&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/260#%EA%B8%B0%EB%B3%B8%20%ED%82%A4%20%EC%9E%90%EB%8F%99%20%EC%83%9D%EC%84%B1(%40GeneratedValue)-1&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/260#%EA%B8%B0%EB%B3%B8%20%ED%82%A4%20%EC%9E%90%EB%8F%99%20%EC%83%9D%EC%84%B1(%40GeneratedValue)-1&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/gvS3Z/hyZQ3DdQ0c/XhgrkHkokuxgWgEBfyn6Tk/img.png?width=348&amp;amp;height=348&amp;amp;face=0_0_348_348,https://scrap.kakaocdn.net/dn/Apwh1/hyZRjRYZN9/DbYvYrK0yxsRIbl8IK0Kpk/img.png?width=348&amp;amp;height=348&amp;amp;face=0_0_348_348,https://scrap.kakaocdn.net/dn/Tpu7B/hyZRhmkhwX/CKvZbkBE0TWyUFzwTYH081/img.png?width=543&amp;amp;height=361&amp;amp;face=0_0_543_361');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[JPA] Entity란 무엇일까❓(Entity: 데이터베이스와 자바 객체 간의 다리)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;자바 애플리케이션에서 데이터베이스와 상호작용할 때, Entity는 중요한 역할을 합니다.&amp;nbsp;JPA(Java Persistence API)에서 Entity는 데이터베이스의 테이블과 자바 클래스 간의 매핑을 정의하며, 데이터베&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IDENTITY 전략에서 쓰기 지연이 작동하지 않는 이유&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 핵심 원인 : PK 값을 즉시 알아야 한다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 엔티티를 &lt;b&gt;영속성 컨텍스트&lt;/b&gt;에 저장할 때 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;반드시 PK 값이 필요&lt;/b&gt;&lt;/span&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트(1차 캐시)는 내부적으로 &lt;b data-index-in-node=&quot;23&quot; data-path-to-node=&quot;4&quot;&gt;Map 구조&lt;/b&gt;로 이루어져 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;Key:&lt;/b&gt; @Id로 지정한 식별자 (PK)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;Value:&lt;/b&gt; 엔티티 객체 자체&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;6&quot; data-ke-size=&quot;size16&quot;&gt;Map에 데이터를 넣을 때 &lt;b&gt;key 값이 null&lt;/b&gt;이면 &lt;s&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;저장&lt;/b&gt;&lt;/span&gt;&lt;/s&gt;할 수 없듯, JPA도 엔티티를 관리하기 위한 최소한의 조건인 &lt;s&gt;&lt;b&gt;PK가 없으면 영속 상태&lt;/b&gt;&lt;/s&gt;로 만들 수 없습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. IDENTITY 전략의 딜레마&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;문제는 &lt;b&gt;IDENTITY 전략&lt;/b&gt;(MySQL의 AUTO_INCREMENT 등)의 특징에 있습니다. 이 방식은 &lt;b data-index-in-node=&quot;58&quot; data-path-to-node=&quot;10&quot;&gt;&quot;일단 DB에 데이터를 넣어봐야&quot;&lt;/b&gt; 비로소 다음 PK 값이 무엇인지 결정됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;JPA 입장&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;얘를 영속성 컨텍스트에 넣으려면 지금 당장 PK가 필요해!&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;DB 입장&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;INSERT 쿼리를 날려주기 전까지는 PK가 뭔지 알려줄 수 없어.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;즉, IDENTITY 전략의 문제는 PK 값을 데이터베이스에 INSERT를 해봐야만 알 수 있다는 점입니다.&lt;br /&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. 결국, 쓰기 지연을 포기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1767869037856&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Member member = new Member(&quot;홍길동&quot;);
System.out.println(member.getId());  // null (아직 저장 전)

// 1. persist 호출 시점에 즉시 INSERT 실행! (쓰기 지연 X)
entityManager.persist(member);  

// 2. DB가 생성한 ID를 JDBC가 즉시 받아옴 (Statement.getGeneratedKeys())
// 3. 받아온 ID를 엔티티의 @Id 필드에 채워넣음
System.out.println(member.getId());  // 1 (DB에서 생성된 값 확인 가능)

// 4. 이제 PK가 생겼으므로 영속성 컨텍스트에 정상 저장&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;persist()&lt;/code&gt; 호출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;즉시 INSERT 쿼리 실행&lt;/b&gt; (쓰기 지연 X)&lt;/li&gt;
&lt;li&gt;DB에서 생성된 PK 값을 조회&lt;/li&gt;
&lt;li&gt;조회한 PK 값을 엔티티에 설정&lt;/li&gt;
&lt;li&gt;PK를 키로 사용하여 영속성 컨텍스트에 저장&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이유로 IDENTITY 전략에서는 &lt;code&gt;persist()&lt;/code&gt; 호출 즉시 INSERT가 실행되며, 쓰기 지연이 동작하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;SEQUENCE 전략과의 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 JPA의 기본키 자동생성 전략 중 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;SEQUENCE 전략&lt;/b&gt;&lt;/span&gt;은 왜 쓰기 지연이 가능할까요❓&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서&lt;b&gt; IDENTITY 전략&lt;/b&gt;이 ID를 알기 위해&lt;b&gt; 즉시 INSERT&lt;/b&gt;를 날려야 했다면, 오라클이나 PostgreSQL에서 주로 사용하는 &lt;b&gt;SEQUENCE 전략&lt;/b&gt;은 동작 방식이 완전히 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;핵심 차이점 : INSERT 전에 ID를 미리 알 수 있다.&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SEQUENCE 전략의 핵심은 &lt;b&gt;DB에 실제 데이터를 넣기 &lt;span style=&quot;color: #ee2323;&quot;&gt;전&lt;/span&gt;&lt;/b&gt;에, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;번호만 따로 생성해주는 전용 객체(Sequence)&lt;/b&gt;&lt;/span&gt;가 존재한다는 점입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1767870199612&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;entityManager.persist(member1);  

entityManager.persist(member2);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt; entityManager.persist(member1);&lt;/b&gt;&lt;/i&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;DB 시퀀스 객체에 &quot;다음 번호 하나 줘!&quot;라고 요청 (SELECT NEXT VALUE)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;DB로부터 '1번'이라는 값을 받아 엔티티 ID에 할당&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이제 ID(Key)가 생겼으니 영속성 컨텍스트에 저장 가능!&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;INSERT 쿼리는 아직 날리지 않고 '쓰기 지연 저장소'에 보관 ✅&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;&lt;span&gt; entityManager.persist(member2);&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;i&gt;&lt;span&gt; 같은 방식으로 '2번' 번호표를 미리 받아오고 쿼리는 저장소에 보관 &lt;/span&gt;&lt;/i&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;IDENTITY vs SEQUENCE&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;11&quot; data-ke-size=&quot;size16&quot;&gt;두 전략의 결정적인 차이를 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;11&quot;&gt;'번호표'&lt;/b&gt; 비유로 정리하면 이렇습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;12&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;IDENTITY (식당 결제 방식)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;일단 음식을 먹어봐야(INSERT) 얼마인지(ID) 알고 영수증을 처리할 수 있다.&quot; ➡️&amp;nbsp;&lt;b data-index-in-node=&quot;72&quot; data-path-to-node=&quot;12,0,0&quot;&gt;기다릴 수 없음.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;SEQUENCE (은행 번호표 방식)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;입구에서 번호표(ID)를 먼저 뽑았으니, 실제 업무(INSERT)는 나중에 순서대로 처리해도 된다.&quot; ➡️ &lt;b data-index-in-node=&quot;82&quot; data-path-to-node=&quot;12,1,0&quot;&gt;쓰기 지연 가능.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;따라서, SEQUENCE는 INSERT 전에 미리 PK 값을 알 수 있기 때문에 쓰기 지연이 가능합니다.&lt;/b&gt;&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면, 그냥 SEQUENCE 전략을 쓰면되는거 아닌가 하는 생각이 듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 &lt;b&gt;SEQUENCE 전략&lt;/b&gt;은 &lt;s&gt;&lt;b&gt;모든 DBMS에서 사용&lt;/b&gt;&lt;/s&gt;할 수 있는 것은 아닙니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 58.3697%; height: 66px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.4186%; height: 22px;&quot;&gt;구분&lt;/td&gt;
&lt;td style=&quot;width: 19.5085%; height: 22px;&quot;&gt;지원 여부&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.4186%; height: 22px;&quot;&gt;지원함&lt;/td&gt;
&lt;td style=&quot;width: 19.5085%; height: 22px;&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,1,2,0&quot;&gt;Oracle, PostgreSQL&lt;/b&gt;, DB2, H2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 22px;&quot;&gt;
&lt;td style=&quot;width: 9.4186%; height: 22px;&quot;&gt;지원 안함&lt;/td&gt;
&lt;td style=&quot;width: 19.5085%; height: 22px;&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,2,2,0&quot;&gt;MySQL, MariaDB&lt;/b&gt;, SQL Server (구버전)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MySQL이나 MariaDB는 시퀀스 객체 대신 AUTO_INCREMENT라는 방식을 사용하기 때문에, 기본적으로 IDENTITY 전략을 사용해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IDENTITY 전략의 문제&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IDENTITY 전략의 가장 큰 성능 문제는 &lt;b&gt;JDBC Batch Insert를 사용할 수 없다&lt;/b&gt;는 점입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Batch Insert란❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Batch Insert&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;여러 개의 INSERT 쿼리를 하나의 네트워크 호출로 묶어서 전송&lt;/b&gt;&lt;/u&gt;하는&lt;b&gt; 최적화 기법&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;-- 일반적인 INSERT (3번의 네트워크 호출)
INSERT INTO member (name) VALUES ('회원1');
INSERT INTO member (name) VALUES ('회원2');
INSERT INTO member (name) VALUES ('회원3');

-- Batch INSERT (1번의 네트워크 호출)
INSERT INTO member (name) VALUES ('회원1'), ('회원2'), ('회원3');&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;IDENTITY 전략에서의 문제&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@Transactional
public void saveMembers() {
    for (int i = 1; i &amp;lt;= 1000; i++) {
        Member member = new Member(&quot;회원&quot; + i);
        entityManager.persist(member);
        // 매번 즉시 INSERT 실행 &amp;rarr; 1000번의 DB 호출!
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;persist()&lt;/code&gt; 호출마다 즉시 INSERT 실행&lt;/li&gt;
&lt;li&gt;각 INSERT마다 개별적인 네트워크 호출 발생&lt;/li&gt;
&lt;li&gt;Batch Insert 최적화 불가능&lt;/li&gt;
&lt;li&gt;대량 데이터 저장 시 성능 저하&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;성능 비교&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1000개의 엔티티를 저장하는 경우&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.2635%;&quot;&gt;&lt;b&gt; 전략 &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.4031%;&quot;&gt;&lt;b&gt; 네트워크 호출 횟수 &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt; 예상 시간 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.2635%;&quot;&gt;&lt;b&gt; IDENTITY (Batch 불가) &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.4031%;&quot;&gt;&lt;b&gt; 1000번 &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt; ~2-3초 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.2635%;&quot;&gt;&lt;b&gt; SEQUENCE (Batch 가능) &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.4031%;&quot;&gt;&lt;b&gt; 10-20번 &lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;&lt;b&gt; ~0.2-0.5초 &lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IDENTITY 전략의 문제 해결방법&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. SEQUENCE 전략으로 변경&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Entity
@SequenceGenerator(
    name = &quot;member_seq_generator&quot;,
    sequenceName = &quot;member_seq&quot;,
    allocationSize = 50  // 성능 최적화
)
public class Member {
    @Id
    @GeneratedValue(
        strategy = GenerationType.SEQUENCE,
        generator = &quot;member_seq_generator&quot;
    )
    private Long id;

    private String name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;쓰기 지연 가능&lt;/li&gt;
&lt;li&gt;Batch Insert 가능&lt;/li&gt;
&lt;li&gt;&lt;code&gt;allocationSize&lt;/code&gt;를 통한 추가 최적화 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MySQL 5.7 이하에서는 SEQUENCE 미지원&lt;/li&gt;
&lt;li&gt;DB 마이그레이션 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. JDBC Batch Size 설정 (Sequence)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;spring:
  jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 50  # 한 번에 50개씩 배치 처리
        order_inserts: true  # INSERT 순서 정렬
        order_updates: true  # UPDATE 순서 정렬&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;Hibernate 설정만으로 여러 개의 INSERT를 하나로 묶어 네트워크 비용을 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단,&lt;/b&gt; 앞서 설명했듯, 이 설정은 &lt;b data-index-in-node=&quot;24&quot; data-path-to-node=&quot;7,0&quot;&gt;IDENTITY 전략에서는 무용지물&lt;/b&gt;입니다. Hibernate가 ID를 확인하기 위해 매번 INSERT를 실행해야 하므로 &lt;s&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;배치가 작동&lt;/b&gt;&lt;/span&gt;&lt;/s&gt;하지 않습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. JDBC Template 직접 사용&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL/MariaDB 환경에서 &lt;b&gt;대량의 데이터를 가장 빠르게 넣는 방법&lt;/b&gt;입니다. JPA를 거치지 않고 직접 SQL을 날려 &lt;b data-index-in-node=&quot;68&quot; data-path-to-node=&quot;10&quot;&gt;쓰기 지연과 ID 조회 과정을 생략&lt;/b&gt;합니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Repository
@RequiredArgsConstructor
public class MemberBulkRepository {

    private final JdbcTemplate jdbcTemplate;

    public void bulkInsert(List&amp;lt;Member&amp;gt; members) {
        String sql = &quot;INSERT INTO member (name) VALUES (?)&quot;;

        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                ps.setString(1, members.get(i).getName());
            }

            @Override
            public int getBatchSize() {
                return members.size(); // 한 번의 네트워크 통신으로 처리할 데이터 양
            }
        });
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;JPA 영속성 컨텍스트&lt;/b&gt;를 거치지 않으므로 1&lt;s&gt;&lt;b&gt;차 캐시 등에 의한 메모리 부하&lt;/b&gt;&lt;/s&gt;가 없습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,1,0&quot;&gt;단,&lt;/b&gt; DB에 직접 넣는 것이기 때문에, 실행 후 영속성 컨텍스트를 새로고침(clear)하거나 동기화에 신경 써야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. TABLE 전략 사용&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 DB에서 시퀀스처럼 미리 번호를 따올 수 있도록 별도의 &lt;b&gt;'키 생성 전용 테이블&lt;/b&gt;'을 만드는 전략입니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Entity
@TableGenerator(
    name = &quot;member_id_generator&quot;,
    table = &quot;id_generator&quot;,
    pkColumnValue = &quot;member_id&quot;,
    allocationSize = 50
)
public class Member {
    @Id
    @GeneratedValue(
        strategy = GenerationType.TABLE,
        generator = &quot;member_id_generator&quot;
    )
    private Long id;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;장점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IDENTITY와 달리 번호를 미리 가져올 수 있어 &lt;b data-index-in-node=&quot;33&quot; data-path-to-node=&quot;17,0,0&quot;&gt;쓰기 지연과 Batch Insert가 가능&lt;/b&gt;해집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;단점&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;번호를 딸 때마다 id_generator 테이블을 업데이트해야 하므로, 아주 빈번한 삽입 시 &lt;b data-index-in-node=&quot;56&quot; data-path-to-node=&quot;17,1,0&quot;&gt;DB 락(Lock)이나 오버헤드&lt;/b&gt;가 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;IDENTITY 전략의 특징 요약&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정이 간단함&lt;/li&gt;
&lt;li&gt;DB의 네이티브 기능 활용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;AUTO_INCREMENT&lt;/b&gt;와 자연스럽게 매칭&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;❌ 쓰기 지연 불가능&lt;/li&gt;
&lt;li&gt;❌ Batch Insert 불가능&lt;/li&gt;
&lt;li&gt;❌ 대량 데이터 저장 시 성능 저하&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;권장 사항&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;소규모 애플리케이션&lt;/b&gt;: IDENTITY 전략 사용해도 무방&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대량 데이터 처리 필요&lt;/b&gt;: SEQUENCE 전략으로 변경 권장 (단 지원 가능 DBMS만)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MySQL 사용 중&lt;/b&gt;: MySQL 8.0+ 버전에서 SEQUENCE 지원 확인 후 전략 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이미 IDENTITY 사용 중&lt;/b&gt;: 대량 INSERT가 필요한 부분만 JDBC Template 활용&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트의 요구사항과 데이터 규모를 고려하여 적절한 키 생성 전략을 선택하는 것이 중요합니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#identifiers&quot;&gt;Hibernate Documentation - ID Generation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.spring.io/spring-data/jpa/docs/current/reference/html/&quot;&gt;Spring Data JPA - Batch Insert&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Framework/JPA</category>
      <category>identity</category>
      <category>JdbcTemplate</category>
      <category>JPA</category>
      <category>SEQUNCE</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/760</guid>
      <comments>https://pixx.tistory.com/760#entry760comment</comments>
      <pubDate>Thu, 8 Jan 2026 20:36:25 +0900</pubDate>
    </item>
    <item>
      <title>[Spring boot] 동기식 HTTP 클라이언트 RestTemplate 알아보기</title>
      <link>https://pixx.tistory.com/759</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1AqzH%2FbtsMyTT86M1%2FV8DfRaXFjDMumvvn5knww0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;163&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring에서 외부 API를 호출할 때 사용되는 방법은 RestTemplate, WebClient, RestClient,&lt;span&gt;&amp;nbsp;&lt;/span&gt;OpenFeign 등이 있습니다. 이번 글에서는 이 중 RestTemplate에 대한 공부한 내용을 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;비록 Spring 공식 문서에서는 &lt;b&gt;WebClient 사용을 지향&lt;/b&gt;하지만, 여전히 많은 레거시 시스템과 프로젝트의 표준으로 자리 잡고 있는 RestTemplate에 대해 다뤄보고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;RestTemplate란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RestTemplate은 Spring 3.0부터 제공된 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;동기식 HTTP 클라이언트&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, HTTP 통신을 위한 도구로 &lt;b&gt;RESTful API&lt;/b&gt; &lt;b&gt;웹 서비스와의 상호작용&lt;/b&gt;을 쉽게 외부 도메인에서 &lt;b&gt;데이터를 가져오거나&lt;/b&gt; &lt;b&gt;전송&lt;/b&gt;할 때 사용되는 스프링 프레임워크의 클래스를 의미합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;RestTemplate이 Deprecated 된다고 알고 있는 사람이 종종있는데 아직까지도 deprecated가 아닙니다. 새로운 기능 추가는 없지만 버그 수정과 보안 업데이트는 계속되고있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://spring.io/blog/2025/09/30/the-state-of-http-clients-in-spring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;출처&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;RestTemplate 주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;블로킹&lt;/b&gt; 기반의 &lt;b&gt;동기(Synchronous)&lt;/b&gt; 방식으로 동작합니다.&lt;/li&gt;
&lt;li&gt;HTTP 메서드별로 직관적인 메서드를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자동&lt;/b&gt;으로 JSON/XML과 객체 간 변환을 처리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;블로킹 요청(Blocking Request) 란❓&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt; 하나의 작업이 진행되는 동안 &lt;b data-index-in-node=&quot;36&quot; data-path-to-node=&quot;0&quot;&gt;그 작업이 끝날 때까지 제어권을 &lt;span style=&quot;color: #ee2323;&quot;&gt;붙잡아&lt;/span&gt; 두어 &lt;s&gt;다음 작업이 실행&lt;/s&gt;되지 못하게 막는 상태&lt;/b&gt;를 의미합니다. &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;unblocked 상태가 되면 다음 요청에 대해 처리를 수행합니다.&lt;/span&gt;&lt;span style=&quot;color: #000000; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;즉, 요청을 보낸 스레드가&amp;nbsp; 응답이&amp;nbsp;올&amp;nbsp;때까지&amp;nbsp;&quot;&lt;b&gt;멈춰서&amp;nbsp;기다리는&lt;/b&gt;&quot;&amp;nbsp;요청&amp;nbsp;방식&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;RestTemplate의 역할&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;386&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XQSE7/dJMcaaKKyl9/QLqRXJDr2hKKCmsTSS8w5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XQSE7/dJMcaaKKyl9/QLqRXJDr2hKKCmsTSS8w5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XQSE7/dJMcaaKKyl9/QLqRXJDr2hKKCmsTSS8w5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXQSE7%2FdJMcaaKKyl9%2FQLqRXJDr2hKKCmsTSS8w5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;510&quot; height=&quot;386&quot; data-origin-width=&quot;510&quot; data-origin-height=&quot;386&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;RestTemplate은 Spring Framework와 외부 REST API 사이의 중간 계층 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Request a resource&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring 애플리케이션이 &lt;b&gt;RestTemplate에게 외부 API 호출을 요청&lt;/b&gt;합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RestTemplate 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RestTemplate이&lt;b&gt; HTTP 요청을 구성&lt;/b&gt;하고 &lt;b&gt;실행&lt;/b&gt;합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;REST API 호출&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실제 외부 REST API 서버에 HTTP 요청을 보냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Get a resource&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;응답&lt;/b&gt;을 받아서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자바 객체로 변환&lt;/b&gt;&lt;/span&gt;하여 애플리케이션에 반환합니다.&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 객체로 변환할 때 RestTemplate는 내부적으로 &lt;b&gt;HttpMessageConverter&lt;/b&gt;를 사용해서 HTTP응답 (JSON, XML 등)을 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;자바 객체로 자동 변환&lt;/b&gt;&lt;/span&gt; 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;nbsp;이러한 중간 계층 덕분에 개발자는 복잡한 HTTP 통신 로직을 직접 작성하지 않고, 간단한 메서드 호출만으로 외부 API와 통신할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;RestTemplate 설정하기&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;의존성 추가&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring Boot Web 스타터를 사용하면 별도의 의존성 추가 없이 &lt;b&gt;RestTemplate을 사용&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767792009460&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Bean 등록&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767792030407&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class RestTemplateConfig {
    
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(5))
            .build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RestTemplate은 여러 곳에서 재사용하는 것이 일반적이므로, &lt;u&gt;&lt;b&gt;Spring Bean으로 등록&lt;/b&gt;&lt;/u&gt;하여 사용하는 것을 권장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt; RestTemplateBuilder 활용&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767792073298&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class RestTemplateConfig {
    
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
            .rootUri(&quot;https://api.example.com&quot;)  // 기본 URL 설정
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(5))
            .defaultHeader(&quot;User-Agent&quot;, &quot;MyApp/1.0&quot;)
            .interceptors(new LoggingInterceptor())  // 인터셉터 추가
            .errorHandler(new CustomErrorHandler())  // 에러 핸들러 설정
            .build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RestTemplateBuilder를 사용하면 더 세밀한 설정이 가능합니다.&lt;/li&gt;
&lt;li&gt;Spring Boot는 &lt;span style=&quot;color: #f3c000;&quot;&gt;&lt;b&gt;RestTemplateBuilder&lt;/b&gt;&lt;/span&gt;를 자동으로 제공합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이를 주입받아 RestTemplate을 생성하면, Spring Boot의 자동 설정 혜택을 받을 수 있습니다.&lt;/li&gt;
&lt;li&gt;위 예제에서는 연결 타임아웃과 읽기 타임아웃을 각각 5초로 설정했습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;rootUri&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 요청에 공통으로 사용될 기본 URL을 설정합니다.&lt;/li&gt;
&lt;li&gt;이후 요청 시 상대 경로만 지정하면 됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;setConnectTimeout&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버와의 연결을 시도하는 최대 시간입니다.&lt;/li&gt;
&lt;li&gt;이 시간 내에 연결되지 않으면 예외가 발생합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;setReadTimeout&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버로부터 데이터를 읽는 최대 시간입니다.&lt;/li&gt;
&lt;li&gt;연결은 되었지만 응답이 느릴 때 적용됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;defaultHeader&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 요청에 기본으로 포함될 HTTP 헤더를 설정합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;interceptors&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청/응답을 가로채서 로깅, 인증 토큰 추가 등의 공통 로직을 처리합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;errorHandler&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 에러 응답(4xx, 5xx)을 커스텀하게 처리하는 핸들러를 등록합니다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;여러개의 RestTemplate Bean 설정하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt; 서로 다른 API 서버를 호출&lt;/b&gt;&lt;/span&gt;해야 하는 경우, &lt;b&gt;여러 개의 RestTemplate Bean을 등록&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 API 서버마다 다른 설정(타임아웃, 기본 URL, 헤더 등)이 필요할 때 유용합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1767793724135&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class RestTemplateConfig {
    
    @Bean
    @Qualifier(&quot;paymentRestTemplate&quot;)
    public RestTemplate paymentRestTemplate(RestTemplateBuilder builder) {
        return builder
            .rootUri(&quot;https://payment-api.example.com&quot;)
            .setConnectTimeout(Duration.ofSeconds(3))
            .setReadTimeout(Duration.ofSeconds(10))
            .build();
    }
    
    @Bean
    @Qualifier(&quot;userRestTemplate&quot;)
    public RestTemplate userRestTemplate(RestTemplateBuilder builder) {
        return builder
            .rootUri(&quot;https://user-api.example.com&quot;)
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(5))
            .build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;@Qualifier&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; Bean&lt;/b&gt;의 &lt;b&gt;식별자를 지정&lt;/b&gt;하는 어노테이션입니다.&lt;/li&gt;
&lt;li&gt;같은 타입(RestTemplate)의 Bean이 여러 개 있을 때, 각각을 구분하기 위해 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;s&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt; @Qualifier 없이&lt;/b&gt;&lt;/span&gt;&lt;/s&gt; 같은 타입의 Bean이 여러 개 있으면, Spring은 &lt;b&gt;어떤 Bean을 주입해야 할지 알 수 없어&lt;/b&gt; &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;NoUniqueBeanDefinitionException 에러&lt;/b&gt;&lt;/span&gt;가 발생합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1767793739217&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class PaymentService {
    
    @Qualifier(&quot;paymentRestTemplate&quot;)
    private final RestTemplate restTemplate;
    
    // ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt; @Qualifier(&quot;paymentRestTemplate&quot;)&lt;/span&gt; &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필드 위에 붙이는 어노테이션으로, 어떤 Bean을 주입받을지 명시합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;동작 원리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Spring이 PaymentService의 인스턴스를 생성할 때, RestTemplate 타입의 Bean 중에서 @Qualifier(&quot;paymentRestTemplate&quot;)로 &lt;b&gt;지정된 Bean을 찾아서 주입&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;위치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Qualifier는 private final RestTemplate restTemplate; 바로 위에 위치해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이름 일치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Config 클래스에서 지정한 Qualifier 이름(&quot;paymentRestTemplate&quot;)과 정확히 일치해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;RestTemplate 주요 메서드 활용하기&lt;/h3&gt;
&lt;table style=&quot;background-color: #ffffff; color: #353638; text-align: left; border-collapse: collapse; width: 100%; height: 273px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px; text-align: left;&quot;&gt;Method&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px; text-align: left;&quot;&gt;HTTP Method&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px; text-align: left;&quot;&gt;Return Type&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px; text-align: left;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;getForObject()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;GET&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;Object&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;GET 요청에 대한 결과를 객체로 반환합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;getForEntity()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;GET&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;ResponseEntity&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;GET 요청에 대한 결과를 ResponseEntity로 반환합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;postForLocation()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;POST&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;URI&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;POST 요청에 대한 결과로 헤더에 저장된 URI 반환합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;postForObject()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;POST&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;Object&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;POST 요청에 대한 결과를 객체로 반환합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;postForEntity()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;POST&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;ResponseEntity&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;POST 요청에 대한 결과를 ResponseEntity로 반환합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;put()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;PUT&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;void&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;PUT 요청을 실행합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;patchForObject()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;PATCH&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;Object&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;PATCH 요청을 실행하고 결과를 객체로 반환합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;delete()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;DELETE&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;void&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;DELETE 요청을 실행합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;headForHeaders()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;HEADER&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;HttpHeaders&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;헤더 정보를 추출하고 HTTP HEAD 메서드를 사용합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;optionsForAllow()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;OPTIONS&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;Set&amp;lt;HttpMethod&amp;gt;&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;지원되는 HTTP 메서드를 추출합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px;&quot;&gt;exchange()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px;&quot;&gt;any&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px;&quot;&gt;ResponseEntity&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px;&quot;&gt;헤더를 생성하고 모든 요청 방법을 허용합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot;&gt;
&lt;td style=&quot;color: #353638; width: 17.4419%; height: 21px; text-align: left;&quot;&gt;execute()&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 13.9535%; height: 21px; text-align: left;&quot;&gt;any&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 16.9768%; height: 21px; text-align: left;&quot;&gt;T&lt;/td&gt;
&lt;td style=&quot;color: #353638; width: 51.5116%; height: 21px; text-align: left;&quot;&gt;요청/응답 콜백을 수정합니다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. GET 요청&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;getForObject()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답 본문을 직접 객체로 반환합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767795574290&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
@RequiredArgsConstructor
public class UserService {
    
    private final RestTemplate restTemplate;
    
    public User getUser(Long id) {
        String url = &quot;https://api.example.com/users/&quot; + id;
        return restTemplate.getForObject(url, User.class);
    }
    
    // URI Variables 사용
    public User getUserWithVariable(Long id) {
        String url = &quot;https://api.example.com/users/{id}&quot;;
        return restTemplate.getForObject(url, User.class, id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;getForEntity() &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답 본문뿐만 아니라 &lt;b&gt;HTTP 상태 코드&lt;/b&gt;, &lt;b&gt;헤더&lt;/b&gt; 등 전체 응답 정보를 포함하는 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;ResponseEntity를 반환&lt;/b&gt;&lt;/span&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767795605693&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public ResponseEntity&amp;lt;User&amp;gt; getUserEntity(Long id) {
    String url = &quot;https://api.example.com/users/{id}&quot;;
    ResponseEntity&amp;lt;User&amp;gt; response = restTemplate.getForEntity(url, User.class, id);
    
    // 상태 코드 확인
    HttpStatus statusCode = response.getStatusCode();
    
    // 헤더 정보 확인
    HttpHeaders headers = response.getHeaders();
    
    // 응답 본문
    User user = response.getBody();
    
    return response;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. POST 요청&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;postForObject() &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;POST 요청&lt;/b&gt;을 보내고 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;응답 본문&lt;/span&gt;을 객체로 반환&lt;/b&gt;합니다.
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767795652527&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public User createUser(User newUser) {
    String url = &quot;https://api.example.com/users&quot;;
    return restTemplate.postForObject(url, newUser, User.class);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;postForEntity()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; POST 요청&lt;/b&gt;을 보내고 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;ResponseEntity&lt;/span&gt;를 반환&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767795690434&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public ResponseEntity&amp;lt;User&amp;gt; createUserEntity(User newUser) {
    String url = &quot;https://api.example.com/users&quot;;
    ResponseEntity&amp;lt;User&amp;gt; response = restTemplate.postForEntity(url, newUser, User.class);
    
    // 생성된 리소스의 Location 헤더 확인
    URI location = response.getHeaders().getLocation();
    
    return response;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;postForLocation()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;POST 요청 &lt;/b&gt;후 생성된 리소스의 &lt;b&gt;Location URI를 반환&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767795722214&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public URI createUserLocation(User newUser) {
    String url = &quot;https://api.example.com/users&quot;;
    return restTemplate.postForLocation(url, newUser);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. PUT 요청&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;put() &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt; PUT 요청&lt;/b&gt;을 보냅니다. &lt;s&gt;&lt;b&gt;반환값&lt;/b&gt;&lt;/s&gt;이 없습니다(void).&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767795763229&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void updateUser(Long id, User updatedUser) {
    String url = &quot;https://api.example.com/users/{id}&quot;;
    restTemplate.put(url, updatedUser, id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. DELETE 요청&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;delete()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;DELETE 요청&lt;/b&gt;을 보냅니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;s&gt;&lt;b&gt;반환값&lt;/b&gt;&lt;/s&gt;이 없습니다(void).&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1767795802082&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public void deleteUser(Long id) {
    String url = &quot;https://api.example.com/users/{id}&quot;;
    restTemplate.delete(url, id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;5. 쿼리 파라미터 처리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;UriComponentsBuilder 사용&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767795863195&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public List&amp;lt;User&amp;gt; searchUsers(String name, Integer age) {
    String baseUrl = &quot;https://api.example.com/users/search&quot;;
    
    UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(baseUrl)
        .queryParam(&quot;name&quot;, name)
        .queryParam(&quot;age&quot;, age);
    
    String url = builder.toUriString();
    
    return restTemplate.getForObject(url, List.class);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;Map으로 쿼리 파라미터 전달 &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1767795893707&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public List&amp;lt;User&amp;gt; searchUsersWithMap(String name, Integer age) {
    String url = &quot;https://api.example.com/users/search?name={name}&amp;amp;age={age}&quot;;
    
    Map&amp;lt;String, Object&amp;gt; params = new HashMap&amp;lt;&amp;gt;();
    params.put(&quot;name&quot;, name);
    params.put(&quot;age&quot;, age);
    
    return restTemplate.getForObject(url, List.class, params);
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Connection Pool 설정하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; RestTemplate&lt;/b&gt;은 기본적으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;요청마다 새로운 연결(Socket)&lt;/b&gt;&lt;/span&gt;을 &lt;b&gt;생성&lt;/b&gt;하고 &lt;b&gt;닫는 방식을 사용&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 트래픽이 많은 서비스에서는 이 과정이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;오버헤드&lt;/b&gt;&lt;/span&gt;가 되어 &lt;b&gt;성능 저하&lt;/b&gt;를 일으킬 수 있습니다. 이때 &lt;b&gt;커넥션 풀(Connection Pool)&lt;/b&gt;을 사용하면 미리 만들어 놓은 연결을 &lt;b&gt;재사용하여 효율을 극대화&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;1. 의존성 추가&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커넥션 풀 기능을 제공하는 &lt;b&gt;Apache HttpClient 라이브러리&lt;/b&gt;를 build.gradle에 추가해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1767796425421&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
    // RestTemplate의 커넥션 풀 관리를 위한 라이브러리
    implementation 'org.apache.httpcomponents.client5:httpclient5'
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;2. RestTemplateConfig에 적용하기&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; RestTemplateBuilder&lt;/b&gt;를 사용하여 커넥션 풀이 적용된 &lt;b&gt;HttpComponentsClientHttpRequestFactory&lt;/b&gt;를 &lt;b&gt;설정&lt;/b&gt;합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1767796459251&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
            // 1. 커넥션 풀 설정 적용
            .requestFactory(this::clientHttpRequestFactory)
            .setConnectTimeout(Duration.ofSeconds(5))
            .setReadTimeout(Duration.ofSeconds(5))
            .build();
    }

    private ClientHttpRequestFactory clientHttpRequestFactory() {
        // Apache HttpClient 5 설정
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(100);             // 최대 전체 커넥션 수
        connectionManager.setDefaultMaxPerRoute(20);   // IP:Port 하나당 유지할 커넥션 수

        CloseableHttpClient httpClient = HttpClients.custom()
            .setConnectionManager(connectionManager)
            .build();

        return new HttpComponentsClientHttpRequestFactory(httpClient);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;성능 최적화를 위해 &lt;b data-index-in-node=&quot;12&quot; data-path-to-node=&quot;7&quot;&gt;Apache HttpClient 5&lt;/b&gt; 기반의 커넥션 풀을 적용한 설정입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;setMaxTotal&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션 전체에서 유지할 최대 커넥션 수를 100개로 제한하여 &lt;b&gt;리소스 고갈을 방지&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;setDefaultMaxPerRoute&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 호스트(예: API 서버 A)당 최대 커넥션을 20개로 설정해 특정 API 지연이 전체 시스템으로 전이되는 것을 막습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,2,0&quot;&gt;requestFactory&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RestTemplateBuilder에 이 설정을 주입함으로써, 매 요청마다 &lt;s&gt;&lt;b&gt;소켓을 새로 여는&lt;/b&gt;&lt;/s&gt; 대신 &lt;b&gt;풀에 있는 커넥션을 재사용&lt;/b&gt;하게 됩니다.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/Spring\Spring boot</category>
      <category>restTemplate</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/759</guid>
      <comments>https://pixx.tistory.com/759#entry759comment</comments>
      <pubDate>Wed, 7 Jan 2026 23:39:13 +0900</pubDate>
    </item>
    <item>
      <title>[Linux] iptables 기초 개념 정리</title>
      <link>https://pixx.tistory.com/758</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;523&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bu0q8O/dJMb9NIzaGm/5V5QkxW2vgNvlMkXzKVM4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bu0q8O/dJMb9NIzaGm/5V5QkxW2vgNvlMkXzKVM4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bu0q8O/dJMb9NIzaGm/5V5QkxW2vgNvlMkXzKVM4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbu0q8O%2FdJMb9NIzaGm%2F5V5QkxW2vgNvlMkXzKVM4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;432&quot; height=&quot;226&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1000&quot; data-origin-height=&quot;523&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿠버네티스를 사용하다가 k3s에서 사용하는 iptables와 firewalld가 iptables를 쓰는 것이 충돌하여 문제가 발생했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정에서 리눅스 네트워킹 개념이 부족하고, iptables의 개념이 부족하여 찾아보고 공부한 내용을 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IPTABLES 란❓&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기본 개념&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;iptables&lt;/b&gt;는 Linux 커널에 내장된 &lt;b&gt;네트워크 패킷 필터링 시스템(netfilter)&lt;/b&gt;을 제어하는 &lt;b&gt;사용자 공간 도구&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;즉, 실제 패킷 처리(차단, 허용 등)는 커널에서 수행하고, iptables는 그 &lt;b&gt;규칙을 설정하거나 제어하는 사용자 공간 프로그램&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;네트워크 패킷 필터링 시스템이란 ❓&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Netfilter&lt;/b&gt;는 리눅스 커널 내부에 포함된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 패킷 처리 프레임워크&lt;/b&gt;입니다. 즉, 리눅스 커널 안에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 패킷&lt;/b&gt;이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;들어오고&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;나가고&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;라우팅&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;되는 과정 중에 패킷을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;가로채서 검사&amp;middot;수정&amp;middot;차단&amp;middot;허용할 수 있는&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기능을 제공합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;iptables이란 ❓&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;규칙을 설정하고 관리&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;쉽게 말하면, Linux 시스템에 들어오고 나가는&amp;nbsp;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;네트워크 트래픽을 제어하는 방화벽&lt;/b&gt;&lt;/span&gt;입니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IPTABLES 핵심 구조&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. Table(테이블)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;iptables는 여러 개의 &lt;b&gt;테이블&lt;/b&gt;로 구성되어 있으며, 각 테이블은 특정 목적을 가집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 테이블&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 62.7907%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.3488%;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;filter&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;패킷 필터링 (허용/차단)&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;방화벽 규칙&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.3488%;&quot;&gt;&lt;b&gt;nat&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;네트워크 주소 변환&lt;/td&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;포트 포워딩, IP 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.3488%;&quot;&gt;&lt;b&gt;mangle&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;패킷 헤더 수정&lt;/td&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;QoS, TTL 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.3488%;&quot;&gt;&lt;b&gt;raw&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 30.1163%;&quot;&gt;연결 추적 예외 설정&lt;/td&gt;
&lt;td style=&quot;width: 22.2093%;&quot;&gt;고급 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. Chain(체인)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 테이블은 여러 개의 &lt;b&gt;체인&lt;/b&gt;을 가지고 있으며, 체인은 &lt;b&gt;패킷이 통과하는 경로&lt;/b&gt;를 나타냅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIGdJB/dJMb9MCS7cT/8OQghpvQNRygZtYiRXDsBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIGdJB/dJMb9MCS7cT/8OQghpvQNRygZtYiRXDsBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIGdJB/dJMb9MCS7cT/8OQghpvQNRygZtYiRXDsBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIGdJB%2FdJMb9MCS7cT%2F8OQghpvQNRygZtYiRXDsBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;708&quot; height=&quot;228&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;◽체인별 역할&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;INPUT&lt;/b&gt; : &lt;b&gt;외부에서 로컬 시스템으로 &lt;span style=&quot;color: #0593d3;&quot;&gt;들어오는&lt;/span&gt; 패킷 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: SSH 접속, 웹 서버 접근&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;OUTPUT&lt;/b&gt; : 로컬 시스템에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;외부로 나가는&lt;/b&gt;&lt;/span&gt;&amp;nbsp;패킷 처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 인터넷 브라우징, API 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FORWARD&lt;/b&gt; : 로컬 시스템을 &lt;b&gt;경유&lt;/b&gt;하는 패킷 처리 (라우터 역할)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: 방화벽, 게이트웨이, Kubernetes Pod 간 통신&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;PREROUTING&lt;/b&gt; : 패킷이 시스템에 도착한 &lt;u&gt;&lt;b&gt;직후&lt;/b&gt;&lt;/u&gt; (라우팅 전)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: DNAT (목적지 주소 변환)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;POSTROUTING&lt;/b&gt; : 패킷이 시스템을 떠나기 &lt;u&gt;&lt;b&gt;직전&lt;/b&gt;&lt;/u&gt;&amp;nbsp;(라우팅 후)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: SNAT (출발지 주소 변환), Masquerading&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. Rules (규칙)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;각 체인은 여러 개의 &lt;b&gt;규칙(Rule)&lt;/b&gt;을 가지고 있습니다. &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;규칙은 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;조건(Match)&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;동작(Target)&lt;/b&gt;&lt;/span&gt;으로 구성됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1760945571764&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;IF (조건) THEN (동작)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;조건 예시&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지 IP가 192.168.1.100&lt;/li&gt;
&lt;li&gt;목적지 포트가 80&lt;/li&gt;
&lt;li&gt;프로토콜이 TCP&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동작 예시&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ACCEPT&lt;/b&gt;: 허용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DROP&lt;/b&gt;: 조용히 차단&lt;/li&gt;
&lt;li&gt;&lt;b&gt;REJECT&lt;/b&gt;: 거부 메시지와 함께 차단&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LOG&lt;/b&gt;: 로그 기록&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;허용(ACCEPT)과 차단(DROP)의 의미&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 허용(ACCEPT) : 패킷을 통과시켜 목적지로 전달&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1760945607734&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;iptables -A INPUT -p tcp --dport 80 -j ACCEPT&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. 차단(DROP) : 패킷을 버립니다. 아무런 응답 X&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1760945613315&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;iptables -A INPUT -p tcp --dport 23 -j DROP&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. 명확한 차단(REJECT) : 패킷을 거부하고 즉시 거부 메시지를 전송&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1760945648086&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;iptables -A INPUT -p tcp --dport 23 -j REJECT&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IPTABLES 기본 명령어&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;규칙 조회&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1760945728555&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모든 규칙 확인
iptables -L -n -v

# nat 테이블 확인
iptables -t nat -L -n -v

# 줄 번호와 함께 확인
iptables -L --line-numbers&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템에 설정된&lt;b&gt; iptables 규칙을 확인&lt;/b&gt;합니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 모든 규칙 확인&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-L: 목록&lt;/li&gt;
&lt;li&gt;n: IP를 이름으로 변환 안 함&lt;/li&gt;
&lt;li&gt;-v: 상세 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;규칙 추가&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 방화벽&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;규칙을 체인에 추가&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1760945734343&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# SSH 허용 (22번 포트 TCP 트래픽 허용)
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 특정 IP 허용 (192.168.1.100에서 오는 모든 트래픽)
iptables -A INPUT -s 192.168.1.100 -j ACCEPT

# HTTP/HTTPS 허용
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 이미 연결된 세션 허용 (중요! 이게 없으면 응답 패킷이 차단됨)
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;-A&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;체인 끝에 규칙 추가 (Append)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;-p&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로토콜 지정 (tcp, udp, icmp 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;--dport&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적지 포트&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;-s&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;출발지 IP 주소&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;-j&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동작 지정 (ACCEPT, DROP, REJECT 등)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;규칙 삭제&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1760945739617&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 줄 번호로 삭제
iptables -D INPUT 3

# 모든 규칙 삭제
iptables -F&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기본 정책 설정&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1760945748322&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 모든 입력 차단
iptables -P INPUT DROP

# 모든 출력 허용
iptables -P OUTPUT ACCEPT&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;규칙 영구 저장&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;iptables 규칙은 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;재부팅 시 사라지므로&lt;/span&gt;&lt;/b&gt; &lt;u&gt;저장이 필요&lt;/u&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; CentOS/RHEL&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1760945810983&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 현재 규칙을 파일로 저장
iptables-save &amp;gt; /etc/sysconfig/iptables

# 부팅 시 자동 로드되도록 설정
systemctl enable iptables&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Ubuntu/Debian&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1760945835866&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# iptables-persistent 패키지 설치
apt-get install iptables-persistent

# 규칙 저장 (설치 중 자동으로 물어봄)
netfilter-persistent save&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Linux</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/758</guid>
      <comments>https://pixx.tistory.com/758#entry758comment</comments>
      <pubDate>Mon, 20 Oct 2025 16:37:27 +0900</pubDate>
    </item>
    <item>
      <title>[Springboot] Spring Boot에서 Service와 ServiceImpl 분리, 꼭 필요할까❓</title>
      <link>https://pixx.tistory.com/742</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1AqzH/btsMyTT86M1/V8DfRaXFjDMumvvn5knww0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1AqzH%2FbtsMyTT86M1%2FV8DfRaXFjDMumvvn5knww0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;163&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-end=&quot;161&quot; data-start=&quot;90&quot; data-ke-size=&quot;size16&quot;&gt;Spring 기반의 프로젝트를 살펴보면, &lt;b&gt;Service&lt;/b&gt;와 &lt;b&gt;ServiceImpl&lt;/b&gt;로 &lt;b&gt;나누어진 구조&lt;/b&gt;를 자주 접하게 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;342&quot; data-start=&quot;163&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;342&quot; data-start=&quot;163&quot; data-ke-size=&quot;size16&quot;&gt;그런데 저는 개인 프로젝트나 팀 프로젝트를 진행할 때에는 별도로 ServiceImpl을 두지 않고&lt;b&gt; 하나의 Service 클래스&lt;/b&gt;에서 &lt;b&gt;비즈니스 로직을 구현&lt;/b&gt;하곤 했습니다.&lt;/p&gt;
&lt;p data-end=&quot;342&quot; data-start=&quot;163&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;342&quot; data-start=&quot;163&quot; data-ke-size=&quot;size16&quot;&gt;하지만 실제 업무에서 코드를 분석하다 보니, 많은 프로젝트들이 &lt;b&gt;Service&lt;/b&gt;와 &lt;b&gt;ServiceImpl&lt;/b&gt;을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;분리&lt;/b&gt;&lt;/span&gt;하는 방식을 택하고 있었습니다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;424&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;424&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;이 글에서는 &lt;b&gt;왜 Service와 ServiceImpl을 분리하는지, 이러한 구조&lt;/b&gt;를 채택한 이유에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;424&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;424&quot; data-start=&quot;344&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;분리하는 이유는❓&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 유지보수성&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Service는 인터페이스로 정의하고, ServiceImpl에서 실제 구현을 담당하는 방식은 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;결합도&lt;/span&gt;를 낮추고 &lt;span style=&quot;color: #009a87;&quot;&gt;변경에 유연&lt;/span&gt;하게 대응&lt;/b&gt;할 수 있도록 도와줍니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;즉, 느슨한 결합으로 인해 수정이 용이합니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;417&quot; data-start=&quot;246&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;i&gt;UserService 인터페이스 &lt;/i&gt;가 있고, 이를 구현한 &lt;i&gt;UserServiceImpl &lt;/i&gt;이 있다고 가정해봅시다.&lt;/p&gt;
&lt;pre id=&quot;code_1740702944388&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface UserService {
    User findUserById(Long id);
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public User findUserById(Long id) {
        // 실제 로직
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;417&quot; data-start=&quot;246&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;만약 &lt;s&gt;&lt;b&gt;기존 UserServiceImpl을 변경&lt;/b&gt;&lt;/s&gt;하지 않고 &lt;b&gt;새로운 구현체&lt;/b&gt;(NewUserServiceImpl)로 &lt;u&gt;&lt;b&gt;교체&lt;/b&gt;&lt;/u&gt;하고 싶다면, 단순히 &lt;b&gt;스프링 빈(Bean) 설정을 변경&lt;/b&gt;하면 됩니다.&lt;/p&gt;
&lt;p data-end=&quot;417&quot; data-start=&quot;246&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;480&quot; data-start=&quot;419&quot; data-ke-size=&quot;size16&quot;&gt;이는 특히 &lt;b&gt;다양한 비즈니스 로직이 필요하거나, 구현체를 변경해야 할 가능성이 높은 경우&lt;/b&gt; 유리합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 테스트 용이성&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;869&quot; data-start=&quot;736&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스를 사용하면 단위 테스트 시 &lt;s&gt;실제 ServiceImpl을 사용&lt;/s&gt;하지 않고, &lt;b&gt;Mock 객체를 주입&lt;/b&gt;하여&lt;b&gt; 테스트를 수행&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;869&quot; data-start=&quot;736&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이렇게 하면 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;불필요한 의존성을 제거&lt;/span&gt;&lt;/b&gt;하고 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;테스트 속도를 향상&lt;/b&gt;&lt;/span&gt;시킬 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740703090476&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Mock
private UserService userService;

@Test
void testFindUser() {
    when(userService.findUserById(1L)).thenReturn(new User(1L, &quot;Test User&quot;));
    User user = userService.findUserById(1L);
    assertEquals(&quot;Test User&quot;, user.getName());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-end=&quot;869&quot; data-start=&quot;736&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;869&quot; data-start=&quot;736&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, Mockito를 사용하여 UserService의 &lt;b&gt;Mock 객체를 생성&lt;/b&gt;하면, UserServiceImpl의 내부 구현과&lt;b&gt; 무관&lt;/b&gt;하게 UserService를 사용하는 로직을 테스트할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. AOP 적용의 유연성&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt; 인터페이스 기반 구조&lt;/span&gt;&lt;/b&gt;는 &lt;b&gt;&lt;u&gt;AOP 적용을 더 유연&lt;/u&gt;하게&lt;/b&gt; 할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;222&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;과거 Spring 2.0에서는 &lt;b&gt;JDK Dynamic Proxy&lt;/b&gt;를 사용하여 AOP Proxy를 생성했으며, 이는 &lt;b&gt;&lt;u&gt;인터페이스를 반드시 구현&lt;/u&gt;해야만 AOP 적용이 가능&lt;/b&gt;한 방식이었습니다.&lt;/p&gt;
&lt;blockquote data-end=&quot;222&quot; data-start=&quot;0&quot; data-ke-style=&quot;style2&quot;&gt;즉, &lt;br /&gt;&lt;i&gt;@Transactional(트랜잭션 관리), @Cacheable(캐싱), @Logging(로깅)&lt;/i&gt; 등 과 같은 &lt;b&gt;AOP 기능&lt;/b&gt;을 사용하려면 &lt;br /&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;인터페이스-구현체 구조가 필수적&lt;/b&gt;&lt;/span&gt;이었으며, 자연스럽게 &lt;b&gt;Service&lt;/b&gt;와 &lt;b&gt;ServiceImpl&lt;/b&gt;로 나누는 패턴이 일반화되었습니다.&lt;/blockquote&gt;
&lt;p data-end=&quot;222&quot; data-start=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;400&quot; data-start=&quot;224&quot; data-ke-size=&quot;size16&quot;&gt;그러나 Spring 3.2 / Spring Boot 1.4 이후부터는 &lt;u&gt;&lt;b&gt;CGLIB가 기본적으로 포함&lt;/b&gt;&lt;/u&gt;되면서, &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;클래스 기반으로도 AOP 프록시를 생성&lt;/span&gt;할 수 있게 되었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;400&quot; data-start=&quot;224&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;덕분에 이제는 &lt;b&gt;인터페이스 없이도 AOP 적용이 가능&lt;/b&gt;하며, 과거처럼 인터페이스-구현체 구조를 강제할 필요는 없어졌습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. 의존성 역전(DIP)의 실현&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;고수준 모듈(컨트롤러)이 저수준 모듈(서비스 구현체)에 의존하지 않고, 둘 다 &lt;u&gt;&lt;b&gt;추상화(인터페이스)에 의존&lt;/b&gt;&lt;/u&gt;하게 합니다.&lt;/li&gt;
&lt;li&gt;이를 통해 &quot;구현보다 인터페이스에 의존하라&quot;는 객체지향 설계 원칙을 따릅니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;분리하는 이유는❓&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 불필요한 추상화&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;230&quot; data-start=&quot;136&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스는 &lt;b&gt;&lt;u&gt;여러 개의 구현체&lt;/u&gt;가 존재할 가능성이 있을 때 의미가 있습니다&lt;/b&gt;. 그러나 하지만 &lt;b&gt;대부분의 서비스 계층에서는 &lt;u&gt;하나의 구현체만 존재&lt;/u&gt;&lt;/b&gt;하는 경우가 많습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1740710300729&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface UserService {
    User findUserById(Long id);
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public User findUserById(Long id) {
        return userRepository.findById(id).orElseThrow();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 구현체가 하나뿐이라면, 굳이 인터페이스를 &lt;s&gt;&lt;b&gt;분리할 필요&lt;/b&gt;&lt;/s&gt;가 없습니다. 이런 경우, &lt;b&gt;직접 클래스를 사용하면 코드가 간결해지고 유지보수도 쉬워집니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740710320112&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class UserService {
    public User findUserById(Long id) {
        return userRepository.findById(id).orElseThrow();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;즉, &lt;s&gt;1:1로 구현&lt;/s&gt;할 것이라면 굳이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;인터페이스를 분리&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;할 필요가 없다고 생각합니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 코드의 가독성과 유지보수성 저하&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-end=&quot;814&quot; data-start=&quot;774&quot; data-ke-size=&quot;size16&quot;&gt;인터페이스를 분리하면 &lt;b&gt;코드의 가독성이 오히려 떨어질 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;924&quot; data-start=&quot;815&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;852&quot; data-start=&quot;815&quot;&gt;인터페이스와 구현체를 왔다 갔다 하면서 코드를 확인해야 함.&lt;/li&gt;
&lt;li data-end=&quot;885&quot; data-start=&quot;853&quot;&gt;단순한 비즈니스 로직에도 &lt;b&gt;불필요한 추상화&lt;/b&gt;가 추가됨.&lt;/li&gt;
&lt;li data-end=&quot;924&quot; data-start=&quot;886&quot;&gt;&lt;b&gt;작은 규모의 프로젝트&lt;/b&gt;에서는 &lt;u&gt;&lt;b&gt;오버엔지니어링&lt;/b&gt;&lt;/u&gt;이 될 가능성이 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. 테스트 시 복잡성 증가&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;Mocking을 활용한 단위 테스트는&lt;s&gt;&lt;b&gt; Service-Impl 구조&lt;/b&gt;&lt;/s&gt; 없이도 충분히 가능합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740710411673&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Mock
private UserRepository userRepository;

@InjectMocks
private UserService userService; // 인터페이스 없이도 Mock 주입 가능

@Test
void testFindUser() {
    when(userRepository.findById(1L)).thenReturn(Optional.of(new User(1L, &quot;Test User&quot;)));
    User user = userService.findUserById(1L);
    assertEquals(&quot;Test User&quot;, user.getName());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스 없이도 테스트는 문제없이 수행될 수 있으며, 오히려 단순한 구조를 유지할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. DI(의존성 주입)와 충돌❌&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring의 @Service는 기본적으로 &lt;b&gt;클래스 기반의 빈 등록을 지원&lt;/b&gt;하기 때문에, 인터페이스 없이도 &lt;b&gt;DI(의존성 주입)에는 아무런 문제가 없습니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740710480360&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class UserService {
    private final UserRepository userRepository;

    @Autowired
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1840&quot; data-start=&quot;1793&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;s&gt;&lt;b&gt;인터페이스&lt;/b&gt;&lt;/s&gt; 없이도 Spring의&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; IoC 컨테이너는 정상적으로 동작&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-end=&quot;60&quot; data-start=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;당연한 이야기지만, &lt;b&gt;프로젝트의 규모&lt;/b&gt;나 &lt;b&gt;상황&lt;/b&gt;을 고려하여 선택하는 것이 최선입니다.&lt;/p&gt;
&lt;p data-end=&quot;60&quot; data-start=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;60&quot; data-start=&quot;10&quot; data-ke-size=&quot;size16&quot;&gt;객체지향프로그래밍(OOP) 관점에서 보았을 땐 인터페이스는 다형성 또는 SOLID원칙의 &lt;b&gt;OCP(계방폐쇄원칙)&lt;/b&gt;때문에 사용합니다. 그러나 &lt;u&gt;&lt;b&gt;대부분의 경우 Service는 1:1 구조&lt;/b&gt;&lt;/u&gt;를 가지며, 하나의 Service가 여러 개의 ServiceImpl을 가지는 &lt;s&gt;&lt;b&gt;1:N 관계&lt;/b&gt;&lt;/s&gt;가 아닙니다.&lt;/p&gt;
&lt;p data-end=&quot;224&quot; data-start=&quot;62&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;즉, 다형성을 적극적으로 활용할 필요가 없는 경우가 많으므로&lt;b&gt;, 불필요한 추상화&lt;/b&gt;는 오히려 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;복잡도를 증가&lt;/b&gt;&lt;/span&gt;시킬 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;224&quot; data-start=&quot;62&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-only-node=&quot;&quot; data-is-last-node=&quot;&quot; data-end=&quot;302&quot; data-start=&quot;226&quot; data-ke-size=&quot;size16&quot;&gt;따라서 특별한 이유가 없다면 &lt;b&gt;단순한 구조를 유지&lt;/b&gt;하는 것이 바람직하며, &lt;b&gt;필요할 때만 인터페이스를 도입&lt;/b&gt;하는 것이 합리적인 접근이라고 생각이 듭니다.&lt;/p&gt;</description>
      <category>Framework/Spring\Spring boot</category>
      <category>Service</category>
      <category>ServiceImpl</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/742</guid>
      <comments>https://pixx.tistory.com/742#entry742comment</comments>
      <pubDate>Fri, 28 Feb 2025 09:54:18 +0900</pubDate>
    </item>
    <item>
      <title>[SpringBoot] ObjectMapper와 직렬화/역직렬화</title>
      <link>https://pixx.tistory.com/740</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmR2sL/btsMx8w7MaB/yqNrZhrJ87QtGw2bQtMY20/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmR2sL/btsMx8w7MaB/yqNrZhrJ87QtGw2bQtMY20/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmR2sL/btsMx8w7MaB/yqNrZhrJ87QtGw2bQtMY20/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmR2sL%2FbtsMx8w7MaB%2FyqNrZhrJ87QtGw2bQtMY20%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;310&quot; height=&quot;163&quot; data-filename=&quot;springboot.png&quot; data-origin-width=&quot;310&quot; data-origin-height=&quot;163&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring boot를 사용한 백엔드 개발을 하다보면 자연스럽게 &lt;b&gt;JSON데이터를 객체로 매핑&lt;/b&gt;해야하는 경우가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한&amp;nbsp; &lt;b&gt;Java 객체&lt;/b&gt;와 &lt;b&gt;JSON 간의 변환 작업&lt;/b&gt;, 즉 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;'직렬화(Serialization)'&lt;/b&gt;&lt;/span&gt;와&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt; '역직렬화(Deserialization)'&lt;/b&gt;&lt;/span&gt;는 매우 중요한 과정인데, 본 글에서는 이 과정을 효율적으로 처리하기 위한 강력한 도구인 &lt;b&gt;ObjectMapper&lt;/b&gt;에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;직렬화 &amp;amp; 역직렬화란❓&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqraXH/btsMzeDgUzO/C36sBAZHOXKECREvETagZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqraXH/btsMzeDgUzO/C36sBAZHOXKECREvETagZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqraXH/btsMzeDgUzO/C36sBAZHOXKECREvETagZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqraXH%2FbtsMzeDgUzO%2FC36sBAZHOXKECREvETagZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;607&quot; height=&quot;270&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;직렬화(Serialization) &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;직렬화는 &lt;b&gt;객체&lt;/b&gt;의 상태를 &lt;b&gt;바이트 스트림&lt;/b&gt;이나&lt;b&gt; 다른 형식(JSON, XML 등)&lt;/b&gt;으로 &lt;b&gt;변환하는 과정&lt;/b&gt;입니다. 이 과정을 통해 &lt;b&gt;메모리&lt;/b&gt;에 존재하는 &lt;b&gt;객체를 외부에서 사용할 수 있는 형태로 변환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 목적:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크를 통한 데이터 전송&lt;/li&gt;
&lt;li&gt;파일 시스템에 데이터 저장&lt;/li&gt;
&lt;li&gt;다른 시스템이나 언어와의 데이터 교환&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;역직렬화(Deserialization) &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;역직렬화는 직렬화의 &lt;b&gt;반대 과정&lt;/b&gt;으로, &lt;b&gt;바이트 스트림&lt;/b&gt;이나 &lt;b&gt;다른 형식(JSON, XML 등)&lt;/b&gt;의 데이터를 다시 &lt;u&gt;&lt;b&gt;객체로 변환하는 과정&lt;/b&gt;&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주요 목적:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전송받은 데이터를 응용 프로그램에서 사용 가능한 객체로 복원&lt;/li&gt;
&lt;li&gt;저장된 데이터를 메모리에 로드&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Spring에서의 직렬화 &amp;amp; 역직렬화 : ObjectMapper&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring(Java)에서 직렬화는 일반적으로 &lt;b&gt;&lt;u&gt;Jackson 라이브러리&lt;/u&gt;&lt;/b&gt;를 활용합니다. 이 중 Jackson 라이브러리의 &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;ObjectMapper&lt;/span&gt;&lt;/b&gt;라는 클래스가 있는데 이 클래스가&lt;b&gt; 직렬화를 처리&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot는 기본적으로 &lt;b&gt;Jackson을 내장&lt;/b&gt;하고 있으며, 이를 활용하여 JSON 데이터를 Java 객체로 변환하거나, Java 객체를 JSON으로 변환할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;client에서 보낸 &lt;b&gt;Json 데이터&lt;/b&gt;를&lt;b&gt; DTO 객체&lt;/b&gt;로 받으면, Spring에서 알아서 Json의 Key값과 DTO 객체의 멤버변수를 &lt;b&gt;매칭&lt;/b&gt;해서 Value값을 &lt;u&gt;&lt;b&gt;DTO 객체에 자동으로 대입&lt;/b&gt;&lt;/u&gt;해주었는데, 그 과정을 바로 SpringBoot의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;color: #ff0000;&quot;&gt;Object Mapper&lt;/span&gt;&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #212529; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클래스가 해주게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;ObjectMapper란❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;ObjectMapper는 &lt;b&gt;Jackson 라이브러리의 핵심 클래스&lt;/b&gt;로, &lt;b&gt;Java 객체와 JSON 데이터 간의 변환을 담당&lt;/b&gt;합니다. 객체 지향 프로그래밍과 데이터 교환 형식 간의 다리 역할을 수행합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt; 주요 기능:&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 직렬화(Serialization) &lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740629263986&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String json = objectMapper.writeValueAsString(myObject);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; Java 객체&lt;/b&gt;를&lt;b&gt; JSON 문자열로 변환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. 역직렬화(Deserialization)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740629298450&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;MyClass obj = objectMapper.readValue(jsonString, MyClass.class);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON 문자열을 &lt;b&gt;Java 객체로 변환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. 다양한 입출력 지원 &lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740629368026&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;objectMapper.writeValue(new File(&quot;data.json&quot;), myObject);
MyClass obj = objectMapper.readValue(new File(&quot;data.json&quot;), MyClass.class);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열뿐만 아니라 &lt;i&gt;&lt;b&gt;파일, 스트림, URL&lt;/b&gt;&lt;/i&gt; 등 다양한 소스에서 읽고 쓸 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt;&amp;nbsp;&lt;/span&gt;트리 모델 지원&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740629406522&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;JsonNode rootNode = objectMapper.readTree(jsonString);
String name = rootNode.get(&quot;name&quot;).asText();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JSON을 &lt;b&gt;트리 구조&lt;/b&gt;로 처리할 수 있는 JsonNode API를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;ObjectMapper 커스텀&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 제공되는 ObjectMapper를 사용해도 되지만, 커스텀이 필요한 경우가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;커스터마이징할 상황:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;날짜/시간 형식 지정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 JSON에서는 날짜를 타임스탬프로 표현하지만, &quot;yyyy-MM-dd HH:mm:ss&quot;와 같은 &lt;b&gt;특정 형식으로 직렬화/역직렬화하고 싶은 경우&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;null 값 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;null 값을 가진 필드를 JSON에서 &lt;b&gt;제외&lt;/b&gt;하거나&lt;b&gt; 특정 방식으로 처리&lt;/b&gt;해야 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;알 수 없는 속성 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 버전 호환성을 위해 알 수 없는 JSON 속성이 있어도&lt;s&gt;&lt;b&gt; 예외가 발생&lt;/b&gt;&lt;/s&gt;하지 않도록 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Enum 값 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Enum 값을 단순 이름이 아닌 다른 방식(예: toString() 메소드 결과)으로 직렬화/역직렬화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명명 전략 적용&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java의 camelCase를 JSON의 snake_case로 변환하는 등의 필드 이름 전략 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;특정 타입 변환기 등록&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;복잡한 객체 타입을 위한 커스텀 직렬화/역직렬화 로직 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;모듈 등록&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Java 8 날짜/시간 타입 지원이나 추가 데이터 타입 처리를 위한 모듈 등록&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;민감한 데이터를 자동으로 마스킹하거나 제외시키는 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능 최적화&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 기능을 비활성화하여 성능을 향상시키는 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다형성 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상속 관계에 있는 클래스들을 적절하게 처리하기 위한 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 외에도 자신의 프로젝트에 맞는 커스텀 ObjectMapper가 필요한 경우가 있을 것 입니다. 이러한 커스텀이 필요한 경우를 살펴보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시: 명명 전략 적용 (camelCase &amp;harr; snake_case) &lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1740633333419&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class JacksonConfig {
    
    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        var objectMapper = new ObjectMapper();
        
        // 모듈 등록
        objectMapper.registerModule(new Jdk8Module());  // Java 8 타입 지원
        objectMapper.registerModule(new JavaTimeModule());  // Java 시간 관련 타입 지원
        
        // 기본 설정
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);  // 날짜를 타임스탬프가 아닌 ISO-8601 형식으로
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);  // 알 수 없는 속성 무시
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);  // 빈 객체 직렬화 허용
        
        // 명명 전략 설정 (camelCase -&amp;gt; snake_case)
        objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy());
        
        return objectMapper;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SnakeCaseStrategy를 적용하여 Java의 &lt;b&gt;camelCase&lt;/b&gt; 필드명(예: firstName)을 JSON의 &lt;b&gt;snake_case&lt;/b&gt; 형식(예: first_name)으로 변환합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런식으로 default로 제공되는 objcetMapper 이외에 추가적인 커스텀이 필요한 경우 &lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;ObjectMapper&lt;/b&gt;를 &lt;b&gt;커스텀&lt;/b&gt;하여 &lt;b&gt;Bean&lt;/b&gt;에다 등록하여 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Framework/Spring\Spring boot</category>
      <category>ObjectMapper</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/740</guid>
      <comments>https://pixx.tistory.com/740#entry740comment</comments>
      <pubDate>Thu, 27 Feb 2025 14:25:18 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커 네트워크 모드 알아보기 (bridge, host, none)</title>
      <link>https://pixx.tistory.com/733</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__20_-removebg-preview.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dr9PpJ/btsMugO3uLR/euPa44RhmLxUtDBIbvzwU0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dr9PpJ/btsMugO3uLR/euPa44RhmLxUtDBIbvzwU0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dr9PpJ/btsMugO3uLR/euPa44RhmLxUtDBIbvzwU0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdr9PpJ%2FbtsMugO3uLR%2FeuPa44RhmLxUtDBIbvzwU0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;238&quot; height=&quot;212&quot; data-filename=&quot;다운로드__20_-removebg-preview.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커(Docker)는 &lt;b&gt;컨테이너화된 애플리케이션&lt;/b&gt;을 위한 &lt;b&gt;다양한 네트워크 모드를 제공&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 &lt;b&gt;네트워크 모드&lt;/b&gt;는 &lt;b&gt;서로 다른 사용 사례&lt;/b&gt;와 &lt;b&gt;요구사항&lt;/b&gt;을 충족시키기 위해 설계되었습니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1740292823739&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker network ls&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 ls 명령어로 현재 네트워크 목록을 확인하면 아래와 같이 3가지의 네트워크 모드가 존재하는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cO0a7q/btsMsVkOX4O/4cB1aq08QgRtnDuUxdVbM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cO0a7q/btsMsVkOX4O/4cB1aq08QgRtnDuUxdVbM0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cO0a7q/btsMsVkOX4O/4cB1aq08QgRtnDuUxdVbM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcO0a7q%2FbtsMsVkOX4O%2F4cB1aq08QgRtnDuUxdVbM0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;170&quot; data-origin-width=&quot;742&quot; data-origin-height=&quot;252&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;bridge, host, none&lt;/b&gt; 이외에도 추가적으로 &lt;b&gt;Ipvlan,Macvlan&lt;/b&gt;도 존재하는 데 본 글에서는 이 도커의 &lt;b&gt;주요 네트워크 모드&lt;/b&gt;들을 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Bridge 네트워크 모드란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Bridge 네트워크는 도커의 &lt;b&gt;기본 네트워크 모드&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도커의 브릿지 네트워크 모드는 &lt;b&gt;컨테이너들이 서로 통신&lt;/b&gt;할 수 있게 해주는 &lt;b&gt;가상의 네트워크 브릿지를 생성&lt;/b&gt;합니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;bridge.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;1076&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byqW3R/btsMuLOzZXA/7CJ9eD1ePPtlxatys6dPD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byqW3R/btsMuLOzZXA/7CJ9eD1ePPtlxatys6dPD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byqW3R/btsMuLOzZXA/7CJ9eD1ePPtlxatys6dPD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyqW3R%2FbtsMuLOzZXA%2F7CJ9eD1ePPtlxatys6dPD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;1076&quot; data-filename=&quot;bridge.png&quot; data-origin-width=&quot;1154&quot; data-origin-height=&quot;1076&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 그림에서 볼 수 있듯이 &lt;b&gt;&quot;mybridge&quot;라는 브릿지&lt;/b&gt;가 &lt;b&gt;여러 컨테이너들을 &lt;span style=&quot;color: #ee2323;&quot;&gt;연결&lt;/span&gt;&lt;/b&gt;하는 &lt;u&gt;&lt;b&gt;중간 다리 역할&lt;/b&gt;&lt;/u&gt;을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;브릿지 네트워크의 중요한 &lt;b&gt;특징&lt;/b&gt; 중 하나는 &lt;b&gt;외부 네트워크와의 통신&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지에서 볼 수 있듯이, &lt;b&gt;호스트 시스템&lt;/b&gt;은 &lt;b&gt;192.168.1.2&lt;/b&gt;라는 IP를 가지고 있으며, 이를 통해 컨테이너들이 &lt;b&gt;외부 네트워크와 통신&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, web 컨테이너의 5000번 포트는 호스트의 8000번 포트와 &lt;b&gt;매핑&lt;/b&gt;되어 있어,&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 외부에서 접근이 가능&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;b&gt;브릿지 네트워크 모드&lt;/b&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;컨테이너 간의 격리된 통신 환경을 제공&lt;/b&gt;&lt;/span&gt;하면서도, 필요한 경우 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;외부와의 통신도 가능&lt;/b&gt;&lt;/span&gt;하게 만드는 유연한 네트워킹 솔루션입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;도커 브릿지 네트워크 모드의 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;679&quot; data-start=&quot;646&quot;&gt;기본적으로 컨테이너 간 &lt;u&gt;&lt;b&gt;격리된 네트워크&lt;/b&gt;&lt;/u&gt;를 제공&lt;/li&gt;
&lt;li data-end=&quot;738&quot; data-start=&quot;680&quot;&gt;&quot;docker network create&quot; 명령어로 &lt;b&gt;사용자 정의 브리지 네트워크&lt;/b&gt; 생성 가능&lt;/li&gt;
&lt;li data-end=&quot;780&quot; data-start=&quot;739&quot;&gt;&quot;-p 옵션&quot;을 사용하면 컨테이너&lt;b&gt; 포트&lt;/b&gt;를 &lt;b&gt;호스트와 연결 가능&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;사용 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&amp;nbsp;기본 브릿지 네트워크 사용&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740293627811&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 기본 브릿지 네트워크로 nginx 컨테이너 실행
docker run -d nginx

# 포트 매핑과 함께 실행
docker run -d -p 8080:80 nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 명령어를 실행하면 &lt;b&gt;nginx 컨테이너&lt;/b&gt;가 &lt;b&gt;생성&lt;/b&gt;되며 &lt;u&gt;&lt;b&gt;자동&lt;/b&gt;&lt;/u&gt;으로 &lt;b&gt;기본 브릿지 네트워크('docker0')에 연결&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 명령어는 단순히 &lt;b&gt;백그라운드에서 컨테이너를 실행&lt;/b&gt;하는 반면, 두 번째 명령어는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;포트 매핑을 추가&lt;/b&gt;&lt;/span&gt;하여 호스트의 &lt;b&gt;8080 포트&lt;/b&gt;를 통해&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;외부에서 nginx 웹 서버(컨테이너의 80 포트)에 접근&lt;/b&gt;&lt;/u&gt;할 수 있게 됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt; 사용자 정의 브릿지 네트워크 생성 및 사용&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1740293714628&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 새로운 브릿지 네트워크 생성
docker network create myapp-network

# 네트워크에 컨테이너 연결
docker run -d --name backend --network myapp-network mongodb
docker run -d --name frontend --network myapp-network -p 3000:3000 nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 명령어를 실행하면 먼저 &lt;b&gt;'myapp-network'&lt;/b&gt;라는 &lt;u&gt;&lt;b&gt;사용자 정의 브릿지 네트워크가 생성&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그 다음 &lt;b&gt;MongoDB 컨테이너&lt;/b&gt;와 &lt;b&gt;Nginx 컨테이너&lt;/b&gt;가 이 &lt;b&gt;네트워크에 연결&lt;/b&gt;되어 &lt;b&gt;실행&lt;/b&gt;되며, 두 컨테이너는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;서로 통신이 가능&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;frontend 컨테이너는 포트 매핑(3000:3000)이 설정되어 외부에서 접근할 수 있으며, --name 옵션으로 지정된 이름을 통해 컨테이너들은 &lt;b&gt;서로를 찾을 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;언제 사용하는 것이 좋을까❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;일반적인 &lt;b&gt;MSA환경&lt;/b&gt;에서&lt;u&gt;&lt;b&gt; 컨테이너 간 통신&lt;/b&gt;&lt;/u&gt;이 필요할 때
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 독립적인 서비스(웹 서버, API 서버, 데이터베이스 등)가 서로 통신해야 하는 상황&lt;/li&gt;
&lt;li&gt;각 서비스를 독립적으로 관리하면서도 안전한 네트워크 통신이 필요한 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포트 바인딩&lt;/b&gt;을 통해 &lt;u&gt;&lt;b&gt;외부에서 컨테이너에 접근&lt;/b&gt;&lt;/u&gt;할 때 (-p 8080:80)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 서버나 API 서버를 외부에 노출시켜야 하는 경우&lt;/li&gt;
&lt;li&gt;특정 포트만 선택적으로 외부 접근을 허용하고 싶을 때&lt;/li&gt;
&lt;li&gt;호스트의 포트를 통해 컨테이너의 서비스에 안전하게 접근해야 할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Host 네트워크 모드란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;호스트 네트워크 모드&lt;/b&gt;는 &lt;b&gt;컨테이너&lt;/b&gt;가 &lt;u&gt;&lt;b&gt;Host의 네트워크를 직접 사용&lt;/b&gt;&lt;/u&gt;하는 모드입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;즉, Host 컴퓨터와 &lt;b&gt;동일한 네트워크&lt;/b&gt; 환경 사용&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 &lt;b&gt;호스트의 네트워크 네임스페이스를 그대로 사용&lt;/b&gt;하기 때문에 &lt;b&gt;별도의 네트워크 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;격리&lt;/s&gt;&lt;/span&gt;&lt;/b&gt;가 없습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;도커 Host 네트워크 모드의 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너가 &lt;b&gt;호스트의 네트워크를 &lt;u&gt;직접 사용&lt;/u&gt;&lt;/b&gt;하므로 &lt;b&gt;네트워크 성능이 가장 좋음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;s&gt;&lt;b&gt;포트 매핑이 필요 없음&lt;/b&gt;&lt;/s&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 &lt;s&gt;격리&lt;/s&gt;가 되지 않아&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;보안상 취약&lt;/b&gt;&lt;/span&gt;할 수 있음&lt;/li&gt;
&lt;li&gt;호스트의 네트워크 인터페이스를 &lt;b&gt;직접 사용&lt;/b&gt;하므로 &lt;b&gt;네트워크 관련 설정이 &lt;span style=&quot;color: #006dd7;&quot;&gt;단순화&lt;/span&gt;&lt;/b&gt;됨&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;사용 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1740294360915&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 호스트 네트워크 모드로 nginx 실행
docker run -d --network host nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어를 실행하면 &lt;b&gt;nginx 컨테이너&lt;/b&gt;가 &lt;b&gt;호스트의 네트워크를 &lt;u&gt;직접 사용&lt;/u&gt;&lt;/b&gt;하게 되어, &lt;b&gt;&lt;s&gt;별도의 포트 매핑&lt;/s&gt; 없이&lt;/b&gt; 호스트의 80포트로 &lt;b&gt;직접 접근이 가능&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;언제 사용하는 것이 좋을까❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;네트워크 성능&lt;/b&gt;이 중요한 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대용량 데이터 처리가 필요한 서비스&lt;/li&gt;
&lt;li&gt;지연 시간에 민감한 애플리케이션&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;호스트 수준&lt;/b&gt;의 네트워크 기능이 필요한 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크 모니터링 도구&lt;/li&gt;
&lt;li&gt;호스트 네트워크 스택을 &lt;b&gt;직접 조작&lt;/b&gt;해야 하는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컨테이너 간 네트워크 격리가 &lt;s&gt;필요 없는&lt;/s&gt;&lt;/b&gt; &lt;b&gt;단일 컨테이너 환경&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; None 네트워크 모드란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;None 네트워크 모드는 말 그대로 컨테이너의 &lt;u&gt;&lt;b&gt;모든 네트워크를 &lt;span style=&quot;color: #ee2323;&quot;&gt;비활성화&lt;/span&gt;&lt;/b&gt;&lt;/u&gt;하는 모드입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;450&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/er2FWY/btsMttg9l82/fu3OE2KMxCKo3HqWdXxf80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/er2FWY/btsMttg9l82/fu3OE2KMxCKo3HqWdXxf80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/er2FWY/btsMttg9l82/fu3OE2KMxCKo3HqWdXxf80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fer2FWY%2FbtsMttg9l82%2Ffu3OE2KMxCKo3HqWdXxf80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;321&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;450&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨테이너가 &lt;u&gt;&lt;b&gt;완전히 격리된 네트워크 환경&lt;/b&gt;&lt;/u&gt;에서 실행되며, &lt;b&gt;외부와의 모든 네트워크 연결이 &lt;span style=&quot;color: #ee2323;&quot;&gt;차단&lt;/span&gt;&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;도커 None 네트워크 모드의 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너가 &lt;b&gt;네트워크 인터페이스를 가지지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;외부와의 모든 네트워크 &lt;u&gt;통신이 불가능&lt;/u&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;u&gt;&lt;b&gt;최대한의 네트워크 격리&lt;/b&gt;&lt;/u&gt;를 제공&lt;/li&gt;
&lt;li&gt;컨테이너&lt;span style=&quot;color: #f89009;&quot;&gt; 내부&lt;/span&gt;에서는 &lt;b&gt;localhost(loopback)만 사용 가능&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;사용 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1740294752778&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# None 네트워크 모드로 컨테이너 실행
docker run -d --network none alpine&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어를 실행하면 alpine 컨테이너는 &lt;u&gt;&lt;b&gt;완전히 격리된 네트워크 환경&lt;/b&gt;에서 실행&lt;/u&gt;되며, &lt;b&gt;외부와의 어떠한 네트워크 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;통신도 불가능&lt;/s&gt;&lt;/span&gt;&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;언제 사용하는 것이 좋을까❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;최대한의 보안&lt;/b&gt;이 필요한 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;민감한 데이터를 처리하는 배치 작업&lt;/li&gt;
&lt;li&gt;네트워크가 전혀 필요 없는 계산 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 접근을 완전히 차단&lt;/b&gt;해야 하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;보안 정책상 격리가 필요한 작업&lt;/li&gt;
&lt;li&gt;로컬에서만 실행되는 프로세스&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;IPvlan과 Macvlan이란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IPvlan과 Macvlan은 컨테이너에게 &lt;b&gt;호스트의 네트워크 인터페이스에 &lt;u&gt;직접 연결할 수 있는 권한&lt;/u&gt;&lt;/b&gt;을 주는 고급 네트워크 모드입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Macvlan 모드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1740295060338&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Macvlan 네트워크 생성
docker network create -d macvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 macvlan-net

# Macvlan 네트워크로 컨테이너 실행
docker run --network macvlan-net -d nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어에서 알 수 있듯이 &lt;b&gt;Macvlan&lt;/b&gt;은 물리적 &lt;u&gt;&lt;b&gt;네트워크 인터페이스(eth0)에 직접 연결&lt;/b&gt;&lt;/u&gt;되며, 각 컨테이너에 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;고유한 MAC 주소&lt;/b&gt;&lt;/span&gt;와 &lt;b&gt;IP 주소&lt;/b&gt;를 &lt;b&gt;할당&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; subnet&lt;/b&gt;과 &lt;b&gt;gateway&lt;/b&gt;를 &lt;b&gt;지정&lt;/b&gt;하여 &lt;b&gt;독립적인 네트워크 구성이 가능&lt;/b&gt;하며, 이를 통해 컨테이너가 마치 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;물리적 네트워크에 직접 연결된 것처럼 동작&lt;/b&gt;&lt;/span&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 특히 컨테이너가 물리 네트워크와 직접적인 통신이 필요한 경우나 특정 IP/MAC 주소가 필요한 레거시 애플리케이션을 컨테이너화할 때 유용합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;IPvlan 모드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1740295231958&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# IPvlan L2 모드 네트워크 생성
docker network create -d ipvlan \
  --subnet=192.168.1.0/24 \
  --gateway=192.168.1.1 \
  -o parent=eth0 ipvlan-net

# IPvlan 네트워크로 컨테이너 실행
docker run --network ipvlan-net -d nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 명령어에서 알 수 있듯이 &lt;b&gt;IPvlan&lt;/b&gt;은 &lt;b&gt;Macvlan&lt;/b&gt;과 유사하게 &lt;b&gt;물리적 네트워크 인터페이스(eth0)에 연결&lt;/b&gt;되지만, 모든 컨테이너가 &lt;b&gt;호스트의 MAC 주소를 &lt;span style=&quot;color: #006dd7;&quot;&gt;공유&lt;/span&gt;&lt;/b&gt;하면서 &lt;u&gt;&lt;b&gt;각자 고유한 IP 주소만을 할당&lt;/b&gt;&lt;/u&gt;받습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;L2&lt;/b&gt; 또는 &lt;b&gt;L3 모드&lt;/b&gt;로 동작할 수 있으며, &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;-d ipvlan 옵션&lt;/b&gt;&lt;/span&gt;을 통해 &lt;b&gt;IPvlan 드라이버&lt;/b&gt;를 지정합니다. &lt;b&gt;subnet&lt;/b&gt;과 &lt;b&gt;gateway&lt;/b&gt; 설정으로 &lt;b&gt;네트워크 구성&lt;/b&gt;이 가능합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 &lt;b&gt;MAC 주소 제한&lt;/b&gt;이 있는 환경이나 &lt;b&gt;더 나은 확장성&lt;/b&gt;이 필요한 경우에 &lt;b&gt;Macvlan&lt;/b&gt;의 &lt;b&gt;대안으로 사용&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;각 네트워크 모드의 차이점&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;network-mode.webp&quot; data-origin-width=&quot;2656&quot; data-origin-height=&quot;1634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oft6U/btsMtomuw9g/OlklVdohKP8KzliwKx7VV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oft6U/btsMtomuw9g/OlklVdohKP8KzliwKx7VV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oft6U/btsMtomuw9g/OlklVdohKP8KzliwKx7VV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Foft6U%2FbtsMtomuw9g%2FOlklVdohKP8KzliwKx7VV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;431&quot; data-filename=&quot;network-mode.webp&quot; data-origin-width=&quot;2656&quot; data-origin-height=&quot;1634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지처럼 Docker의 네트워크 모드는 &lt;b&gt;Bridge&lt;/b&gt;, &lt;b&gt;None&lt;/b&gt;, &lt;b&gt;Host&lt;/b&gt; 세 가지 방식으로 나눌 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Bridge 모드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;docker0라는 &lt;b&gt;가상 브릿지&lt;/b&gt;를 통해 컨테이너들이 연결되며, &lt;b&gt;각각 독립된 IP(172.17.0.x)를 할당받아 통신&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt; None 모드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;완전히 격리&lt;/b&gt;&lt;/span&gt;된 네트워크 환경을 제공하여 &lt;s&gt;&lt;b&gt;외부와의 통신이 불가능&lt;/b&gt;&lt;/s&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt; Host 모드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;호스트의 네트워크를 직접 사용&lt;/b&gt;하여 별도의 격리 없이 &lt;b&gt;호스트의 포트를 그대로 사용&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 각각의 네트워크 모드는 서로 다른 특징을 가지고 있으므로, 애플리케이션의 요구사항과 보안 정책에 따라 적절한 모드를 선택하여 사용해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker</category>
      <category>birdge</category>
      <category>docker network</category>
      <category>Host</category>
      <category>None</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/733</guid>
      <comments>https://pixx.tistory.com/733#entry733comment</comments>
      <pubDate>Sun, 23 Feb 2025 16:26:42 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.18 - 리눅스 : chown 명령어 알아보기 : -h옵션과 심볼릭 링크의 관계</title>
      <link>https://pixx.tistory.com/729</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3bZyB/btsMlGGLbqV/Nq5pk6xGEvFBbKDc6H7VA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3bZyB/btsMlGGLbqV/Nq5pk6xGEvFBbKDc6H7VA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3bZyB/btsMlGGLbqV/Nq5pk6xGEvFBbKDc6H7VA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3bZyB%2FbtsMlGGLbqV%2FNq5pk6xGEvFBbKDc6H7VA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스 시스템에서 &lt;b&gt;파일&lt;/b&gt;과 &lt;b&gt;디렉토리의 소유권&lt;/b&gt;은 보안과 접근 제어에 매우 중요한 요소입니다. 리눅스에서는 &lt;b&gt;&quot;chown&quot;&lt;/b&gt;라는 개념이 존재하는 데, &amp;nbsp;&lt;b&gt;chown(change owner) 명령어&lt;/b&gt;는 이러한 &lt;b&gt;소유권을 관리&lt;/b&gt;하는 핵심 도구입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 chown 명령어에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;chown이란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스에서 파일과 디렉토리는 각각 &lt;b&gt;소유자(owner)&lt;/b&gt; 와 &lt;b&gt;소유 그룹(group)&lt;/b&gt;을 가지는데, chown(change owner)은 &lt;b&gt;파일이나 디렉토리의 &lt;u&gt;소유자 또는 그룹을 변경&lt;/u&gt;하는 명령어&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기본 사용법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 파일 소유자 변경&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739717700179&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown 새로운소유자 파일명&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739717683296&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown user1 myfile.txt  # myfile.txt의 소유자를 user1로 변경&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;위와 같이 실행하면 &quot;myfile.txt&quot;파일의 &lt;b&gt;소유자&lt;/b&gt;를 user1으로 &lt;b&gt;변경&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt; 파일 소유자와 그룹 변경&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739717828869&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown 새로운소유자:새로운그룹 파일명&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739717851257&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown user1:usergroup myfile.txt  # 소유자를 user1, 그룹을 usergroup으로 변경&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 실행하면 &quot;myfile.txt&quot;파일의 소유자를 user1으로 변경하고, 소유 그룹을 usergroup으로 함께 변경합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;그룹만 변경&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739718208499&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown :새로운그룹 파일명&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739718256211&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown :usergroup myfile.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;chown의 주요 옵션&amp;nbsp;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;-R (recursive)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739718390021&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown -R john:developers /home/project/&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-R 옵션&lt;/b&gt;은 &lt;b&gt;디렉토리&lt;/b&gt;와 &lt;u&gt;&lt;b&gt;그 하위 모든 파일/디렉토리&lt;/b&gt;&lt;/u&gt;에 &lt;b&gt;변경 적용&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;-v (verbose)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739718440303&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown -v john file.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-v&lt;/b&gt; &lt;b&gt;옵션&lt;/b&gt;은 &lt;u&gt;&lt;b&gt;변경된 내용을 자세히 출력&lt;/b&gt;&lt;/u&gt;하는 옵션입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;-f (force)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739718494444&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown -f john file.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-f 옵션&lt;/b&gt;을 사용하면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;에러 메시지를 표시&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;chown -h의 의미&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chown명령어의 옵션 중 &quot;-h&quot;옵션이 존재합니다. 이 chown -h 옵션은 &lt;u&gt;&lt;b&gt;심볼릭 링크 자체의 소유권을 변경&lt;/b&gt;&lt;/u&gt;하는 명령어입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 심볼릭 링크가 가리키는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;원본 파일&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;이 아니라, &lt;b&gt;링크 파일 자체&lt;/b&gt;의 &lt;b&gt;소유자를 변경&lt;/b&gt;합니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;심볼릭 링크와 -h옵션의 관계&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 기본 동작(옵션 없을 때)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739719114797&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# example.txt의 소유권이 변경됨
ln -s example.txt symlink.txt
chown john symlink.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이&lt;s&gt;&lt;b&gt; -h 옵션을 사용&lt;/b&gt;&lt;/s&gt;하지 않는다면,&lt;s&gt;&lt;b&gt; 심볼릭 링크&lt;/b&gt;&lt;/s&gt;가 가리키는 &lt;u&gt;&lt;b&gt;원본 파일의 소유권이 변경&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. -h 옵션 사용 시&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739719196852&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# symlink.txt의 소유권만 변경됨
chown -h john symlink.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 -h옵션을 실행하면, &lt;b&gt;심볼릭 링크 자체의 소유권만 변경&lt;/b&gt;되고,&lt;s&gt;&lt;b&gt; 원본 파일의 소유권은 변경&lt;/b&gt;&lt;/s&gt;되지 않습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;실제 예시로 이해하기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739719267928&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 테스트 파일 생성
echo &quot;원본 파일입니다&quot; &amp;gt; original.txt
ln -s original.txt link.txt

# 현재 상태 확인
ls -l original.txt link.txt

# -h 옵션 없이 chown 실행
chown bob link.txt  # original.txt의 소유자가 bob으로 변경됨

# -h 옵션과 함께 chown 실행
chown -h alice link.txt  # link.txt의 소유자만 alice로 변경됨&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해를 돕기 위해 파일 구조를 시각화하면 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;305&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/daPs3P/btsMk2p1Xnn/gvaB1Fw70H9pvPeUJP3NEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/daPs3P/btsMk2p1Xnn/gvaB1Fw70H9pvPeUJP3NEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/daPs3P/btsMk2p1Xnn/gvaB1Fw70H9pvPeUJP3NEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdaPs3P%2FbtsMk2p1Xnn%2FgvaB1Fw70H9pvPeUJP3NEk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;509&quot; height=&quot;305&quot; data-origin-width=&quot;509&quot; data-origin-height=&quot;305&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;주의 사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;권한 필요성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;chown 명령어는&lt;b&gt; root 권한&lt;/b&gt;이나&lt;b&gt; sudo 권한&lt;/b&gt;이 &lt;b&gt;필요&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;일반 사용자는 &lt;b&gt;자신이 소유한 파일&lt;/b&gt;의 &lt;b&gt;그룹만 변경 가능&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;심볼릭 링크 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본적으로 &lt;b&gt;심볼릭 링크 자체의 소유권만 변경&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;-h 옵션&lt;/b&gt;을 사용하면 &lt;b&gt;심볼릭 링크 자체의 소유권만 변경&lt;/b&gt;되고 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;원본 파일은 변경&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;되지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;보안 고려사항&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일 소유권 변경은 보안에 직접적인 영향을 미칩니다.&lt;/li&gt;
&lt;li&gt;특히 시스템 파일의 소유권 변경은 신중하게 수행해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/729</guid>
      <comments>https://pixx.tistory.com/729#entry729comment</comments>
      <pubDate>Tue, 18 Feb 2025 22:56:15 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.17 - 심볼릭 링크(Symbolic Link)와 하드 링크(Hard Link) 알아보기</title>
      <link>https://pixx.tistory.com/728</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HijeX/btsMlB6xFXt/6poIEvbBa45O3o7uZoy8a1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HijeX/btsMlB6xFXt/6poIEvbBa45O3o7uZoy8a1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HijeX/btsMlB6xFXt/6poIEvbBa45O3o7uZoy8a1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHijeX%2FbtsMlB6xFXt%2F6poIEvbBa45O3o7uZoy8a1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;개발을 하다 보면 같은 파일을 여러 경로에서 접근해야 하는 경우가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;설정 파일&lt;/b&gt;을 &lt;b&gt;여러 프로젝트에서 공유&lt;/b&gt;하거나,&lt;b&gt; 특정 실행 파일&lt;/b&gt;을 &lt;b&gt;다양한 위치에서 실행&lt;/b&gt;하고 싶을 경우가 있습니다. 이때 사용하는 개념이 &lt;b&gt;링크(Link)&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 리눅스의 &lt;b&gt;심볼릭 링크(Symbolic Link)&lt;/b&gt; 와 &lt;b&gt;하드 링크(Hard Link)&lt;/b&gt;에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;심볼릭 링크(Symbolic Link)란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;심볼릭 링크(Symbolic Link, 소프트 링크)&lt;/b&gt; 는 &lt;b&gt;&lt;u&gt;일종의&lt;/u&gt; 바로가기 개념&lt;/b&gt;으로, &lt;b&gt;원본 파일의 경로를 &lt;span style=&quot;color: #ee2323;&quot;&gt;참조&lt;/span&gt;&lt;/b&gt;하는 &lt;b&gt;링크 파일&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원본 파일&lt;/b&gt;의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;경로를 저장&lt;/b&gt;&lt;/span&gt;하는&lt;b&gt; 새로운 파일을 생성&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원본 파일&lt;/b&gt;이&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;b&gt;삭제&lt;/b&gt;&lt;/span&gt;되면 &lt;u&gt;&lt;b&gt;링크는 깨집니다.&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다른 파일시스템&lt;/b&gt;에 있는 &lt;b&gt;파일도 링크&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디렉토리도 링크&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;생성 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739715535463&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ln -s 원본파일 링크이름&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;/home/user/config.yaml&lt;/b&gt; 파일을&lt;b&gt; /etc/config.yaml 경로&lt;/b&gt;에서도 &lt;b&gt;접근&lt;/b&gt;하고 싶다면 다음과 같이 작성할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739715568057&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ln -s /home/user/config.yaml /etc/config.yaml&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 명령어를 실행하면, /etc/config.yaml를 통해 /home/user/config.yaml의 내용을 그대로 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;하드 링크(Hard Link)란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하드링크는 &lt;b&gt;원본 파일&lt;/b&gt;과 &lt;b&gt;동일한 inode&lt;/b&gt;를 가리키는 &lt;u&gt;&lt;b&gt;또 다른 파일명&lt;/b&gt;&lt;/u&gt;입니다. 즉,&lt;b&gt; 동일한 데이터&lt;/b&gt;를 가리키는&lt;b&gt; 여러 개의 파일명&lt;/b&gt;이 &lt;b&gt;존재&lt;/b&gt;하는 것입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;inode 란❓&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Unix/Linux 파일 시스템&lt;/b&gt;에서 &lt;b&gt;파일&lt;/b&gt;이나 &lt;b&gt;디렉토리&lt;/b&gt;의 &lt;b&gt;모든 메타데이터를 저장하는 데이터 구조&lt;/b&gt;입니다. 쉽게 말해서, &lt;b&gt;&lt;i&gt;파일의 &quot;신분증&quot;&lt;/i&gt;&lt;/b&gt; 같은 것입니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;원본 파일과 &lt;u&gt;완전히 동일한 파일&lt;/u&gt;&lt;/b&gt;입니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원본 파일&lt;/b&gt;이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;삭제&lt;/b&gt;&lt;/span&gt;되어도 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;링크된 파일은 계속 사용 가능&lt;/b&gt;&lt;/span&gt;합니다&lt;/li&gt;
&lt;li&gt;&lt;b&gt;같은 파일시스템 내에서만 생성 가능&lt;/b&gt;합니다&lt;/li&gt;
&lt;li&gt;&lt;s&gt;&lt;b&gt;디렉토리는 링크&lt;/b&gt;&lt;/s&gt;할 수 없습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;생성 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739715835019&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ln 원본파일 링크이름&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어,&lt;b&gt; file1.txt&lt;/b&gt;의 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;하드 링크&lt;/b&gt;&lt;/span&gt;를&lt;b&gt; file2.txt&lt;/b&gt;로 만들고 싶다면 다음과 같이 작성할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739715871610&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ln file1.txt file2.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 명령어를 실행하면 &lt;b&gt;file1.txt&lt;/b&gt;와 &lt;b&gt;file2.txt&lt;/b&gt;는 &lt;b&gt;동일한 파일을 가리키며&lt;/b&gt;, 둘 중 하나를 수정하면 다른 파일도 동일하게 변경됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;심볼릭 링크와 하드 링크의 차이점 한눈에 보기&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 108px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.6822%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.9844%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;심볼릭 링크 (Symbolic Link)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;하드 링크 (Hard Link)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.6822%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;개념&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.9844%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;원본 파일의 경로를 &lt;span style=&quot;color: #006dd7;&quot;&gt;참조&lt;/span&gt;하는 파일&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;원본과 &lt;span style=&quot;color: #f89009;&quot;&gt;같은 Inode&lt;/span&gt;를 가지는 파일&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.6822%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;파일 존재 여부&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.9844%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;원본 파일이 &lt;span style=&quot;color: #ee2323;&quot;&gt;삭제&lt;/span&gt;되면 링크가 &lt;span style=&quot;color: #ee2323;&quot;&gt;깨짐&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;원본 파일이 삭제되어도 &lt;span style=&quot;color: #006dd7;&quot;&gt;유지&lt;/span&gt;됨&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.6822%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;디렉토리 링크 가능 여부&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.9844%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;가능 ✅&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;불가능 ❌&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.6822%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;다른 파일 시스템에서 가능 여부&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.9844%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;가능 ✅&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;❌ (같은 파일 시스템 내에서만 가능)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 23.6822%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;Inode 번호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 42.9844%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;원본과 다름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;원본과 같은&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1691&quot; data-start=&quot;1632&quot;&gt;&lt;b&gt;심볼릭 링크&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1691&quot; data-start=&quot;1632&quot;&gt;&lt;b&gt;설정 파일을 공유&lt;/b&gt;하거나, &lt;b&gt;특정 실행 파일&lt;/b&gt;을&lt;b&gt; 여러 위치에서 실행&lt;/b&gt;해야 할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;1753&quot; data-start=&quot;1692&quot;&gt;&lt;b&gt;하드 링크&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1753&quot; data-start=&quot;1692&quot;&gt;&lt;b&gt;백업 파일&lt;/b&gt;을 만들거나, &lt;b&gt;하나의 파일&lt;/b&gt;을&lt;b&gt; 여러 경로에서 동일하게 유지&lt;/b&gt;하고 싶을 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>inode</category>
      <category>심볼릭 링크</category>
      <category>하드 링크</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/728</guid>
      <comments>https://pixx.tistory.com/728#entry728comment</comments>
      <pubDate>Mon, 17 Feb 2025 01:30:49 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.16 - MySQL 문자열 검색: LIKE, INSTR, REGEXP, SUBSTRING</title>
      <link>https://pixx.tistory.com/726</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ulI0z/btsMjO0npxP/hPxtgcutfwWRyHfX1khFeK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ulI0z/btsMjO0npxP/hPxtgcutfwWRyHfX1khFeK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ulI0z/btsMjO0npxP/hPxtgcutfwWRyHfX1khFeK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FulI0z%2FbtsMjO0npxP%2FhPxtgcutfwWRyHfX1khFeK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MySQL 쿼리를 작성하다보면 &lt;b&gt;특정 문자가 포함된 조건&lt;/b&gt;을 걸어야할 때가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이때 주로 사용하는 연산자는 &lt;b&gt;LIKE연산자&lt;/b&gt;입니다. 이 외에도 MySQL에서는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;INSTR() 함수&lt;/b&gt;&lt;/span&gt;, &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;REGEXP()&lt;/b&gt;&lt;/span&gt;를&amp;nbsp;제공합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 INSTR() 함수에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;LIKE 연산자란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LIKE 연산자는 &lt;u&gt;&lt;b&gt;문자열 패턴 매칭&lt;/b&gt;&lt;/u&gt;에 사용됩니다. 예를 들어, &lt;b&gt;특정 문자열이 포함&lt;/b&gt;되어 있는지 확인하려면&lt;u&gt;&lt;b&gt; % 와일드카드를 사용&lt;/b&gt;&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739634398583&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM FOOD_FACTORY
WHERE address LIKE '%강원도%';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쿼리는 address 컬럼에 &lt;b&gt;&quot;강원도&quot;&lt;/b&gt;라는 문자열이 포함된 &lt;b&gt;모든 행을 반환&lt;/b&gt;합니다. &lt;b&gt;%&lt;/b&gt;는 &lt;b&gt;어떤 문자열이든 0번 이상 일치하는 부분&lt;/b&gt;을 나타냅니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;423&quot; data-start=&quot;334&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;364&quot; data-start=&quot;334&quot;&gt;&lt;b&gt;%강원도%&lt;/b&gt; : &quot;강원도&quot;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;포함&lt;/b&gt;&lt;/span&gt;하는 모든 문자열&lt;/li&gt;
&lt;li data-end=&quot;394&quot; data-start=&quot;365&quot;&gt;&lt;b&gt;강원도%&lt;/b&gt; : &quot;강원도&quot;로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;시작&lt;/b&gt;&lt;/span&gt;하는 모든 문자열&lt;/li&gt;
&lt;li data-end=&quot;423&quot; data-start=&quot;395&quot;&gt;&lt;b&gt;%강원도&lt;/b&gt; : &quot;강원도&quot;로 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;끝나는&lt;/b&gt;&lt;/span&gt; 모든 문자열&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;INSTR()함수란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;INSTR() 함수&lt;/b&gt;는 &lt;b&gt;특정 문자열&lt;/b&gt;이 &lt;b&gt;다른 문자열 내에 존재하는지 확인&lt;/b&gt;하고, &lt;b&gt;존재하는 경우 &lt;span style=&quot;color: #006dd7;&quot;&gt;해당 위치를 반환&lt;/span&gt;&lt;/b&gt;합니다. &lt;s&gt;&lt;b&gt;존재하지 않으면&lt;/b&gt;&lt;/s&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;0을 반환&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739634489400&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM FOOD_FACTORY
WHERE INSTR(address, '강원도') &amp;gt; 0;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쿼리는 address 컬럼에 &lt;b&gt;&quot;강원도&quot;가 포함된 모든 행을 반환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;INSTR() 함수는 &quot;강원도&quot;가 문자열 내에 존재하는 경우 &lt;b&gt;그 위치를 반환&lt;/b&gt;하므로,&lt;b&gt; &amp;gt; 0으로 검사&lt;/b&gt;하여&lt;b&gt; 해당 문자열이 포함된 경우를 확인&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;REGEXP 란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;REGEXP는 &lt;b&gt;정규 표현식&lt;/b&gt;을 사용하여 &lt;u&gt;&lt;b&gt;문자열에서 패턴&lt;/b&gt;&lt;/u&gt;을 찾는 데 사용됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;LIKE와 비슷하지만, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;더 복잡한 패턴 매칭이 가능&lt;/b&gt;&lt;/span&gt;합니다. 예를 들어, 숫자나 특정 형식의 문자열을 찾을 때 유용합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;252&quot; data-start=&quot;219&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 복잡한 문자열 패턴을 매칭할 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;290&quot; data-start=&quot;253&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 사용이 다소 복잡하고 성능이 떨어질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 특정 문자열로 시작하는 값 찾기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739634679662&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM FOOD_FACTORY
WHERE address REGEXP '^강원도.*';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쿼리는 address 컬럼이 &quot;강원도&quot;로 시작하는 데이터를 검색합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 특정 문자열로 끝나는 값 찾기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739634841237&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM FOOD_FACTORY
WHERE address REGEXP '시$';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쿼리는 address 컬럼이 &quot;시&quot;로 &lt;b&gt;끝나는 모든 데이터를 검색&lt;/b&gt;합니다. 예를 들어 &quot;서울시&quot;, &quot;부산시&quot; 등 &quot;시&quot;로 끝나는 주소를 조회합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3 특정 패턴을 포함하는 값 찾기&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739634871113&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM FOOD_FACTORY
WHERE address REGEXP '서울|강원';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 쿼리는 address 컬럼에 &lt;b&gt;&quot;서울&quot; 또는 &quot;강원&quot;&lt;/b&gt;이 포함된 데이터를 검색합니다. 예를 들어 &quot;서울특별시&quot;, &quot;강원도 강릉시&quot; 등 &quot;서울&quot; 또는 &quot;강원&quot;이 포함된 주소를 조회할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시들을 통해 REGEXP를 사용하여 다양한 패턴 매칭을 할 수 있다는 점을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;SUBSTRING / SUBSTR&amp;nbsp;란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SUBSTRING (또는 SUBSTR)은 &lt;u&gt;&lt;b&gt;문자열의 일부분을 추출&lt;/b&gt;&lt;/u&gt;할 때 사용됩니다. 이 함수는 문자열에서 지정된 &lt;b&gt;시작 위치&lt;/b&gt;와 &lt;b&gt;길이에 해당하는 부분을 반환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;639&quot; data-start=&quot;538&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;574&quot; data-start=&quot;538&quot;&gt;&lt;b&gt;장점&lt;/b&gt;: 문자열의 특정 부분을 쉽게 추출할 수 있습니다.&lt;/li&gt;
&lt;li data-end=&quot;639&quot; data-start=&quot;575&quot;&gt;&lt;b&gt;단점&lt;/b&gt;: 특정 위치부터 &lt;b&gt;잘라낸 결과만 반환&lt;/b&gt;하기 때문에, &lt;b&gt;포함 여부를 확인하려면 추가적인 로직이 필요&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1739634726736&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM FOOD_FACTORY
WHERE SUBSTRING(address, 1, 2) = '강원';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쿼리는 address의 첫 2자리가 &quot;강원&quot;인 데이터만 반환합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1739634761694&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT *
FROM FOOD_FACTORY
WHERE SUBSTRING(address, 3, 2) = '도';&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 쿼리는 address 컬럼의 &lt;b&gt;3번째 문자부터 2자리&lt;/b&gt;가&lt;b&gt; &quot;도&quot;인 데이터를 검색&lt;/b&gt;합니다. 예를 들어 &quot;강원도&quot;에서 &quot;도&quot; 부분을 추출하여 비교할 수 있습니다.&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>instr</category>
      <category>like</category>
      <category>MySQL</category>
      <category>regExp</category>
      <category>substring</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/726</guid>
      <comments>https://pixx.tistory.com/726#entry726comment</comments>
      <pubDate>Sun, 16 Feb 2025 00:57:37 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.15 - MySQL에서 OR 연산자 이외의 조건문 활용법: IN, CASE WHEN, FIND_IN_SET</title>
      <link>https://pixx.tistory.com/725</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFWRwA/btsMjV59sw5/knM5G0KAmwoDyFFer08hKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFWRwA/btsMjV59sw5/knM5G0KAmwoDyFFer08hKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFWRwA/btsMjV59sw5/knM5G0KAmwoDyFFer08hKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFWRwA%2FbtsMjV59sw5%2FknM5G0KAmwoDyFFer08hKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SQL 쿼리문을 작성하다 보면 조건을 조합해야 하는 경우가 많습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이때 가장 일반적으로 사용하는 조건은&amp;nbsp;&lt;b&gt;OR&lt;/b&gt; 연산자입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;226&quot; data-start=&quot;128&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;226&quot; data-start=&quot;177&quot;&gt;&lt;b&gt;OR :&lt;/b&gt;&amp;nbsp;여러 조건 중 &lt;b&gt;하나라도 만족&lt;/b&gt;하는 데이터를 조회할 때 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-end=&quot;317&quot; data-start=&quot;228&quot; data-ke-size=&quot;size16&quot;&gt;그러나 경우에 따라 IN, BETWEEN, CASE WHEN 등 다른 조건문을 활용하면 쿼리를 더 &lt;b&gt;간결하고 효율적&lt;/b&gt;으로 작성할 수 있습니다.&lt;/p&gt;
&lt;p data-end=&quot;317&quot; data-start=&quot;228&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-is-last-node=&quot;&quot; data-end=&quot;387&quot; data-start=&quot;319&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 &lt;b&gt;MySQL에서 조건을 조합할 때 사용할 수 있는 다양한 조건문&lt;/b&gt;을 정리하고자 합니다.&lt;/p&gt;
&lt;p data-is-last-node=&quot;&quot; data-end=&quot;387&quot; data-start=&quot;319&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; 일반적으로 사용하는 논리합&amp;nbsp; : OR&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;OR 연산자란❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OR 연산자는 &lt;b&gt;여러 조건 중 &lt;u&gt;하나라도 만족&lt;/u&gt;&lt;/b&gt;하는 데이터를 조회할 때 사용되는 &lt;b&gt;논리 연산자&lt;/b&gt;입니다. 여러 조건을 연결하여 &lt;b&gt;하나라도 만족&lt;/b&gt;하는 데이터를 가져와야 할 때 유용하게 사용됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739628821242&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM users WHERE age = 30 OR age = 40;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서는 age가 30 또는 40인 사용자들을 조회하는 쿼리입니다. &lt;b&gt;OR 연산자&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;두 개 이상의 조건을 결합&lt;/b&gt;&lt;/u&gt;하여, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;하나라도 만족&lt;/b&gt;&lt;/span&gt;하는 &lt;b&gt;데이터를 반환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;잘못된 사용 ❌&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739628922870&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WHERE MCDP_CD = 'CS' || 'GS'&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MySQL에서 &lt;b&gt;AND연산&lt;/b&gt;일 떄는 &lt;b&gt;&quot;&amp;amp;&amp;amp; &quot;로 표현이 가능&lt;/b&gt;하지만 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;OR연산은 불가능&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;141&quot; data-start=&quot;99&quot;&gt;|| 연산자는 &lt;b&gt;MySQL에서는 OR 연산자로 동작하지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;195&quot; data-start=&quot;142&quot;&gt;MySQL에서는 ||가 &lt;b&gt;문자열 연결 (CONCAT) 연산자로 해석될 수도 있음&lt;/b&gt;&lt;/li&gt;
&lt;li data-end=&quot;264&quot; data-start=&quot;196&quot;&gt;MCDP_CD = 'CS' || 'GS'는 논리적으로 MCDP_CD = ('CS' || 'GS')와 같음
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;352&quot; data-start=&quot;265&quot;&gt;'CS' || 'GS'는 MySQL에서 &lt;b&gt;단순한 문자열 연결&lt;/b&gt;이므로, MCDP_CD = 'CSGS'와 같은 의미가 됨 &amp;rarr; &lt;u&gt;&lt;b&gt;잘못된 결과 발생&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; &lt;b&gt;IN 연산자&lt;/b&gt; (여러 개의 = 조건을 단축)&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;IN 연산자란❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IN 연산자는 &lt;u&gt;&lt;b&gt;여러 개의 = 조건을 하나로 묶을 수 있는 방법&lt;/b&gt;&lt;/u&gt;입니다. OR 연산자를 사용하는 대신 IN을 사용하면 SQL을 더 &lt;b&gt;간결&lt;/b&gt;하고 &lt;b&gt;가독성&lt;/b&gt; 있게 작성할 수 있습니다. IN은 &lt;b&gt;여러 값을 동시에 비교&lt;/b&gt;할 때 매우 유용합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739629089211&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- OR 사용
SELECT * FROM DOCTOR WHERE MCDP_CD = 'CS' OR MCDP_CD = 'GS';

-- IN 사용 (더 간결)
SELECT * FROM DOCTOR WHERE MCDP_CD IN ('CS', 'GS');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 &lt;b&gt;IN연산자&lt;/b&gt;를 사용하여 여러개의 &lt;u&gt;&lt;b&gt;'='조건을 단축&lt;/b&gt;&lt;/u&gt;할 수 있습니다. IN연산자를 사용하면 &lt;b&gt;가독성&lt;/b&gt;이 좋고, &lt;b&gt;간결&lt;/b&gt;하게 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;CASE WHEN (조건에 따라 분기 처리)&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;CASE WHEN 구문이란❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CASE WHEN 구문&lt;/b&gt;은 SQL에서 &lt;u&gt;&lt;b&gt;조건에 따라 결과를 분기 처리&lt;/b&gt;&lt;/u&gt;할 수 있는 기능을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 특정 조건에 맞는 값을 반환&lt;/b&gt;하거나, 그 외의 경우 &lt;b&gt;다른 값을 반환&lt;/b&gt;해야 할 때 유용하게 사용됩니다. 이를 통해 쿼리 내에서 조건에 따른 값 변환을 쉽게 처리할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739629159070&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT DR_NAME, 
       MCDP_CD,
       CASE 
           WHEN MCDP_CD = 'CS' OR MCDP_CD = 'GS' THEN '외과 계열' 
           ELSE '기타' 
       END AS DEPARTMENT_CATEGORY
FROM DOCTOR;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서는 MCDP_CD가 'CS' 또는 'GS'인 경우 '외과 계열'로 반환하고, 그 외의 경우는 '기타'로 분기 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CASE WHEN&lt;/b&gt;을 사용하여 &lt;u&gt;&lt;b&gt;조건에 따라 분기 처리&lt;/b&gt;&lt;/u&gt;할 수 있습니다. &lt;b&gt;CASE WHEN&lt;/b&gt;을 사용하면 &lt;b&gt;특정 조건을 만족&lt;/b&gt;하는 경우 &lt;b&gt;값을 변환&lt;/b&gt;하기에 적합합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;FIND_IN_SET (문자열에서 값 검색)&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;FIND_IN_SET 함수란❓&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;FIND_IN_SET 함수&lt;/b&gt;는 주어진 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;문자열&lt;/b&gt;&lt;/span&gt;이 &lt;b&gt;콤마&lt;/b&gt;로 구분된 &lt;b&gt;리스트 안에서 존재하는지 확인하는 함수&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스트에서 &lt;b&gt;특정 값이 포함되어 있는지 확인&lt;/b&gt;하고, 해당 값이 &lt;b&gt;리스트 내에서 몇 번째 위치에 있는지를 반환&lt;/b&gt;합니다. 주로 &lt;b&gt;IN과 비슷한 기능&lt;/b&gt;을 수행하지만, &lt;u&gt;&lt;b&gt;값이 문자열로 구분되어 있을 때 유용&lt;/b&gt;&lt;/u&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1739629284927&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT * FROM users WHERE FIND_IN_SET(MCDP_CD, 'CS',GS');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서 FIND_IN_SET은 MCDP_CD 값이 'CS' 또는 'GS'인 경우를 조회합니다. 콤마로 구분된 문자열 내에서 &lt;b&gt;해당 값이 있는지 확인&lt;/b&gt;하는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>CASE WHEN</category>
      <category>FIND_IN_SET</category>
      <category>IN</category>
      <category>MySQL</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/725</guid>
      <comments>https://pixx.tistory.com/725#entry725comment</comments>
      <pubDate>Sat, 15 Feb 2025 21:31:15 +0900</pubDate>
    </item>
    <item>
      <title>[백준, 2630번] 색종이 만들기 (분할 정복, 재귀, Java)</title>
      <link>https://pixx.tistory.com/724</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l019O/btsMkaurSUd/BUrnD6AQrtFIluOPTcElu1/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l019O/btsMkaurSUd/BUrnD6AQrtFIluOPTcElu1/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l019O/btsMkaurSUd/BUrnD6AQrtFIluOPTcElu1/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl019O%2FbtsMkaurSUd%2FBUrnD6AQrtFIluOPTcElu1%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문제설명&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2360&quot; data-origin-height=&quot;1258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ohYNP/btsMiYhGmBz/yaJ4XmWSJUXaGTOafmVVGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ohYNP/btsMiYhGmBz/yaJ4XmWSJUXaGTOafmVVGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ohYNP/btsMiYhGmBz/yaJ4XmWSJUXaGTOafmVVGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FohYNP%2FbtsMiYhGmBz%2FyaJ4XmWSJUXaGTOafmVVGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;373&quot; data-origin-width=&quot;2360&quot; data-origin-height=&quot;1258&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2410&quot; data-origin-height=&quot;432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmz2Vh/btsMjDYrFim/a1GSeEkVaFyLbVgzYEyaqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmz2Vh/btsMjDYrFim/a1GSeEkVaFyLbVgzYEyaqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmz2Vh/btsMjDYrFim/a1GSeEkVaFyLbVgzYEyaqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmz2Vh%2FbtsMjDYrFim%2Fa1GSeEkVaFyLbVgzYEyaqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;125&quot; data-origin-width=&quot;2410&quot; data-origin-height=&quot;432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2380&quot; data-origin-height=&quot;1114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EiYyf/btsMjgvBlA5/ukduNmJuhScH4U1kFwcW20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EiYyf/btsMjgvBlA5/ukduNmJuhScH4U1kFwcW20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EiYyf/btsMjgvBlA5/ukduNmJuhScH4U1kFwcW20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEiYyf%2FbtsMjgvBlA5%2FukduNmJuhScH4U1kFwcW20%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;328&quot; data-origin-width=&quot;2380&quot; data-origin-height=&quot;1114&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입력 &amp;amp; 출력&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2374&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2ajQP/btsMjB0DwZN/8fdnLIawb3yfHhyEF52a1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2ajQP/btsMjB0DwZN/8fdnLIawb3yfHhyEF52a1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2ajQP/btsMjB0DwZN/8fdnLIawb3yfHhyEF52a1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2ajQP%2FbtsMjB0DwZN%2F8fdnLIawb3yfHhyEF52a1K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;356&quot; data-origin-width=&quot;2374&quot; data-origin-height=&quot;1208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나의 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2630&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준 - 색종이 만들기&quot;&lt;/b&gt;&lt;/a&gt; 문제는 &lt;b&gt;하얀색(0)&lt;/b&gt;과 &lt;b&gt;파란색(1)&lt;/b&gt;로 칠해진 종이가 주어지고 &lt;s&gt;&lt;b&gt;전체 종이가 모두 같은색으로 칠해있지 않으면&lt;/b&gt;&lt;/s&gt; &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;N/2&lt;/b&gt;&lt;/span&gt;로 나눠가면서 &lt;b&gt;모든 영역의 종이가 같은색&lt;/b&gt;으로만 이루도록 만들고, &lt;b&gt;각 종이의 색깔의 개수를 출력&lt;/b&gt;하는 문제입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;1008&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/caogil/btsMiqySXzf/2UAZe8ry4TdrUnTAgTdzgK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/caogil/btsMiqySXzf/2UAZe8ry4TdrUnTAgTdzgK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/caogil/btsMiqySXzf/2UAZe8ry4TdrUnTAgTdzgK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcaogil%2FbtsMiqySXzf%2F2UAZe8ry4TdrUnTAgTdzgK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;457&quot; data-origin-width=&quot;1102&quot; data-origin-height=&quot;1008&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 최종적으로 나누어진 색종이들을 보면, 흰색은 9개, 파란색은 7개로 나누어집니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 접근한 방법은 다음과 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li data-end=&quot;314&quot; data-start=&quot;224&quot;&gt;&lt;b&gt;주어진 종이 전체가 하나의 색깔로 이루어져 있는지 확인&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;314&quot; data-start=&quot;265&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;314&quot; data-start=&quot;265&quot;&gt;&lt;u&gt;&lt;b&gt;모두 같은 색&lt;/b&gt;&lt;/u&gt;이면 하얀색 종이 개수 또는 파란색 종이 개수를 &lt;b&gt;증가&lt;/b&gt;시키고 종료.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li data-end=&quot;417&quot; data-start=&quot;316&quot;&gt;&lt;b&gt;하나의 색깔이 아니라면 4등분(재귀 호출)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;417&quot; data-start=&quot;350&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;398&quot; data-start=&quot;350&quot;&gt;N &amp;times; N 크기의 종이를&lt;b&gt; N/2 &amp;times; N/2 크기&lt;/b&gt;의 &lt;b&gt;네 개의 부분으로 나누고&lt;/b&gt;,&lt;/li&gt;
&lt;li data-end=&quot;417&quot; data-start=&quot;402&quot;&gt;각각을 &lt;u&gt;&lt;b&gt;재귀적&lt;/b&gt;&lt;/u&gt;으로 검사.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;이 때 4등분으로 나누는 이유는 다음과 같습니다.&lt;br /&gt;&lt;br /&gt;영역 안에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;서로 다른 색깔&lt;/b&gt;&lt;/span&gt;이 섞여 있다면, 이 영역을 &lt;u&gt;&lt;b&gt;4개의 작은 정사각형&lt;/b&gt;&lt;/u&gt;으로 나누어 다시 검사해야 합니다.&lt;br /&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;162&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q4ycp/btsMjWb7dLX/duvm93zjK1sKFXvqHdOKrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q4ycp/btsMjWb7dLX/duvm93zjK1sKFXvqHdOKrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q4ycp/btsMjWb7dLX/duvm93zjK1sKFXvqHdOKrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq4ycp%2FbtsMjWb7dLX%2Fduvm93zjK1sKFXvqHdOKrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;406&quot; height=&quot;162&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;162&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;

&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 하나의 영역을 4가지 영역 으로 나누어 각각의 영역을 &lt;b&gt;재귀적으로 검사&lt;/b&gt;합니다.&lt;br /&gt;&lt;br /&gt;이렇게 나눈 각각의 영역에 대해 다시 같은 과정을 &lt;b&gt;반복&lt;/b&gt;하며, &lt;u&gt;&lt;b&gt;모든 칸이 같은 색이 될 때까지 계속해서 분할하고 검사&lt;/b&gt;&lt;/u&gt;합니다. 이러한 &lt;b&gt;분할 정복(Divide and Conquer) 방식&lt;/b&gt;을 통해&lt;b&gt; 전체 종이를 효율적으로 처리&lt;/b&gt;할 수 있기 때문입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;2566&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvugJu/btsMjHl6JUU/bO3svZaDS8VDVuErBRDmpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvugJu/btsMjHl6JUU/bO3svZaDS8VDVuErBRDmpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvugJu/btsMjHl6JUU/bO3svZaDS8VDVuErBRDmpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvugJu%2FbtsMjHl6JUU%2FbO3svZaDS8VDVuErBRDmpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;1113&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1439&quot; data-origin-height=&quot;2566&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 핵심은 영역의 색종이가 &lt;s&gt;&lt;b&gt;모두 같은색&lt;/b&gt;&lt;/s&gt;이 아니라면, 주어진 요구사항대로 &lt;b&gt;범위를 줄여야한다는 것&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 재귀적으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;범위를 수정&lt;/b&gt;&lt;/span&gt;하며 &lt;b&gt;각 영역을 검사&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;하나의 큰 정사각형&lt;/b&gt;을 &lt;b&gt;4개의 작은 정사각형&lt;/b&gt;으로 나누고, 각각의 작은 정사각형에 대해 같은 과정을 &lt;u&gt;&lt;b&gt;반복&lt;/b&gt;&lt;/u&gt;하는 것입니다. 이러한 과정은 &lt;b&gt;모든 칸이 같은 색&lt;/b&gt;이 될 때까지 계속되며, 이는 &lt;b&gt;분할 정복 알고리즘의 전형적인 예시&lt;/b&gt;라고 할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 27번째 줄에서 볼 수 있듯이 각 영역의 &lt;b&gt;첫번째 포인트만 비교하여 색깔의 개수를 카운트&lt;/b&gt;합니다. &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이는 각 영역이 &lt;/span&gt;&lt;u style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;모두 같은색&lt;/b&gt;&lt;/u&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;으로만 이루어져 있다는 것이 확인된 후에 수행되는 작업입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;isAllSame&lt;/b&gt;이 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;true&lt;/b&gt;&lt;/span&gt;인 경우에만 &lt;b&gt;해당 영역을 하나의 색종이로 간주&lt;/b&gt;하여 카운트하게 됩니다. 이렇게 함으로써 &lt;b&gt;불필요한 중복 검사를 피하고 효율적&lt;/b&gt;으로 색종이의 개수를 셀 수 있습니다.&lt;/p&gt;</description>
      <category>Coding Test/백준</category>
      <category>분할 정복</category>
      <category>재귀</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/724</guid>
      <comments>https://pixx.tistory.com/724#entry724comment</comments>
      <pubDate>Fri, 14 Feb 2025 16:46:12 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.14 - 리눅스 : umask 명령어란❓</title>
      <link>https://pixx.tistory.com/723</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6Up71/btsMjqjq69x/czvP7vPiSst6z3OkW3PV0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6Up71/btsMjqjq69x/czvP7vPiSst6z3OkW3PV0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6Up71/btsMjqjq69x/czvP7vPiSst6z3OkW3PV0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6Up71%2FbtsMjqjq69x%2FczvP7vPiSst6z3OkW3PV0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스 시스템에서 &lt;b&gt;파일&lt;/b&gt;과 &lt;b&gt;디렉토리&lt;/b&gt;는 기본적으로 &lt;b&gt;특정한 접근 권한&lt;/b&gt;을 가지며, 이는 보안과 직결됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 새로 생성되는 파일이나 디렉토리가 &lt;u&gt;&lt;b&gt;항상 원하는 권한을 갖도록 설정&lt;/b&gt;&lt;/u&gt;하려면 어떻게 해야 할까요?&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt; umask(User File Creation Mode Mask)&lt;/b&gt;&lt;/span&gt;&amp;nbsp;는 이러한 문제를 해결하는 핵심 개념으로, 기본 권한에서 &lt;b&gt;특정 권한을 자동으로 제거&lt;/b&gt;하여 &lt;b&gt;보안을 강화&lt;/b&gt;하는 역할을 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 umask에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;umask란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;리눅스에서 &lt;b&gt;새 파일&lt;/b&gt;이나 &lt;b&gt;디렉토리&lt;/b&gt;를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;생성&lt;/b&gt;&lt;/span&gt;할 때, &lt;b&gt;기본적으로 적용&lt;/b&gt;되는 &lt;u&gt;&lt;b&gt;권한을 제어&lt;/b&gt;하는 &lt;b&gt;값&lt;/b&gt;&lt;/u&gt;이 &lt;/span&gt;&lt;span&gt;&lt;b&gt;umask&lt;/b&gt;&lt;/span&gt;&lt;span&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; umask 값은 파일이나 디렉토리가 생성될 때 &lt;b&gt;기본적으로 어떤 권한을 &lt;span style=&quot;color: #ee2323;&quot;&gt;제거&lt;/span&gt;&lt;/b&gt;할지를 결정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기본적으로 리눅스에서 새로 생성되는 파일과 디렉토리는 다음과 같은 &lt;b&gt;기본 권한(초기 권한)&lt;/b&gt;을 가집니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;파일:&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 666 (rw-rw-rw-)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;디렉토리:&lt;/b&gt;&lt;/span&gt;&lt;span&gt; 777 (rwxrwxrwx)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만 보안상의 이유로 모든 사용자에게 &lt;b&gt;모든 권한을 부여하는 것은 위험&lt;/b&gt;하므로, &lt;/span&gt;&lt;span&gt;umask&lt;/span&gt;&lt;span&gt; 값을 이용해 &lt;b&gt;특정 권한을 자동으로 제거&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;umask 계산법&lt;/h3&gt;
&lt;div data-ke-type=&quot;moreLess&quot; data-text-more=&quot;더보기&quot; data-text-less=&quot;닫기&quot;&gt;&lt;a class=&quot;btn-toggle-moreless&quot;&gt;더보기&lt;/a&gt;
&lt;div class=&quot;moreless-content&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;파일&amp;nbsp;기본&amp;nbsp;권한&amp;nbsp;(666)&amp;nbsp;&lt;span style=&quot;color: #ee2323;&quot;&gt;-&lt;/span&gt;&amp;nbsp;umask&amp;nbsp;값&lt;/b&gt;&amp;nbsp;=&amp;nbsp;최종&amp;nbsp;파일&amp;nbsp;권한&lt;br /&gt;&lt;b&gt;디렉토리&amp;nbsp;기본&amp;nbsp;권한&amp;nbsp;(777)&lt;/b&gt;&amp;nbsp;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;-&lt;/span&gt;&amp;nbsp;umask&amp;nbsp;값&lt;/b&gt;&amp;nbsp;=&amp;nbsp;최종&amp;nbsp;디렉토리&amp;nbsp;권한&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어, &lt;/span&gt;&lt;span&gt;umask&lt;/span&gt;&lt;span&gt; 값이 &lt;/span&gt;&lt;b&gt;&lt;span&gt;022&lt;/span&gt;&lt;/b&gt;&lt;span&gt;라면&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;파일 권한: &lt;b&gt;666&lt;/b&gt; &lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;-&lt;/span&gt; 022&lt;/b&gt; = &lt;/span&gt;&lt;span&gt;&lt;b&gt;644 (rw-r--r--)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;디렉토리 권한: &lt;b&gt;777&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;-&lt;/b&gt;&lt;/span&gt; &lt;b&gt;022&lt;/b&gt; = &lt;/span&gt;&lt;span&gt;&lt;b&gt;755 (rwxr-xr-x)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;umask&amp;nbsp;값&amp;nbsp;확인&amp;nbsp;및&amp;nbsp;설정&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 현재 umask 값 확인&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739460258682&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ umask
0022  # 일반적으로 시스템 기본값&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;umask 명령어&lt;/b&gt;만 입력하면 &lt;b&gt;현재 설정된 umask 값을 확인&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 일시적으로 umask 변경&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739460292043&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ umask 027  # 파일: 640, 디렉토리: 750&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;터미널에서 &lt;b&gt;umask 값&lt;/b&gt;을 &lt;b&gt;변경&lt;/b&gt;하면, &lt;u&gt;&lt;b&gt;해당 세션에서만 적용&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;보안&amp;nbsp;관점에서&amp;nbsp;적절한&amp;nbsp;umask&amp;nbsp;값&amp;nbsp;설정하기&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일 및 디렉토리의 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;기본 권한&lt;/b&gt;&lt;/span&gt;을 적절히 제한하면 보안 강화를 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;개인 사용자&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span&gt;umask 077&lt;/span&gt;&lt;span&gt; (&lt;b&gt;자신만 접근 가능&lt;/b&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;일반 서버 환경&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span&gt;umask 027&lt;/span&gt;&lt;span&gt; (&lt;b&gt;소유자&lt;/b&gt;와 &lt;b&gt;그룹&lt;/b&gt;만 접근 가능, &lt;s&gt;&lt;b&gt;기타 사용자는 제한&lt;/b&gt;&lt;/s&gt;)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;공유 서버 환경&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;span&gt;umask 022&lt;/span&gt;&lt;span&gt; (소유자만 쓰기 가능, 그룹 및 기타 사용자는 읽기 가능)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;umask와&amp;nbsp;chmod&amp;nbsp;차이점&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;chmod&lt;/span&gt;&lt;/b&gt;&lt;span&gt;와 &lt;/span&gt;&lt;b&gt;&lt;span&gt;umask&lt;/span&gt;&lt;/b&gt;&lt;span&gt;는 모두 파일 및 디렉토리 &lt;b&gt;권한&lt;/b&gt;을 다루지만, 역할이 다릅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 98px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 18px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;umask&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 18px;&quot;&gt;&lt;b&gt;chmod&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;적용 시점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;파일/디렉토리 &lt;span style=&quot;color: #006dd7;&quot;&gt;생성 시&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;파일/디렉토리 &lt;span style=&quot;color: #ee2323;&quot;&gt;생성 후&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;적용 방식&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;기본 권한에서 특정 권한 &lt;span style=&quot;color: #ee2323;&quot;&gt;제거&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;지정된 권한으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;설정&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;사용 목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;자동화&lt;/span&gt;된 기본 권한 설정&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;수동&lt;/span&gt;으로 특정 권한 변경&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;예시 명령어&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;umask 022&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; text-align: center; height: 20px;&quot;&gt;&lt;b&gt;chmod 644 file.txt&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;umask&lt;/span&gt;&lt;span&gt;는 리눅스에서 &lt;b&gt;새 파일&lt;/b&gt;과&lt;b&gt; 디렉토리&lt;/b&gt;의 &lt;b&gt;기본 권한을 설정&lt;/b&gt;하는 중요한 개념입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 보안 강화를 위해 적절한 &lt;/span&gt;&lt;b&gt;&lt;span&gt;umask&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;b&gt; 값&lt;/b&gt;을 설정하는 것이 중요하며, 서버 환경에 맞춰 설정을 변경하면 보다 &lt;b&gt;안전한 시스템&lt;/b&gt;을 운영할 수 있습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>til</category>
      <category>umask</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/723</guid>
      <comments>https://pixx.tistory.com/723#entry723comment</comments>
      <pubDate>Fri, 14 Feb 2025 00:32:59 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.13 - 리눅스 파일 접근 권한 이해하기</title>
      <link>https://pixx.tistory.com/722</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ltXbU/btsMg3jhXgP/qviu4DWh8JXTaHzkmzZlk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ltXbU/btsMg3jhXgP/qviu4DWh8JXTaHzkmzZlk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ltXbU/btsMg3jhXgP/qviu4DWh8JXTaHzkmzZlk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FltXbU%2FbtsMg3jhXgP%2Fqviu4DWh8JXTaHzkmzZlk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스는 다중 사용자 시스템으로 설계되었습니다.&lt;b&gt; 여러 사용자가 동시에&lt;/b&gt; 시스템을 사용하는 환경에서는 파일과 데이터의 안전한 보호가 매우 중요합니다. 이를 위해 리눅스는 &lt;b&gt;파일 접근 권한(File Permission) 시스템&lt;/b&gt;을 도입했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 리눅스의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;파일 접근 권한(File Permission) 시스템&lt;/b&gt;&lt;/span&gt;에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;파일 접근 권한의 기본 구조&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리눅스에서는 &lt;b&gt;모든 파일&lt;/b&gt;에 대해 &lt;b&gt;세 가지 범주의 사용자&lt;/b&gt;를 구분하여 &lt;b&gt;서로 다른 접근 권한을 부여&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 소유자 (Owner)&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일을 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;소유&lt;/b&gt;&lt;/span&gt;한 사용자&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;그룹 (Group)&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일에 지정된 &lt;b&gt;그룹에 속한 사용자들&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt; 기타 사용자 (Others)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소유자나 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;그룹에 속하지 않은&lt;/b&gt;&lt;/s&gt;&lt;/span&gt; &lt;b&gt;모든 사용자&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;권한의 종류&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;각 범주의 사용자에 대해 다음 &lt;b&gt;세 가지 권한&lt;/b&gt;을 설정할 수 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;읽기 권한 (r)&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;쓰기 권한 (w)&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;실행 권한 (x)&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;파일에서의 권한 의미&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;읽기(r)&lt;/b&gt;: 파일의 내용을 &lt;b&gt;읽을&lt;/b&gt; 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쓰기(w)&lt;/b&gt;: 파일의 내용을 &lt;b&gt;수정&lt;/b&gt;할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행(x)&lt;/b&gt;: 파일을 &lt;b&gt;실행&lt;/b&gt;할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;디렉토리에서의 권한 의미&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;읽기(r)&lt;/b&gt;: 디렉토리 내용을 &lt;b&gt;볼 수 있음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쓰기(w)&lt;/b&gt;: 디렉토리 내 파일을 &lt;b&gt;생성/삭제&lt;/b&gt;할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행(x)&lt;/b&gt;: 디렉토리에 &lt;b&gt;접근&lt;/b&gt;할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;접근 권한 8진수 표기법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스는 권한을 &lt;b&gt;8진수로 표현&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739458660453&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 파일 생성
$ touch test.txt

# 소유자:rwx(7), 그룹:r-x(5), 기타사용자:r--(4) 권한 설정
$ chmod 754 test.txt
$ ls -l test.txt
-rwxr-xr-- 1 user group 0 Feb 13 10:00 test.txt

# 소유자:rw-(6), 그룹:r--(4), 기타사용자:r--(4) 권한 설정
$ chmod 644 test.txt
$ ls -l test.txt
-rw-r--r-- 1 user group 0 Feb 13 10:00 test.txt&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;읽기(r) = 4&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;쓰기(w) = 2&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;실행(x) = 1&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;권한 변경&lt;/b&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;chmod 명령어 : 권한 변경&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;숫자를 사용한 방법&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739458781249&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chmod 755 file  # rwxr-xr-x
chmod 644 file  # rw-r--r--
chmod 700 file  # rwx------&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;문자를 사용한 방법&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739458796861&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chmod u+x file  # 소유자에게 실행 권한 추가
chmod g-w file  # 그룹의 쓰기 권한 제거
chmod o+r file  # 기타 사용자에게 읽기 권한 추가
chmod a+x file  # 모든 사용자에게 실행 권한 추가&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;사용자 지정 문자&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;u : user(소유자)&lt;/li&gt;
&lt;li&gt;g : group(그룹)&lt;/li&gt;
&lt;li&gt;o : others(기타 사용자)&lt;/li&gt;
&lt;li&gt;a : all(모든 사용자)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;연산자&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;+ : 권한 &lt;b&gt;추가&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;- : 권한 &lt;b&gt;제거&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;= : 권한 &lt;b&gt;설정&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;권한 문자&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;r : 읽기 권한&lt;/li&gt;
&lt;li&gt;w : 쓰기 권한&lt;/li&gt;
&lt;li&gt;x : 실행 권한&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;chown 명령어 : 소유자 or 그룹 변경&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739458986209&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;chown user:group file  # 소유자와 그룹 모두 변경
chown user file       # 소유자만 변경
chown :group file     # 그룹만 변경&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;권한 설정 시 주의사항&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;보안을 위한 권한 설정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정 파일: 600 또는 640&lt;/li&gt;
&lt;li&gt;실행 파일: 755&lt;/li&gt;
&lt;li&gt;일반 문서: 644&lt;/li&gt;
&lt;li&gt;중요 데이터: 600&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;일반적인 실수 피하기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;777 권한&lt;/b&gt;&lt;/span&gt; &lt;u&gt;&lt;b&gt;사용 자제&lt;/b&gt;&lt;/u&gt; (모든 사용자에게 모든 권한 부여)&lt;/li&gt;
&lt;li&gt;홈 디렉토리 권한 관리 (700 또는 750 권장)&lt;/li&gt;
&lt;li&gt;로그 파일 권한 관리 (644 또는 640 권장)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>chmod</category>
      <category>chown</category>
      <category>til</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/722</guid>
      <comments>https://pixx.tistory.com/722#entry722comment</comments>
      <pubDate>Thu, 13 Feb 2025 23:40:21 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.12 - 리눅스 크론탭(Linux Crontab)</title>
      <link>https://pixx.tistory.com/721</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/St94D/btsMfgJ60ND/SkI2kxolP0CeO5UmiIfWCK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/St94D/btsMfgJ60ND/SkI2kxolP0CeO5UmiIfWCK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/St94D/btsMfgJ60ND/SkI2kxolP0CeO5UmiIfWCK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSt94D%2FbtsMfgJ60ND%2FSkI2kxolP0CeO5UmiIfWCK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;서버 관리를 하다 보면 &lt;b&gt;특정 작업&lt;/b&gt;을 &lt;u&gt;&lt;b&gt;정해진 시간에 자동으로 실행&lt;/b&gt;&lt;/u&gt;해야 할 때가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 매일 밤 12시에 데이터베이스 백업을 실행하거나, 매주 일요일마다 로그 파일을 정리하는 등의 작업이 있습니다. 리눅스에서는 이런 반복 작업을 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자동화&lt;/b&gt;&lt;/span&gt;할 수 있는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;'crontab'&lt;/b&gt;&lt;/span&gt;이라는 편리한 도구를 제공합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;crontab이란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;crontab&lt;/b&gt;은 &lt;b&gt;리눅스/유닉스 시스템&lt;/b&gt;에서 제공하는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;작업 스케줄러&lt;/b&gt;&lt;/span&gt;로, &lt;b&gt;특정 시간&lt;/b&gt;이나 &lt;b&gt;주기적&lt;/b&gt;으로 &lt;b&gt;실행&lt;/b&gt;해야 하는 &lt;b&gt;작업&lt;/b&gt;을 &lt;u&gt;&lt;b&gt;자동화&lt;/b&gt;&lt;/u&gt;할 수 있게 해주는 도구입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기본 문법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;crontab의 기본 문법은 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739371142347&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;*　　　　　　*　　　　　　 *　　　　　　*　　　　　　 *
분(0-59)　　시간(0-23)　　일(1-31)　　월(1-12)　　　요일(0-7)

 분(0~59)을 설정. *을 설정한 경우 1분 단위로 실행
 시간(0~23)을 설정. *을 설정한 경우 매시간 실행
 일(1~31)을 설정. *을 설정한 경우 매일 실행
 월(1~12)을 설정. *을 설정한 경우 매달 실행
 요일(0~7)을 설정. *을 설정한 경우 월요일부터 일요일까지 매일 실행&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;분: 0-59&lt;/li&gt;
&lt;li&gt;시: 0-23&lt;/li&gt;
&lt;li&gt;일: 1-31&lt;/li&gt;
&lt;li&gt;월: 1-12&lt;/li&gt;
&lt;li&gt;요일: 0-6 (0은 일요일)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 옵션&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1. 작업 목록 확인&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739371288447&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;crontab -l&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2. 작업 편집하기&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739371340631&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;crontab -e&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;3. 모든 작업 삭제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739371346113&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;crontab -r&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;자우 사용하는 예시 알아보기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&amp;nbsp;매일 특정시간에 실행&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739371190851&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 매일 오후 2시에 실행
0 14 * * * /scripts/daily-backup.sh&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&amp;nbsp;매주 특정 요일에 실행&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739371212748&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 매주 일요일 자정에 실행
0 0 * * 0 /scripts/weekly-cleanup.sh&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt; 정기적인 간격으로 실행&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739371246534&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 10분마다 실행
*/10 * * * * /scripts/check-service.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;주의 사항&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;절대 경로 사용하기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령어와 스크립트는 항상 &lt;u&gt;&lt;b&gt;절대 경로를 사용&lt;/b&gt;&lt;/u&gt;해야합니다.&lt;/li&gt;
&lt;li&gt;상대 경로를 사용하면 예상치 못한 문제가 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;권한 확인하기&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실행할 스크립트의 &lt;b&gt;실행 권한&lt;/b&gt;을 확인해야 합니다.&lt;/li&gt;
&lt;li&gt;필요한 디렉토리와 파일에 대한 &lt;b&gt;접근 권한&lt;/b&gt; 또한 확인해야합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;crontab&lt;/b&gt;은 &lt;b&gt;시스템 관리자&lt;/b&gt;에게 없어서는 안 될 중요한 도구입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; 반복적인 작업을 자동화&lt;/b&gt;&lt;/span&gt;함으로써 시간을 절약하고 실수를 줄일 수 있습니다. 하지만 강력한 만큼 &lt;b&gt;신중하게 사용&lt;/b&gt;해야 합니다. 잘못 설정된 &lt;b&gt;cron 작업&lt;/b&gt;은 시스템에 &lt;b&gt;부담&lt;/b&gt;을 주거나 예상치 못한 &lt;b&gt;문제&lt;/b&gt;를 일으킬 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>crontab</category>
      <category>til</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/721</guid>
      <comments>https://pixx.tistory.com/721#entry721comment</comments>
      <pubDate>Wed, 12 Feb 2025 12:54:19 +0900</pubDate>
    </item>
    <item>
      <title>[백준, 1182번] 부분수열의 합 (브루트 포스, 재귀, 백트래킹, Java)</title>
      <link>https://pixx.tistory.com/720</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uNHST/btsMdoBkwbV/337su57dGQliKSxNlbdm9K/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uNHST/btsMdoBkwbV/337su57dGQliKSxNlbdm9K/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uNHST/btsMdoBkwbV/337su57dGQliKSxNlbdm9K/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuNHST%2FbtsMdoBkwbV%2F337su57dGQliKSxNlbdm9K%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문제설명&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2350&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPaNwV/btsMeKQTmtr/8i8GXSXhlqIAOWxGSFOumk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPaNwV/btsMeKQTmtr/8i8GXSXhlqIAOWxGSFOumk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPaNwV/btsMeKQTmtr/8i8GXSXhlqIAOWxGSFOumk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPaNwV%2FbtsMeKQTmtr%2F8i8GXSXhlqIAOWxGSFOumk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;224&quot; data-origin-width=&quot;2350&quot; data-origin-height=&quot;752&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입력 &amp;amp; 출력&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SsZdk/btsMfPXUQxn/voXbOLHU89Sv5fZnFt1Qm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SsZdk/btsMfPXUQxn/voXbOLHU89Sv5fZnFt1Qm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SsZdk/btsMfPXUQxn/voXbOLHU89Sv5fZnFt1Qm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSsZdk%2FbtsMfPXUQxn%2FvoXbOLHU89Sv5fZnFt1Qm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;236&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나의 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1182&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준 - 부분수열의 합&quot;&lt;/b&gt;&lt;/a&gt; 문제는 &lt;b&gt;정수 N개&lt;/b&gt; &lt;b&gt;수열&lt;/b&gt;과 &lt;b&gt;정수S&lt;/b&gt;가 주어졌을 때 해당 수열의 부분 수열에서 더하여 정수 S를 만들 수 있는 &lt;b&gt;경우의 수&lt;/b&gt;를 구하는 문제입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;124&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRaYj6/btsMdpNMfVn/Lh7TBHdu3IWATn42YPGMPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRaYj6/btsMdpNMfVn/Lh7TBHdu3IWATn42YPGMPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRaYj6/btsMdpNMfVn/Lh7TBHdu3IWATn42YPGMPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRaYj6%2FbtsMdpNMfVn%2FLh7TBHdu3IWATn42YPGMPk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;311&quot; height=&quot;124&quot; data-origin-width=&quot;311&quot; data-origin-height=&quot;124&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 정수 S가 0일 때, 수열에서 0을 만들 수 있는 부분수열은 &lt;b&gt;[-3, -2, 5]&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 &lt;b&gt;부분수열&lt;/b&gt;을 찾기 위해서는 수열의 &lt;u&gt;&lt;b&gt;첫 번째 원소부터 차례대로 탐색&lt;/b&gt;&lt;/u&gt;하며, 각 원소를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;포함&lt;/b&gt;&lt;/span&gt;할지 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;말지&lt;/b&gt;&lt;/span&gt;를 결정하여 &lt;b&gt;부분수열을 구성&lt;/b&gt;해 나가야 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 각 원소에 대해 &lt;b&gt;포함할지 말지&lt;/b&gt;를 결정해야 하며, 이 과정은 &lt;b&gt;백트래킹&lt;/b&gt;(Backtracking) 방식으로 해결할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;1790&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vC9aG/btsMe2cFxN0/muS0bJRR6c9QiMtRKKtqmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vC9aG/btsMe2cFxN0/muS0bJRR6c9QiMtRKKtqmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vC9aG/btsMe2cFxN0/muS0bJRR6c9QiMtRKKtqmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvC9aG%2FbtsMe2cFxN0%2FmuS0bJRR6c9QiMtRKKtqmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;898&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1544&quot; data-origin-height=&quot;1790&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;부분 수열&lt;/b&gt;을 구할 때, 각 원소를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;포함&quot;&lt;/b&gt;&lt;/span&gt;하거나 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;포함하지 않음&quot;&lt;/b&gt;&lt;/span&gt; 두 가지 선택합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;재귀 함수에서 중요한 부분 중 하나인 &lt;u&gt;&lt;b&gt;탈출 조건&lt;/b&gt;&lt;/u&gt;은 idx(인덱스)가 수열의 길이와 같을 때, 즉, &lt;b&gt;수열을 전부 순회했을 때&lt;/b&gt; 입니다. 이때, 수열을 모두 탐색한 후, &lt;b&gt;현재까지 더한 값&lt;/b&gt;이 &lt;b&gt;타겟 넘버(S)&lt;/b&gt;와 &lt;b&gt;같다면 경우의 수를 증가&lt;/b&gt;시킵니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;283&quot; data-start=&quot;219&quot; data-ke-size=&quot;size16&quot;&gt;이때 중요한 점은 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;s&gt;&lt;b&gt;아무 수열도 포함&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;하지 않는 경우가 있을 수 있다는 점입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739261192893&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;5 0
-7 -3 -2 5 8&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;첫 번째 정수인&lt;b&gt; -7&lt;/b&gt;부터 &lt;b&gt;포함&lt;/b&gt;할지 &lt;s&gt;&lt;b&gt;포함&lt;/b&gt;&lt;/s&gt;하지 않을지 결정합니다. 이때 &lt;s&gt;&lt;b&gt;-7을 포함&lt;/b&gt;&lt;/s&gt;하지 않는 경우, &lt;b&gt;부분 수열은 []&lt;/b&gt;가 되고, &lt;b&gt;부분 합은 0&lt;/b&gt;이 됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;516&quot; data-start=&quot;402&quot; data-ke-size=&quot;size16&quot;&gt;현재&lt;b&gt; 타겟 넘버 S가 0&lt;/b&gt;이므로, 부분 합이 0인 경우는&lt;u&gt;&lt;b&gt; 하나의 유효한 경우로 취급&lt;/b&gt;&lt;/u&gt;됩니다. 따라서 &lt;b&gt;S가 0&lt;/b&gt;일 때는 &lt;b&gt;경우의 수에서 1을 빼줘야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;ps&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;처음에는 백트래킹 + 수열 문제이기 때문에 visited 배열을 사용하여 방문여부를 체크하려고 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;그러나 결과적으로는 visited배열은 필요가 없습니다. 왜냐하면 &lt;b&gt;부분 수열&lt;/b&gt;을 구할 때, 각 원소를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;&quot;포함&quot;&lt;/b&gt;&lt;/span&gt;하거나 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;포함하지 않음&quot;&lt;/b&gt;&lt;/span&gt; 두 가지 선택을 하게 되는데, 이 선택 자체가 &lt;u&gt;&lt;b&gt;중복된 탐색을 발생시키지 않기 때문&lt;/b&gt;&lt;/u&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt; for문을 사용하여 &lt;s&gt;&lt;b&gt;모든 인덱스를 반복&lt;/b&gt;&lt;/s&gt;하는 대신, &lt;b&gt;재귀 호출로 자연스럽게 각 수를 선택&lt;/b&gt;하는 방식으로 구현할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;b&gt;visited 배열&lt;/b&gt;을 사용하여 &lt;b&gt;방문 여부를 체크&lt;/b&gt;하는 궁극적인 이유는 &lt;b&gt;중복된 탐색을 방지&lt;/b&gt;하기 위함인데, &lt;b&gt;재귀적 탐색에서 각 선택이 &lt;u&gt;독립적&lt;/u&gt;&lt;/b&gt;이기 때문에 &lt;s&gt;&lt;b&gt;중복 탐색이 발생&lt;/b&gt;&lt;/s&gt;하지 않아 &lt;s&gt;&lt;b&gt;visited 배열이 필요&lt;/b&gt;&lt;/s&gt;하지 않습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Coding Test/백준</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/720</guid>
      <comments>https://pixx.tistory.com/720#entry720comment</comments>
      <pubDate>Tue, 11 Feb 2025 17:13:58 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.11 - ORDER BY의 숫자의 의미</title>
      <link>https://pixx.tistory.com/719</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kB0LA/btsMeMtt3DQ/PAhwZCETJ6I7jYYDOyQ5b0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kB0LA/btsMeMtt3DQ/PAhwZCETJ6I7jYYDOyQ5b0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kB0LA/btsMeMtt3DQ/PAhwZCETJ6I7jYYDOyQ5b0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkB0LA%2FbtsMeMtt3DQ%2FPAhwZCETJ6I7jYYDOyQ5b0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SQL 쿼리를 작성하다보면, SQL에서 ORDER BY 절은 쿼리 결과를 특정 기준으로 정렬할 때 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 때 컬럼명 대신 숫자로도 정렬이 가능한데, 본 글에서는 이 숫자로 정렬하는 방식에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;위치 기반 정렬이란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;컬럼명 대신 숫자를 사용하여 정렬하는 방식을 &lt;b&gt;위치 기반 정렬(Positional Ordering)&lt;/b&gt; 또는 &lt;b&gt;서수 정렬(Ordinal Ordering)&lt;/b&gt;이라고 한다고 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;SELECT 문&lt;/b&gt;에 &lt;b&gt;나열된 &lt;u&gt;컬럼의 순서를 기준&lt;/u&gt;&lt;/b&gt;으로 &lt;b&gt;정렬&lt;/b&gt;하는 방식입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기존 방식&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739203992060&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT name, age, city
FROM users
ORDER BY age;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;숫자로 정렬&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739204005415&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT name, age, city
FROM users
ORDER BY 2;  -- age 컬럼으로 정렬&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 쿼리에서 숫자 2는 SELECT 문의 &lt;b&gt;두 번째 컬럼(age)&lt;/b&gt;을 의미합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;위치 값의 의미&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;1&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT 문의 &lt;b&gt;첫 번째&lt;/b&gt; 컬럼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT 문의 &lt;b&gt;두 번째&lt;/b&gt; 컬럼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SELECT 문의 &lt;b&gt;세 번째&lt;/b&gt; 컬럼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>til</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/719</guid>
      <comments>https://pixx.tistory.com/719#entry719comment</comments>
      <pubDate>Tue, 11 Feb 2025 01:17:09 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] Lv.2 3월에 태어난 여성 회원 목록 출력하기 (MySQL)</title>
      <link>https://pixx.tistory.com/718</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;프로그래머스.jpeg&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbriEz/btsMeb8lDLU/jSudVdIOvMHsbxDs48UMgK/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbriEz/btsMeb8lDLU/jSudVdIOvMHsbxDs48UMgK/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbriEz/btsMeb8lDLU/jSudVdIOvMHsbxDs48UMgK/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbriEz%2FbtsMeb8lDLU%2FjSudVdIOvMHsbxDs48UMgK%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;프로그래머스.jpeg&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;문제 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;455&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TmiwG/btsMcGVT9rs/eF9C7WFuuTJ80ntE7OwRDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TmiwG/btsMcGVT9rs/eF9C7WFuuTJ80ntE7OwRDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TmiwG/btsMcGVT9rs/eF9C7WFuuTJ80ntE7OwRDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTmiwG%2FbtsMcGVT9rs%2FeF9C7WFuuTJ80ntE7OwRDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;335&quot; data-origin-width=&quot;951&quot; data-origin-height=&quot;455&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C3SFA/btsMeus2xbI/ZP3WkVkaikePbOGyx88sp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C3SFA/btsMeus2xbI/ZP3WkVkaikePbOGyx88sp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C3SFA/btsMeus2xbI/ZP3WkVkaikePbOGyx88sp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC3SFA%2FbtsMeus2xbI%2FZP3WkVkaikePbOGyx88sp1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;94&quot; data-origin-width=&quot;940&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;551&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AH4Mm/btsMd8DU8fX/NNEaeSLC6jQTJZFxwnRjuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AH4Mm/btsMd8DU8fX/NNEaeSLC6jQTJZFxwnRjuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AH4Mm/btsMd8DU8fX/NNEaeSLC6jQTJZFxwnRjuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAH4Mm%2FbtsMd8DU8fX%2FNNEaeSLC6jQTJZFxwnRjuk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;413&quot; data-origin-width=&quot;935&quot; data-origin-height=&quot;551&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;나의 풀이&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/131120?language=mysql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;프로그래머스 - 3월에 태어난 여성 회원 목록 출력하기&quot;&lt;/b&gt;&lt;/a&gt; 문제는 &lt;b&gt;식당&amp;nbsp;리뷰&amp;nbsp;사이트&lt;/b&gt;의&amp;nbsp;&lt;b&gt;회원&amp;nbsp;정보&lt;/b&gt;를&amp;nbsp;담은&amp;nbsp;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;MEMBER_PROFILE&amp;nbsp;테이블&lt;/b&gt;&lt;/span&gt;이 주어질 때 생일이&amp;nbsp;&lt;b&gt;3월인&amp;nbsp;여성&amp;nbsp;회원&lt;/b&gt;의&amp;nbsp;&lt;b&gt;ID,&amp;nbsp;이름,&amp;nbsp;성별,&amp;nbsp;생년월일&lt;/b&gt;을&amp;nbsp;조회하는&amp;nbsp;SQL문을&amp;nbsp;작성하는 문제입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 핵심은 &lt;b&gt;생년월일&lt;/b&gt;이 담겨져있는 &lt;b&gt;DATE_OF_BIRTH 컬럼&lt;/b&gt;을 &lt;u&gt;&lt;b&gt;3월로 포맷팅&lt;/b&gt;&lt;/u&gt;하는 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFnGKQ/btsMer4dvW2/U7ONDlt0lAzfFfesf2bKhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFnGKQ/btsMer4dvW2/U7ONDlt0lAzfFfesf2bKhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFnGKQ/btsMer4dvW2/U7ONDlt0lAzfFfesf2bKhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFnGKQ%2FbtsMer4dvW2%2FU7ONDlt0lAzfFfesf2bKhk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;931&quot; height=&quot;112&quot; data-origin-width=&quot;931&quot; data-origin-height=&quot;112&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 전화번호가&lt;b&gt; NULL인 경우가 존재&lt;/b&gt;하기 때문에 &lt;b&gt;전화번호가 NULL&lt;/b&gt;인 경우에는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IS NOT NULL로 제외&lt;/b&gt;&lt;/span&gt;를 해야합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739202757909&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select MEMBER_ID,MEMBER_NAME,GENDER,DATE_FORMAT(DATE_OF_BIRTH, &quot;%Y-%m-%d&quot;) AS DATE_OF_BIRTH
from MEMBER_PROFILE
where DATE_FORMAT(DATE_OF_BIRTH,&quot;%m&quot;) = &quot;03&quot;
and TLNO IS NOT NULL
and GENDER = 'W';&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;195&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdU5qS/btsMeMUxgqN/AUSkaBVKZGr2B8gHTW9lB0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdU5qS/btsMeMUxgqN/AUSkaBVKZGr2B8gHTW9lB0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdU5qS/btsMeMUxgqN/AUSkaBVKZGr2B8gHTW9lB0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdU5qS%2FbtsMeMUxgqN%2FAUSkaBVKZGr2B8gHTW9lB0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;195&quot; height=&quot;180&quot; data-origin-width=&quot;195&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;원래의 &lt;b&gt;DATE_OF_BIRTH 컬럼&lt;/b&gt;은 &lt;b&gt;시, 분, 초&lt;/b&gt;가 포함된 전체 &lt;b&gt;날짜 형식&lt;/b&gt;을 가지고 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;SELECT 절에서는 &lt;u&gt;&lt;b&gt;DATE_FORMAT 함수&lt;/b&gt;&lt;/u&gt;를 사용해 &quot;1993-03-16&quot;와 같이 &lt;b&gt;년-월-일 형식으로 변환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고 WHERER절에서&lt;b&gt; Month(&quot;%m&quot;)을 03월로 지정&lt;/b&gt;해줍니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WHERE 절에서는 &lt;b&gt;DATE_FORMAT 함수&lt;/b&gt;의&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt; %m 형식 지정자&lt;/b&gt;&lt;/span&gt;로 &lt;b&gt;3월생을 필터링&lt;/b&gt;하고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;IS NOT NULL&lt;/b&gt;&lt;/span&gt;로&lt;b&gt; 전화번호가 있는 회원만 선택&lt;/b&gt;하며, GENDER = 'W'로 &lt;b&gt;여성 회원을 추출&lt;/b&gt;합니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>Coding Test/프로그래머스</category>
      <category>date_format</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/718</guid>
      <comments>https://pixx.tistory.com/718#entry718comment</comments>
      <pubDate>Tue, 11 Feb 2025 01:03:08 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] Lv.1 평균 일일 대여 요금 구하기 (MySQL)</title>
      <link>https://pixx.tistory.com/716</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;프로그래머스.jpeg&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T1bKp/btsMciVnJ2f/nS2StTR54w0Bwe1kHyYUtK/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T1bKp/btsMciVnJ2f/nS2StTR54w0Bwe1kHyYUtK/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T1bKp/btsMciVnJ2f/nS2StTR54w0Bwe1kHyYUtK/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT1bKp%2FbtsMciVnJ2f%2FnS2StTR54w0Bwe1kHyYUtK%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;프로그래머스.jpeg&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;문제 설명&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;539&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB1klW/btsMd6sz4ZC/e6OS3ng8my5UhuCobcBhtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB1klW/btsMd6sz4ZC/e6OS3ng8my5UhuCobcBhtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB1klW/btsMd6sz4ZC/e6OS3ng8my5UhuCobcBhtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB1klW%2FbtsMd6sz4ZC%2Fe6OS3ng8my5UhuCobcBhtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;445&quot; data-origin-width=&quot;848&quot; data-origin-height=&quot;539&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;문제&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;137&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dhOGbJ/btsMdlKBHnT/aNDHcxaA27Ue2zsBjq12kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dhOGbJ/btsMdlKBHnT/aNDHcxaA27Ue2zsBjq12kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dhOGbJ/btsMdlKBHnT/aNDHcxaA27Ue2zsBjq12kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdhOGbJ%2FbtsMdlKBHnT%2FaNDHcxaA27Ue2zsBjq12kK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;114&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;137&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;375&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Joj4x/btsMczWTKE5/WyQ0rh6ubEiiS0RjircjS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Joj4x/btsMczWTKE5/WyQ0rh6ubEiiS0RjircjS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Joj4x/btsMczWTKE5/WyQ0rh6ubEiiS0RjircjS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJoj4x%2FbtsMczWTKE5%2FWyQ0rh6ubEiiS0RjircjS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;309&quot; data-origin-width=&quot;850&quot; data-origin-height=&quot;375&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;나의 풀이&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://school.programmers.co.kr/learn/courses/30/lessons/151136?language=mysql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;프로그래머스 - 평균 일일 대여 요금 구하기&quot;&lt;/b&gt;&lt;/a&gt; 문제는 문제의 제목그대로 &lt;b&gt;평균 일일 대여 요금&lt;/b&gt;을 구하는 문제입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;주어진 자동차 종류에는 &lt;b&gt;세단, SUV, 승합차, 트럭, 리무진&lt;/b&gt;이 있으며, 이 중 &lt;b&gt;SUV&lt;/b&gt; 차량을 선택한 후 &lt;b&gt;daily_fee 컬럼&lt;/b&gt;의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;평균&lt;/b&gt;&lt;/span&gt;을 구하면 됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 때 &lt;b&gt;평균&lt;/b&gt;이므로 &lt;b&gt;소수점이 존재&lt;/b&gt;하는 데 평균&amp;nbsp;일일&amp;nbsp;대여&amp;nbsp;요금은&amp;nbsp;&lt;u&gt;&lt;b&gt;소수&amp;nbsp;첫&amp;nbsp;번째&amp;nbsp;자리에서&amp;nbsp;반올림&lt;/b&gt;&lt;/u&gt;해야합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, 정확한 소수점을 구하기 위해서 MySQL의 &lt;b&gt;AVG()함수&lt;/b&gt;와 &lt;b&gt;ROUND()함수&lt;/b&gt;를 &lt;u&gt;&lt;b&gt;같이 사용&lt;/b&gt;&lt;/u&gt;해야합니다.&lt;/p&gt;
&lt;figure id=&quot;og_1739195976801&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[MySQL] AVG()와 ROUND()로 정확한 평균 구하기&quot; data-og-description=&quot; AVG() 함수란❓MySQL의 AVG() 함수는 데이터베이스에서 평균값을 계산하는 필수적인 집계 함수입니다.기본 문법SELECT AVG(column_name) FROM table_name;&amp;nbsp; AVG() 함수의 특징1. NULL 처리SELECT AVG(IFNULL(salary, 0)) FRO&quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/715&quot; data-og-url=&quot;https://pixx.tistory.com/715&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/7zXHv/hyYf4aLTJ7/PbFZAY7cnfGeOuow8DZMP0/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/I98bB/hyYcgcT8T9/tN1BRENE7KCIderjbUWP60/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/715&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/715&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/7zXHv/hyYf4aLTJ7/PbFZAY7cnfGeOuow8DZMP0/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/I98bB/hyYcgcT8T9/tN1BRENE7KCIderjbUWP60/img.png?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[MySQL] AVG()와 ROUND()로 정확한 평균 구하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt; AVG() 함수란❓MySQL의 AVG() 함수는 데이터베이스에서 평균값을 계산하는 필수적인 집계 함수입니다.기본 문법SELECT AVG(column_name) FROM table_name;&amp;nbsp; AVG() 함수의 특징1. NULL 처리SELECT AVG(IFNULL(salary, 0)) FRO&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739194749752&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select ROUND(AVG(daily_fee),0) as AVERAGE_FEE
from CAR_RENTAL_COMPANY_CAR
where CAR_TYPE = &quot;SUV&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;평균&amp;nbsp;일일&amp;nbsp;대여&amp;nbsp;요금은&amp;nbsp;&lt;u&gt;&lt;b&gt;소수 첫 번째 자리에서 반올림&lt;/b&gt;&lt;/u&gt; 해야한다는 의미는 소수점 자리가 없어야 한다는 의미입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 ROUND()함수의&lt;b&gt; 두 번째 매개변수(소수점 자릿수)&lt;/b&gt;를 &lt;b&gt;0으로 지정&lt;/b&gt;하여 &lt;b&gt;소수점 0번째까지 표시&lt;/b&gt;를 해줍니다.&lt;/p&gt;</description>
      <category>Coding Test/프로그래머스</category>
      <category>avg()</category>
      <category>round()</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/716</guid>
      <comments>https://pixx.tistory.com/716#entry716comment</comments>
      <pubDate>Mon, 10 Feb 2025 23:01:35 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] AVG()와 ROUND()로 정확한 평균 구하기</title>
      <link>https://pixx.tistory.com/715</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_mysql.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;145&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D6JKE/btsMeya1JL1/J0VEqlm7aFo8M0dtmXvRyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D6JKE/btsMeya1JL1/J0VEqlm7aFo8M0dtmXvRyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D6JKE/btsMeya1JL1/J0VEqlm7aFo8M0dtmXvRyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD6JKE%2FbtsMeya1JL1%2FJ0VEqlm7aFo8M0dtmXvRyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;145&quot; data-filename=&quot;edited_mysql.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;145&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; AVG() 함수란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MySQL의 &lt;b&gt;AVG() 함수&lt;/b&gt;는 데이터베이스에서 &lt;u&gt;&lt;b&gt;평균값을 계산&lt;/b&gt;&lt;/u&gt;하는 필수적인 &lt;b&gt;집계 함수&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기본 문법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739195235431&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT AVG(column_name) FROM table_name;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; AVG() 함수의 특징&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; NULL 처리&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739195365609&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT AVG(IFNULL(salary, 0)) FROM employees;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;NULL 값&lt;/b&gt;은 &lt;b&gt;자동&lt;/b&gt;으로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;계산에서 제외&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;NULL을 &lt;b&gt;0으로 처리&lt;/b&gt;하려면 &lt;b&gt;IFNULL 함수&lt;/b&gt; 사용 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;소수점 처리&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739195551524&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 급여 평균이 3456.789일 경우
SELECT ROUND(AVG(salary), 2);  -- 결과: 3456.79
SELECT ROUND(AVG(salary), 1);  -- 결과: 3456.8
SELECT ROUND(AVG(salary), 0);  -- 결과: 3457&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소수점을 처리하려면&lt;u&gt;&lt;b&gt; ROUND()함수를 같이 사용&lt;/b&gt;&lt;/u&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;b&gt;ROUND() 함수&lt;/b&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;숫자를 반올림&lt;/b&gt;&lt;/span&gt;하는 함수로, 두 가지 매개변수를 받습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;첫 번째 매개변수&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반올림할 &lt;b&gt;숫자&lt;/b&gt; (여기서는 AVG(salary))&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;두 번째 매개변수
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;소수점 &lt;b&gt;자릿수&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; AVG() 함수 활용 예시&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 기본 평균 계산&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739195424868&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT AVG(price) FROM products;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 단순한 형태로, products 테이블의 &lt;b&gt;price 컬럼 &lt;u&gt;전체 평균값&lt;/u&gt;을 계산&lt;/b&gt;합니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 그룹별 평균&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739195430009&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT category, AVG(price) as avg_price 
FROM products 
GROUP BY category;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;GROUP BY 절&lt;/b&gt;을 사용하여 &lt;b&gt;&lt;u&gt;카테고리별로 평균&lt;/u&gt;을 계산&lt;/b&gt;합니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. 조건부 평균&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739195434954&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;SELECT department, 
       AVG(CASE 
           WHEN experience &amp;gt;= 5 THEN salary 
           END) as senior_avg_salary
FROM employees
GROUP BY department;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CASE 문&lt;/b&gt;을 활용하여 &lt;b&gt;&lt;u&gt;조건에 맞는 데이터만 평균&lt;/u&gt;을 계산&lt;/b&gt;합니다. 이 예시에서는 &lt;b&gt;경력 5년 이상&lt;/b&gt;인 직원들의 부서별 평균 급여를 계산합니다. 경력 5년 미만인 직원의 급여는 계산에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제외&lt;/b&gt;&lt;/span&gt;됩니다.&lt;/p&gt;</description>
      <category>Database/SQL</category>
      <category>avg()</category>
      <category>MySQL</category>
      <category>round()</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/715</guid>
      <comments>https://pixx.tistory.com/715#entry715comment</comments>
      <pubDate>Mon, 10 Feb 2025 22:58:37 +0900</pubDate>
    </item>
    <item>
      <title>[백준, 11286번] 절댓값 힙 (우선 순위 큐, 정렬, Java)</title>
      <link>https://pixx.tistory.com/714</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q058Y/btsMcg30aVC/ZuFsDOKkMGblFCzuF3p2nK/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q058Y/btsMcg30aVC/ZuFsDOKkMGblFCzuF3p2nK/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q058Y/btsMcg30aVC/ZuFsDOKkMGblFCzuF3p2nK/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq058Y%2FbtsMcg30aVC%2FZuFsDOKkMGblFCzuF3p2nK%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문제설명&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2110&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bUeGIX/btsMcitTTov/Wh80KjVkVCwafeCi4mBhd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bUeGIX/btsMcitTTov/Wh80KjVkVCwafeCi4mBhd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bUeGIX/btsMcitTTov/Wh80KjVkVCwafeCi4mBhd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbUeGIX%2FbtsMcitTTov%2FWh80KjVkVCwafeCi4mBhd1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;293&quot; data-origin-width=&quot;2110&quot; data-origin-height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입력 &amp;amp; 출력&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2116&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bx1gCN/btsMbEYwse3/yYLIBiv2duKM1KOLkwAPG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bx1gCN/btsMbEYwse3/yYLIBiv2duKM1KOLkwAPG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bx1gCN/btsMbEYwse3/yYLIBiv2duKM1KOLkwAPG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbx1gCN%2FbtsMbEYwse3%2FyYLIBiv2duKM1KOLkwAPG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;153&quot; data-origin-width=&quot;2116&quot; data-origin-height=&quot;462&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2152&quot; data-origin-height=&quot;1070&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfo4t4/btsMcgv6jME/2Hemtsyk3m3Jzz7MtXYjFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfo4t4/btsMcgv6jME/2Hemtsyk3m3Jzz7MtXYjFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfo4t4/btsMcgv6jME/2Hemtsyk3m3Jzz7MtXYjFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcfo4t4%2FbtsMcgv6jME%2F2Hemtsyk3m3Jzz7MtXYjFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;348&quot; data-origin-width=&quot;2152&quot; data-origin-height=&quot;1070&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나의 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/11286&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준 - 절댓값 힙&quot;&lt;/b&gt;&lt;/a&gt; 문제는 &lt;u&gt;&lt;b&gt;우선순위 큐 자료구조&lt;/b&gt;&lt;/u&gt;를 사용하여 풀이한다면 손쉽게 풀이할 수 있는 문제입니다.&lt;/p&gt;
&lt;figure id=&quot;og_1739169862480&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[자료구조 JAVA] 우선순위 큐(Priority Queue) 클래스 알아보기 ✔&quot; data-og-description=&quot;Java를 활용하다 보면 데이터를 처리할 때 우선순위를 지켜야 하는 상황이 있습니다. 이때 사용할 수 있는 자료구조가우선순위 큐(Priority Queue)입니다.&amp;nbsp; 우선순위 큐를 사용하면 우선순위가 높은 &quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/204&quot; data-og-url=&quot;https://pixx.tistory.com/204&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/L46A7/hyYcajmlyv/oN4Q1Ol5F3QMoabaw0KtXK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/b2qODo/hyYfRWKh1r/0tzMeU9k5PtF4CxOR8KL9k/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/p3o5A/hyYcaKrJ9K/lIW1VXIvGV9paw1yLmN5Q1/img.png?width=1052&amp;amp;height=403&amp;amp;face=0_0_1052_403&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/204&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/204&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/L46A7/hyYcajmlyv/oN4Q1Ol5F3QMoabaw0KtXK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/b2qODo/hyYfRWKh1r/0tzMeU9k5PtF4CxOR8KL9k/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/p3o5A/hyYcaKrJ9K/lIW1VXIvGV9paw1yLmN5Q1/img.png?width=1052&amp;amp;height=403&amp;amp;face=0_0_1052_403');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[자료구조 JAVA] 우선순위 큐(Priority Queue) 클래스 알아보기 ✔&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Java를 활용하다 보면 데이터를 처리할 때 우선순위를 지켜야 하는 상황이 있습니다. 이때 사용할 수 있는 자료구조가우선순위 큐(Priority Queue)입니다.&amp;nbsp; 우선순위 큐를 사용하면 우선순위가 높은&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;선순위 큐는 일반적으로&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;힙(heap)이라는 트리 구조&lt;/b&gt;&lt;/u&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;를 기반으로 구현됩니다. 이 힙에 &lt;b&gt;정수x&lt;/b&gt;를 넣고 &lt;b&gt;0이 입력&lt;/b&gt;될 때마다 힙에서 &lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;절댓값&lt;/b&gt;&lt;/span&gt;이 &lt;b&gt;가장 작은 값을 출력&lt;/b&gt;하고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;그 값을 배열에서 제거&lt;/b&gt;&lt;/span&gt;합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: left;&quot;&gt;만약 &lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: left;&quot;&gt;절댓값이 가장 작은 값이 &lt;b&gt;여러개&lt;/b&gt;일 때는, &lt;b&gt;가장 작은 수를 출력&lt;/b&gt;하는 문제입니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;요구사항을 만족하기 위해서는 &lt;b&gt;Comparator&lt;/b&gt;를 사용하여 &lt;u&gt;&lt;b&gt;커스텀 정렬을 구현&lt;/b&gt;&lt;/u&gt;해야합니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt; 전체 코드&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1230&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9pn8c/btsMcz3jaDN/sBdfLKVb4BeLtNhf7dLoZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9pn8c/btsMcz3jaDN/sBdfLKVb4BeLtNhf7dLoZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9pn8c/btsMcz3jaDN/sBdfLKVb4BeLtNhf7dLoZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9pn8c%2FbtsMcz3jaDN%2FsBdfLKVb4BeLtNhf7dLoZ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;544&quot; data-origin-width=&quot;1582&quot; data-origin-height=&quot;1230&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이번 문제의 핵심인 &lt;b&gt;Comparator&lt;/b&gt;를 사용한 &lt;b&gt;커스텀 정렬&lt;/b&gt;을 주로 설명해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739170304757&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;PriorityQueue&amp;lt;Integer&amp;gt; priorityQueue = new PriorityQueue&amp;lt;&amp;gt;((a,b) -&amp;gt; {
           int absA = Math.abs(a);
           int absB = Math.abs(b);

           if(absA == absB) return Integer.compare(a,b);

           return Integer.compare(absA,absB);
        });&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;요구사항 1&lt;span&gt; : 절댓값이 가장 작은 값을 출력&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739170362475&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;return Integer.compare(absA,absB);  // 절댓값 기준 정렬&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Math.abs()메서드&lt;/b&gt;로 &lt;b&gt;절댓값&lt;/b&gt;을 구하고&lt;/li&gt;
&lt;li&gt;Integer.compare(absA,absB)로 &lt;b&gt;절댓값&lt;/b&gt;이 &lt;u&gt;&lt;b&gt;작은 값이 우선순위가 높도록 정렬&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;요구사항 2&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;:&lt;span&gt; 절댓값이 가장 작은 값이 여러개일 때는, 가장 작은 수를 출력&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739170405107&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;if(absA == absB) return Integer.compare(a,b);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;절댓값이 같을 때(absA == absB)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;원래 값&lt;/b&gt;을 비교(Integer.compare(a,b))하여 &lt;b&gt;더 작은 값이 우선순위가 높도록 정렬&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;정렬 동작 원리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Comparator의 반환 값에 따라서 동작은 다음과 같이 진행됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739170487892&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 모든 경우에서
양수 반환 &amp;rarr; 순서 바꿈
음수 반환 &amp;rarr; 순서 유지
0 반환 &amp;rarr; 동일 값&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1739170641110&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Integer.compare(absA,absB)&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;absA가 더 크면 양수가 반환되어 순서가 바뀌어 절대값이 작은 값이 앞으로 감&lt;/li&gt;
&lt;li&gt;absA가 더 작으면 음수가 반환되어 순서가 유지되어 절대값이 작은 값이 앞에 있게 됨&lt;/li&gt;
&lt;li&gt;절대값이 같으면 0이 반환되어 동일한 값으로 취급&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 이 비교 로직과 &lt;b&gt;우선순위 큐&lt;/b&gt;의 &lt;u&gt;&lt;b&gt;최소 힙 특성&lt;/b&gt;&lt;/u&gt;이 함께 작용하여 결과적으로 &lt;b&gt;절대값이 작은 값이 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;큐의 맨 앞에 위치&lt;/span&gt;&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;pre id=&quot;code_1739171174625&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 절대값 오름차순(작은 값 우선)
return Integer.compare(absA, absB);  // absA가 크면 양수-&amp;gt;순서바꿈

// 절대값 내림차순(큰 값 우선)
return Integer.compare(absB, absA);  // absB가 크면 양수-&amp;gt;순서바꿈&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;b&gt;PriorityQueue&lt;/b&gt;가 최대 힙을 기본으로 했다면, 절댓값이 큰 수가 먼저 나오도록 하기 위해 Integer.compare(absB, absA)와 같이 비교 순서를 반대로 해야합니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;결국 중요한 것은 &lt;b&gt;첫 번째 파라미터&lt;/b&gt;가 &lt;b&gt;두 번째 파라미터&lt;/b&gt;보다 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;크면&lt;/b&gt;&lt;/span&gt; &lt;u&gt;&lt;b&gt;순서가 바뀐다는 것&lt;/b&gt;&lt;/u&gt;입니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. &lt;b&gt;오름차순 정렬&lt;/b&gt;을 원할 때: Integer.compare(absA, absB)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739172098076&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;예1) absA=5, absB=3 일 때
compare(5,3) &amp;rarr; 양수 반환 &amp;rarr; 순서 바꿈 &amp;rarr; [3,5]
// 5가 3보다 크므로, 순서를 바꿔서 작은 값이 앞으로

예2) absA=2, absB=4 일 때
compare(2,4) &amp;rarr; 음수 반환 &amp;rarr; 순서 유지 &amp;rarr; [2,4]
// 2가 4보다 작으므로, 순서 유지해서 작은 값이 앞으로&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. &lt;b&gt;내림차순 정렬&lt;/b&gt;을 원할 때: Integer.compare(absB, absA)&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739172109977&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;예1) absA=5, absB=3 일 때
compare(3,5) &amp;rarr; 음수 반환 &amp;rarr; 순서 유지 &amp;rarr; [5,3]
// 3이 5보다 작으므로, 순서 유지해서 큰 값이 앞으로

예2) absA=2, absB=4 일 때
compare(4,2) &amp;rarr; 양수 반환 &amp;rarr; 순서 바꿈 &amp;rarr; [4,2]
// 4가 2보다 크므로, 순서를 바꿔서 큰 값이 앞으로&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;쉽게 말해서 &lt;b&gt;오름차순 정렬&lt;/b&gt;을 위해&lt;b&gt; a를 앞에 두었다&lt;/b&gt;고 이해하면 좋습니다!&lt;/span&gt;&lt;/blockquote&gt;</description>
      <category>Coding Test/백준</category>
      <category>comparator</category>
      <category>우선순위 큐</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/714</guid>
      <comments>https://pixx.tistory.com/714#entry714comment</comments>
      <pubDate>Mon, 10 Feb 2025 16:01:25 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.10 - API와 Endpoint 차이점 알아보기</title>
      <link>https://pixx.tistory.com/713</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yZ4DW/btsMbGBoKwM/975G1LFCLzVfaH9hJLftak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yZ4DW/btsMbGBoKwM/975G1LFCLzVfaH9hJLftak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yZ4DW/btsMbGBoKwM/975G1LFCLzVfaH9hJLftak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyZ4DW%2FbtsMbGBoKwM%2F975G1LFCLzVfaH9hJLftak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;웹 개발을 하다보면 자주 사용되는 용어인 &lt;b&gt;API&lt;/b&gt;와 &lt;b&gt;Endpoint&lt;/b&gt;가 있습니다. 이 둘은 많은 개발자들이 혼동하기 쉬운 개념인데, 저는 Endpoint를 &lt;b&gt;URL의 특정 resource path&lt;/b&gt;로 알고있었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 API와 Endpoint의 정확한 의미와 차이점에 대해 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;API란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;API(Application Programming Interface)는 서로 다른 소프트웨어 시스템들이 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;통신&lt;/b&gt;&lt;/span&gt;할 수 있게 해주는 인터페이스입니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;즉, 어플리케이션 간의 &lt;b&gt;통신&lt;/b&gt;을 할수 있게 해주는&lt;b&gt;&amp;nbsp;접점&lt;/b&gt;&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 카카오 API는 지도, 결제, 로그인 등 다양한 서비스를 제공하며, 각 서비스에 접근하기 위한 규칙과 방법을 정의합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Endpoint란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Endpoint는 &lt;b&gt;API의 한 구성 요소&lt;/b&gt;로, &lt;b&gt;특정 기능&lt;/b&gt;이나&lt;b&gt; 리소스&lt;/b&gt;에 접근할 수 있는 &lt;u&gt;&lt;b&gt;구체적인 URL&lt;/b&gt;&lt;/u&gt;이나 &lt;u&gt;&lt;b&gt;URI&lt;/b&gt;&lt;/u&gt;를 의미합니다. &lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;API에 액세스하거나 API와 상호 작용하기 위한 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;진입점&lt;/b&gt;&lt;/span&gt; 역할을 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Endpoint는 다음과 같은 특징을 가집니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Endpoint의 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;구체적인 기능 제공&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;명확한 URL 구조&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;특정 HTTP 메소드(GET, POST, PUT, DELETE 등) 사용&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;단일 리소스나 기능에 대한 접근점&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Endpoint의 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;GET&amp;nbsp;/books&lt;/b&gt;&amp;nbsp;:&amp;nbsp;모든&amp;nbsp;&lt;b&gt;책&amp;nbsp;목록을&amp;nbsp;검색&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GET /books/{id}&lt;/b&gt; : ID로 &lt;b&gt;특정 책을 검색&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; POST /books&lt;/b&gt; : 새로운 책을 만듭니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; PUT /books/{id}&lt;/b&gt; : 기존 책을 ID로 &lt;b&gt;업데이트&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; DELETE /books/{id}&lt;/b&gt; : ID로 책을 &lt;b&gt;삭제&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;API와 Endpoint의 차이점&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;300&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YRkJG/btsMdpSCLA0/PO0pWCIqVCP6TKXQo8Mk8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YRkJG/btsMdpSCLA0/PO0pWCIqVCP6TKXQo8Mk8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YRkJG/btsMdpSCLA0/PO0pWCIqVCP6TKXQo8Mk8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYRkJG%2FbtsMdpSCLA0%2FPO0pWCIqVCP6TKXQo8Mk8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;960&quot; height=&quot;300&quot; data-origin-width=&quot;960&quot; data-origin-height=&quot;300&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;b&gt;&lt;br /&gt;Endpoint&lt;/b&gt;는 &lt;b&gt;API의 구성 요소&lt;/b&gt;인 반면 &lt;b&gt;API&lt;/b&gt;는 두 애플리케이션이 &lt;b&gt;리소스를 공유할 수 있도록 하는 규칙 &lt;u&gt;집합&lt;/u&gt;&lt;/b&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;Endpoint&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;리소스의 위치&lt;/b&gt;&lt;/span&gt;이고 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;API&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;엔드포인트 URL을 사용&lt;/b&gt;하여 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;요청된 리소스를 검색&lt;/b&gt;&lt;/span&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;297&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cfmzcy/btsMbEDAAg3/Dir33vOiOOIki0VwGcQ0uK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cfmzcy/btsMbEDAAg3/Dir33vOiOOIki0VwGcQ0uK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cfmzcy/btsMbEDAAg3/Dir33vOiOOIki0VwGcQ0uK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcfmzcy%2FbtsMbEDAAg3%2FDir33vOiOOIki0VwGcQ0uK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;491&quot; height=&quot;297&quot; data-origin-width=&quot;491&quot; data-origin-height=&quot;297&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 범위의 차이&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;API&lt;/b&gt;: 전체 서비스의 인터페이스를 포괄하는 &lt;b&gt;상위 개념&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Endpoint&lt;/b&gt;: API 내의 특정 기능이나 &lt;u&gt;&lt;b&gt;리소스에 접근하는 단일 접점&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. 기능적 차이&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;API&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전체 시스템의 통신 규약 정의&lt;/li&gt;
&lt;li&gt;보안과 인증 메커니즘 제공&lt;/li&gt;
&lt;li&gt;데이터 교환 방식 설정&lt;/li&gt;
&lt;li&gt;전반적인 서비스 구조 설계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Endpoint&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 리소스에 대한 &lt;b&gt;CRUD 작업&lt;/b&gt; 수행&lt;/li&gt;
&lt;li&gt;&lt;b&gt;단일 기능&lt;/b&gt;이나 서비스 제공&lt;/li&gt;
&lt;li&gt;구체적인 데이터 처리&lt;/li&gt;
&lt;li&gt;특정 &lt;b&gt;HTTP 메소드&lt;/b&gt;로 작업 수행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. 구조적 차이&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;API&lt;/b&gt;는 &lt;b&gt;여러 Endpoint들의 &lt;u&gt;집합체&lt;/u&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하나의 API&lt;/b&gt;는 &lt;b&gt;다수의 Endpoint를 포함&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Endpoint는 API의 실제 구현체&lt;/li&gt;
&lt;li&gt;API는 Endpoint들을 조직화하고 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4. 실제 사용 예시&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;API&lt;/b&gt;: https://api.example.com/&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Endpoints&lt;/b&gt;:&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;/users: 사용자 프로필 관리&lt;/li&gt;
&lt;li&gt;/messages: 다이렉트 메시지 기능&lt;/li&gt;
&lt;li&gt;/media: 미디어 파일 업로드/다운로드&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;5. 관계성&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API는 도서관 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;전체&lt;/b&gt;&lt;/span&gt; 시스템&lt;/li&gt;
&lt;li&gt;Endpoint는 도서관 내의 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;특정&lt;/b&gt;&lt;/span&gt; 서비스 창구나 책장
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대출 창구 (/borrow)&lt;/li&gt;
&lt;li&gt;반납 창구 (/return)&lt;/li&gt;
&lt;li&gt;회원가입 창구 (/register)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;API와 Endpoint는 밀접한 관계를 가지고 있지만, 그 범위와 역할에서 명확한 차이를 보입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; API&lt;/b&gt;가 &lt;b&gt;전체 서비스의 인터페이스&lt;/b&gt;를 정의한다면, &lt;b&gt;Endpoint&lt;/b&gt;는 그 인터페이스 내에서 &lt;b&gt;실제로 기능을 수행하는 접점&lt;/b&gt;이라고 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>API</category>
      <category>EndPoint</category>
      <category>til</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/713</guid>
      <comments>https://pixx.tistory.com/713#entry713comment</comments>
      <pubDate>Mon, 10 Feb 2025 01:06:53 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 도커 네트워크 이해하기 (Docker network)</title>
      <link>https://pixx.tistory.com/712</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__20_-removebg-preview.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pKUiY/btsMaSCyaHu/V1CEmHoCwxBeEZj6r7PmO0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pKUiY/btsMaSCyaHu/V1CEmHoCwxBeEZj6r7PmO0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pKUiY/btsMaSCyaHu/V1CEmHoCwxBeEZj6r7PmO0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpKUiY%2FbtsMaSCyaHu%2FV1CEmHoCwxBeEZj6r7PmO0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;238&quot; height=&quot;212&quot; data-filename=&quot;다운로드__20_-removebg-preview.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker를 사용하다 보면 &lt;b&gt;여러 컨테이너 간의 통신&lt;/b&gt;이 필요한 상황이 발생합니다. 도커는 이런 상황에서 컨테이너 간 안전하고 효율적인 통신이 가능하게 하는&lt;b&gt; network기능&lt;/b&gt;을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서는 Docker Network에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Docker Network란❓&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;407&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciB7sx/btsMbzvARzX/hlJSUPcSp1bM7cibOooLXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciB7sx/btsMbzvARzX/hlJSUPcSp1bM7cibOooLXK/img.png&quot; data-alt=&quot;https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciB7sx/btsMbzvARzX/hlJSUPcSp1bM7cibOooLXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciB7sx%2FbtsMbzvARzX%2FhlJSUPcSp1bM7cibOooLXK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;435&quot; height=&quot;407&quot; data-origin-width=&quot;435&quot; data-origin-height=&quot;407&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;https://www.docker.com/blog/understanding-docker-networking-drivers-use-cases/&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Docker Network&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;컨테이너 간의 통신&lt;/b&gt;&lt;/u&gt;을 가능하게 하는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;가상의 네트워크 인프라&lt;/b&gt;&lt;/span&gt;입니다. 여러 컨테이너가 &lt;b&gt;서로 통신&lt;/b&gt;해야 하는 상황에 필수적인 요소입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;Docker Network가 필요한 이유&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너 간 안전한 &lt;b&gt;통신 환경 구축&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마이크로서비스 아키텍처(MSA)&lt;/b&gt; 구현&lt;/li&gt;
&lt;li&gt;애플리케이션 컴포넌트 간의 격리&lt;/li&gt;
&lt;li&gt;IP 주소 대신 &lt;u&gt;&lt;b&gt;컨테이너 이름으로 통신 가능&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Docker Network 사용 방법&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&amp;nbsp;네트워크 생성&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;볼륨과 달리 Docker는 네트워크를&lt;s&gt;&lt;b&gt; 자동으로 생성&lt;/b&gt;&lt;/s&gt;하지 않습니다. 따라서 네트워크를 사용하기 전에 &lt;u&gt;&lt;b&gt;먼저 생성&lt;/b&gt;&lt;/u&gt;해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739107817573&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker network create [네트워크_이름]&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&amp;nbsp;네트워크에 컨테이너 연결&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;네트워크를 생성한 후에는 컨테이너를 실행할 때 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;--network 옵션&lt;/b&gt;&lt;/span&gt;을 사용하여&lt;b&gt; 해당 네트워크에 연결&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;생성된 네트워크에 컨테이너를 연결하는 방법은 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739107866336&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name mongodb --network [네트워크_이름] mongo&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Docker Network 특징 : 컨테이너 이름을 통한 통신&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Docker Network의 가장 큰 장점 중 하나는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;IP 주소&lt;/b&gt;&lt;/s&gt;&lt;/span&gt; 대신 &lt;u&gt;&lt;b&gt;컨테이너 이름을 사용&lt;/b&gt;&lt;/u&gt;할 수 있다는 점입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 컨테이너 이름을 통한 통신&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.1&lt;span&gt; 기존의 IP기반 통신&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739108161752&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongoose.connect(
  'mongodb://172.17.0.2:27017/swfavorites',
  { useNewUrlParser: true }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.2&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Docker Network를 사용한 통신&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1739108175932&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongoose.connect(
  'mongodb://mongodb:27017/swfavorites',
  { useNewUrlParser: true }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자동&lt;/b&gt;&lt;/span&gt;으로 &lt;b&gt;컨테이너 이름&lt;/b&gt;을 &lt;b&gt;해당 IP 주소로 변환&lt;/b&gt;해주므로, &lt;s&gt;&lt;b&gt;하드코딩된 IP 주소를 사용&lt;/b&gt;&lt;/s&gt;할 필요가 없습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 포트 게시 없는 자유로운 통신&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739109669454&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;docker run -d --name mongodb --network facorites-net mongo&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 코드를 보면 컨테이너에 연결하기 위해 실행할 때&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;s&gt;&lt;b&gt;포트를 게시&lt;/b&gt;&lt;/s&gt;하지 않은 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이는 의도된 것으로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;같은 네트워크 내의 컨테이너&lt;/b&gt;&lt;/span&gt;들은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;s&gt;&lt;b&gt;포트 게시&lt;/b&gt;&lt;/s&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;없이도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자유롭게 통신&lt;/b&gt;할 수 있기 때문입니다. 포트 게시는 로컬 호스트나 &lt;b&gt;외부에서 컨테이너에 접근해야 할 때만 필요&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Docker Network 활용 예시&lt;/h3&gt;
&lt;figure id=&quot;og_1739108309253&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Docker] Docker 컨테이너에서 호스트 머신에 접근하기: host.docker.internal&quot; data-og-description=&quot;개요Docker를 사용하다 보면 컨테이너 내부에서 로컬 머신의 애플리케이션이나 데이터베이스에 접근해야 할 때가 있습니다.이때 사용할 수 있는 기능이 바로 host.docker.internal 입니다.&amp;nbsp;본 글에서&quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/697&quot; data-og-url=&quot;https://pixx.tistory.com/697&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/XzcaF/hyYcgX3ggT/Ssh2kLaGZjVNzoF5BZFkS0/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/KwCA7/hyYcj8mOdX/diQ1RmxNuwn7CRsUsdnEF1/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/dmNsQQ/hyYb77TvoG/3wWRngo2j489tbK1nJTlU1/img.png?width=1111&amp;amp;height=747&amp;amp;face=0_0_1111_747&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/697&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/697&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/XzcaF/hyYcgX3ggT/Ssh2kLaGZjVNzoF5BZFkS0/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/KwCA7/hyYcj8mOdX/diQ1RmxNuwn7CRsUsdnEF1/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/dmNsQQ/hyYb77TvoG/3wWRngo2j489tbK1nJTlU1/img.png?width=1111&amp;amp;height=747&amp;amp;face=0_0_1111_747');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Docker] Docker 컨테이너에서 호스트 머신에 접근하기: host.docker.internal&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요Docker를 사용하다 보면 컨테이너 내부에서 로컬 머신의 애플리케이션이나 데이터베이스에 접근해야 할 때가 있습니다.이때 사용할 수 있는 기능이 바로 host.docker.internal 입니다.&amp;nbsp;본 글에서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;159&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bivAV3/btsMbqFGdi7/0aK23tBZ8LuSvdWSn2kI3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bivAV3/btsMbqFGdi7/0aK23tBZ8LuSvdWSn2kI3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bivAV3/btsMbqFGdi7/0aK23tBZ8LuSvdWSn2kI3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbivAV3%2FbtsMbqFGdi7%2F0aK23tBZ8LuSvdWSn2kI3k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;440&quot; height=&quot;159&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;159&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 포스팅에서의 간단한 시나리오에 Docker Network를 활용하는 방법을 살펴보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1) 네트워크 연결 시도&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 MongoDB 컨테이너를 실행하면서 네트워크에 연결해보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739105234970&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name mongodb --network favorites-net mongo&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1347&quot; data-origin-height=&quot;197&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baHM3w/btsMdl3PCa1/oc4z4YmWPmyLC5ulOzJpJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baHM3w/btsMdl3PCa1/oc4z4YmWPmyLC5ulOzJpJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baHM3w/btsMdl3PCa1/oc4z4YmWPmyLC5ulOzJpJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaHM3w%2FbtsMdl3PCa1%2Foc4z4YmWPmyLC5ulOzJpJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1347&quot; height=&quot;197&quot; data-origin-width=&quot;1347&quot; data-origin-height=&quot;197&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;예상대로 &lt;i&gt;&lt;b&gt;&quot;네트워크를 찾을 수 없다&quot; &lt;/b&gt;&lt;/i&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;에러가 발생&lt;/b&gt;&lt;/span&gt;합니다. Docker는 볼륨과 달리 &lt;s&gt;&lt;b&gt;네트워크를 자동으로 생성&lt;/b&gt;&lt;/s&gt;하지 않기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2) 네트워크 생성&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;283&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bo8tbE/btsMb2RJmCk/78sSkq0ryoCtKDDIXrd201/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bo8tbE/btsMb2RJmCk/78sSkq0ryoCtKDDIXrd201/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bo8tbE/btsMb2RJmCk/78sSkq0ryoCtKDDIXrd201/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbo8tbE%2FbtsMb2RJmCk%2F78sSkq0ryoCtKDDIXrd201%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;549&quot; height=&quot;283&quot; data-origin-width=&quot;549&quot; data-origin-height=&quot;283&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1739108964022&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker network create favorites-net&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;docker network --help 명령어&lt;/b&gt;로 확인해보면 네트워크 생성을 위한 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;create 옵션&lt;/b&gt;&lt;/span&gt;을 확인할 수 있습니다. 이를 사용하여 네트워크를 &lt;b&gt;생성&lt;/b&gt;해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNjaEu/btsMby4yWt4/SwWXZq8EWO3bdDK6AkzS31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNjaEu/btsMby4yWt4/SwWXZq8EWO3bdDK6AkzS31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNjaEu/btsMby4yWt4/SwWXZq8EWO3bdDK6AkzS31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNjaEu%2FbtsMby4yWt4%2FSwWXZq8EWO3bdDK6AkzS31%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1215&quot; height=&quot;96&quot; data-origin-width=&quot;1215&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생성된 네트워크는 &lt;b&gt;Docker 내부 네트워크&lt;/b&gt;로, &lt;u&gt;&lt;b&gt;컨테이너 간 통신에 사용&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3) MongoDB 컨테이너 실행&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 생성된 네트워크를 사용하여 다시 MongoDB 컨테이너를 실행합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739109130209&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name mongodb --network favorites-net mongo&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4)&lt;span&gt; 컨테이너 간 통신 설정&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에는 다음과 같이 MongoDB의 IP 주소를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;직접 지정&lt;/b&gt;&lt;/span&gt;했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739109204824&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongoose.connect(
  'mongodb://container-ip:27017/swfavorites', // 127.17.0.2
  { useNewUrlParser: true },
  (err) =&amp;gt; {
    if (err) {
      console.log(err);
    } else {
      app.listen(3000);
    }
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이런 &lt;b&gt;IP 하드코딩 방식은 좋지 않습니다.&lt;/b&gt; &lt;b&gt;Docker Network를 사용&lt;/b&gt;하면 IP 대신&lt;u&gt;&lt;b&gt; 컨테이너 이름을 사용&lt;/b&gt;&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739109233631&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongoose.connect(
  'mongodb://mongodb:27017/swfavorites',
  { useNewUrlParser: true },
  (err) =&amp;gt; {
    if (err) {
      console.log(err);
    } else {
      app.listen(3000);
    }
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker가 &lt;b&gt;자동&lt;/b&gt;으로 컨테이너 이름을 해당 &lt;b&gt;IP 주소로 변환&lt;/b&gt;해주기 때문에, &lt;b&gt;더 안정적이고 관리하기 쉬운 방식&lt;/b&gt;입니다.&lt;/p&gt;</description>
      <category>DevOps/Docker</category>
      <category>docker network</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/712</guid>
      <comments>https://pixx.tistory.com/712#entry712comment</comments>
      <pubDate>Sun, 9 Feb 2025 23:04:37 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.09 - MySQL : CONCAT_WS로 문자열 손쉽게 결합하기</title>
      <link>https://pixx.tistory.com/711</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bp14gn/btsMbVdTMhh/OCfwOONA8HtRuRb2uOBDK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bp14gn/btsMbVdTMhh/OCfwOONA8HtRuRb2uOBDK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bp14gn/btsMbVdTMhh/OCfwOONA8HtRuRb2uOBDK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbp14gn%2FbtsMbVdTMhh%2FOCfwOONA8HtRuRb2uOBDK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터베이스 작업 시 &lt;b&gt;여러 문자열을 하나로 합쳐야 하는 경우&lt;/b&gt;가 자주 있습니다. MySQL에서는 이러한 작업을 위해 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;CONCAT_WS 함수&lt;/b&gt;&lt;/span&gt;를 제공합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;본 글에서는 MySQL의 CONCAT_WS 함수에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;CONCAT_WS란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CONCAT_WS&lt;/b&gt;는 &quot;&lt;b&gt;Concatenate With Separato&lt;/b&gt;r&quot;의 약자로, &lt;u&gt;&lt;b&gt;여러 문자열을 지정된 구분자로 연결&lt;/b&gt;&lt;/u&gt;하는 &lt;b&gt;MySQL 함수&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;CONCAT_WS의 기본 문법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739029074216&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CONCAT_WS(separator, string1, string2, ...)&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;일반 CONCAT 함수와 달리, &lt;b&gt;CONCAT_WS&lt;/b&gt;는 &lt;b&gt;첫 번째 인자로 &lt;span style=&quot;color: #ee2323;&quot;&gt;구분자를 지정&lt;/span&gt;&lt;/b&gt;하고, 이후의&lt;b&gt; 모든 문자열 사이&lt;/b&gt;에 &lt;b&gt;해당 구분자가 &lt;span style=&quot;color: #006dd7;&quot;&gt;자동&lt;/span&gt;으로 삽입&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;CONCAT과 CONCAT_WS의 차이점&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1739028866699&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- CONCAT 사용
SELECT CONCAT('Hello', ' - ', 'World', ' - ', '!');
-- 결과: Hello - World - !

-- CONCAT_WS 사용
SELECT CONCAT_WS(' - ', 'Hello', 'World', '!');
-- 결과: Hello - World - !&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 결과에서 알 수 있듯이 CONCAT과 CONCAT_WS의 &lt;b&gt;주요 차이점&lt;/b&gt;은 &lt;b&gt;구분자(separator) 처리 방식&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;CONCAT&lt;/b&gt;&lt;/span&gt;을 사용할 때는 구분자를 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;각각 직접 입력&lt;/b&gt;&lt;/span&gt;해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 'Hello'와 'World' 사이, 'World'와 '!' 사이에 각각 ' - '를 별도로 지정해야 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1739029035533&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- CONCAT: 구분자를 4번 써야 함
CONCAT(str1, ' - ', str2, ' - ', str3, ' - ', str4, ' - ', str5)

-- CONCAT_WS: 구분자를 한 번만 쓰면 됨
CONCAT_WS(' - ', str1, str2, str3, str4, str5)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;CONCAT_WS&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;첫 번째 인자로 구분자를 한 번만 지정&lt;/b&gt;하면, 이후의 모든 문자열 사이에 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;자동으로 해당 구분자가 삽입&lt;/b&gt;&lt;/span&gt;됩니다. 이는 코드를 더 간결하게 만들고, 실수를 줄일 수 있으며, 특히 많은 문자열을 연결할 때 매우 효율적입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;CONCAT_WS 주의 사항❗️&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;구분자&lt;/b&gt;는 반드시 &lt;u&gt;&lt;b&gt;첫 번째 인자로 지정&lt;/b&gt;&lt;/u&gt;해야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문자열이 아닌 데이터 타입&lt;/b&gt;은 &lt;u&gt;&lt;b&gt;자동으로 문자열로 변환&lt;/b&gt;&lt;/u&gt;됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구분자가 NULL&lt;/b&gt;이면 &lt;u&gt;&lt;b&gt;전체 결과가 NULL&lt;/b&gt;&lt;/u&gt;이 됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>CONCAT_WS</category>
      <category>MySQL</category>
      <category>til</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/711</guid>
      <comments>https://pixx.tistory.com/711#entry711comment</comments>
      <pubDate>Sun, 9 Feb 2025 00:42:15 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.08 - Java 입력 처리: BufferedReader vs Scanner 실제 성능 비교해보기</title>
      <link>https://pixx.tistory.com/710</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cm1Cib/btsMcTe0NKz/kA1RrANDOHQilx4VhndOJk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cm1Cib/btsMcTe0NKz/kA1RrANDOHQilx4VhndOJk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cm1Cib/btsMcTe0NKz/kA1RrANDOHQilx4VhndOJk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcm1Cib%2FbtsMcTe0NKz%2FkA1RrANDOHQilx4VhndOJk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Java 알고리즘 문제 풀이에서 Scanner로 입력을 받다가 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;시간 초과가 발생&lt;/b&gt;&lt;/span&gt;할 때, &lt;b&gt;BufferedReader 클래스&lt;/b&gt;로 변경하면 &lt;b&gt;해결&lt;/b&gt;되는 경우가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;BufferedReader 클래&lt;/b&gt;스는 &lt;b&gt;버퍼를 이용해 입력을 한 번에&lt;/b&gt; 읽어오기 때문에 Scanner보다 빠른 것으로 알려져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 BufferedReader는 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;String으로 입력&lt;/b&gt;&lt;/span&gt;을 받아 &lt;u&gt;&lt;b&gt;정수로 형변환이 필요&lt;/b&gt;&lt;/u&gt;하므로, 단일 정수나 적은 양의 정수 입력에서는 Scanner가 더 빠를 것이라는 의문이 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서는 &lt;b&gt;적은 양의 정수 입력&lt;/b&gt;에서도&lt;b&gt; BufferedReader가 실제로 더 빠른지 코드를 통해 검증&lt;/b&gt;해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;BufferedReader 클래스와 Scanner의 차이&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;202&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qJQjn/btsMbuHyMQz/HnIZ7hNI7B6Kbw6ckY8Kz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qJQjn/btsMbuHyMQz/HnIZ7hNI7B6Kbw6ckY8Kz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qJQjn/btsMbuHyMQz/HnIZ7hNI7B6Kbw6ckY8Kz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqJQjn%2FbtsMbuHyMQz%2FHnIZ7hNI7B6Kbw6ckY8Kz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;129&quot; data-origin-width=&quot;1100&quot; data-origin-height=&quot;202&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위 그림에서 알 수 있듯이, &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;Scanner&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;데이터를 읽을 때마다 시스템에 직접 요청&lt;/b&gt;&lt;/span&gt;하는 반면, &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;BufferedReader&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;버퍼에 데이터를 한 번에 불러온 후 버퍼에서 읽어오는 방식&lt;/b&gt;&lt;/span&gt;으로 작동합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 입력 방식의 차이로 인해 BufferedReader가 더 효율적인 입력 처리가 가능합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;자세한 내용은 아래의 포스팅에서 확인 가능합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1738943993094&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JAVA] 입출력, BufferedReader, StringTokenizer, StringBuilder 알아보기&quot; data-og-description=&quot;Java로 코딩테스트를 보거나 입력을 사용해야 할 때 Scanner 클래스를 사용하면 편리하지만 속도가 느리다는 단점이 있습니다.&amp;nbsp;그렇기 때문에 속도가 빠른 BufferReader 클래스를 사용을 하면 시간복&quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/129&quot; data-og-url=&quot;https://pixx.tistory.com/129&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/RAJLj/hyYcek6653/DDQoqGYesufkibQR9yypl1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/bcW27N/hyYcha4uVN/bf8ScGuFUamYyG8ErVecJk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/mJA1g/hyYcgwutpP/TKXXVoARthm00Qk0vStwGK/img.png?width=1281&amp;amp;height=264&amp;amp;face=0_0_1281_264&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/129&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/129&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/RAJLj/hyYcek6653/DDQoqGYesufkibQR9yypl1/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/bcW27N/hyYcha4uVN/bf8ScGuFUamYyG8ErVecJk/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/mJA1g/hyYcgwutpP/TKXXVoARthm00Qk0vStwGK/img.png?width=1281&amp;amp;height=264&amp;amp;face=0_0_1281_264');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[JAVA] 입출력, BufferedReader, StringTokenizer, StringBuilder 알아보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Java로 코딩테스트를 보거나 입력을 사용해야 할 때 Scanner 클래스를 사용하면 편리하지만 속도가 느리다는 단점이 있습니다.&amp;nbsp;그렇기 때문에 속도가 빠른 BufferReader 클래스를 사용을 하면 시간복&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Scanner의 내부 동작&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Scanner는 입력 처리 시 다음과 같은&lt;b&gt; 복잡한 과정&lt;/b&gt;을 거칩니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;입력 데이터&lt;/b&gt;를 &lt;u&gt;&lt;b&gt;토큰 단위로 분리&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;정규표현식&lt;/b&gt;을 사용한 &lt;b&gt;패턴 매칭&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;입력 유효성 검사&lt;/b&gt; 및 &lt;b&gt;예외 처리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 타입 변환&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 다단계 처리 과정은 &lt;b&gt;유연한 입력 처리를 가능&lt;/b&gt;하게 하지만, 동시에 &lt;u&gt;&lt;b&gt;성능 저하의 원인&lt;/b&gt;&lt;/u&gt;이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 nextInt()와 같은 메서드 호출 시마다 이 과정이 반복되어 실행됩니다.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt; 입력 방식별 속도 비교 ✅&lt;/h3&gt;
&lt;pre id=&quot;code_1738944551827&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.io.*;
import java.util.*;

public class InputPerformanceTest {
    public static void main(String[] args) throws Exception {
        // Scanner 테스트
        long startTime = System.nanoTime();
        Scanner sc = new Scanner(System.in);
        int n1 = sc.nextInt();
        long scannerTime = System.nanoTime() - startTime;

        // BufferedReader 테스트
        startTime = System.nanoTime();
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n2 = Integer.parseInt(br.readLine());
        long bufferTime = System.nanoTime() - startTime;

        // 결과 출력 (나노초 -&amp;gt; 밀리초 변환)
        System.out.println(&quot;Scanner 실행 시간: &quot; + scannerTime / 1000000.0 + &quot;ms&quot;);
        System.out.println(&quot;BufferedReader 실행 시간: &quot; + bufferTime / 1000000.0 + &quot;ms&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;실행 결과&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738944575024&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;3
3
Scanner 실행 시간: 636.295833ms
BufferedReader 실행 시간: 413.656583ms&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실행 결과&lt;/b&gt;에서 알 수 있듯이, 단일 정수 입력에서도 BufferedReader가 Scanner보다 더 빠른 성능을 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 BufferedReader는 Scanner보다 &lt;u&gt;&lt;b&gt;약 220ms 더 빠른 실행 시간을 기록&lt;/b&gt;&lt;/u&gt;했습니다. 이는 Scanner의 &lt;b&gt;복잡한 내부 처리 과정&lt;/b&gt;이 단순 &lt;b&gt;형변환&lt;/b&gt;보다 &lt;b&gt;더 많은 시간을 소요&lt;/b&gt;하기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;648&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TTlf0/btsMbq6mptG/sOzYuvVcMqTBWwkKjlAAOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TTlf0/btsMbq6mptG/sOzYuvVcMqTBWwkKjlAAOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TTlf0/btsMbq6mptG/sOzYuvVcMqTBWwkKjlAAOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTTlf0%2FbtsMbq6mptG%2FsOzYuvVcMqTBWwkKjlAAOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;419&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;648&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;백준 사이트의 입력 속도 비교 자료를 보면 위와 같이 &lt;b&gt;BufferedReader클래스&lt;/b&gt;를 통한 입력이 &lt;b&gt;높은 순위에 위치&lt;/b&gt;하는 것을 알 수 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;그러면, 무조건 BufferedReader를 쓰면되는 것인가❓&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코딩테스트나 알고리즘 문제 풀이에서 입력 처리 속도는 BufferedReader가 더 빠릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 적은 양의 입력을 처리할 때는 &lt;u&gt;&lt;b&gt;속도 차이가 미미&lt;/b&gt;&lt;/u&gt;하므로, &lt;b&gt;문제의 입력 크기&lt;/b&gt;와 &lt;b&gt;복잡도&lt;/b&gt;를 고려하여 &lt;b&gt;Scanner&lt;/b&gt;와 &lt;b&gt;BufferedReader&lt;/b&gt;를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;적절히 선택&lt;/b&gt;&lt;/span&gt;하는 것이 좋 습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 대량의 데이터를 처리&lt;/b&gt;하거나 &lt;b&gt;시간 제한이 빡빡한 경우&lt;/b&gt; &lt;b&gt;BufferedReader&lt;/b&gt;를, &lt;b&gt;단순한 입력의 경우&lt;/b&gt; &lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;가독성&lt;/b&gt;&lt;/span&gt;이 좋은 &lt;b&gt;Scanner&lt;/b&gt;를 사용하는 것이 좋을 것 같다는 개인적인 생각입니다.&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>BufferedReader</category>
      <category>scanner</category>
      <category>til</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/710</guid>
      <comments>https://pixx.tistory.com/710#entry710comment</comments>
      <pubDate>Sat, 8 Feb 2025 01:22:03 +0900</pubDate>
    </item>
    <item>
      <title>[백준, 7569번] 토마토 (너비 우선 탐색 : BFS, Java)</title>
      <link>https://pixx.tistory.com/709</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5eF5u/btsMaxqZEbI/VbuR7Ax6zYwDbR66HDbHDk/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5eF5u/btsMaxqZEbI/VbuR7Ax6zYwDbR66HDbHDk/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5eF5u/btsMaxqZEbI/VbuR7Ax6zYwDbR66HDbHDk/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5eF5u%2FbtsMaxqZEbI%2FVbuR7Ax6zYwDbR66HDbHDk%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문제설명&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2186&quot; data-origin-height=&quot;1180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rIR91/btsL9NgYQMN/zqz3x8xKYKCS58wSLTV0lK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rIR91/btsL9NgYQMN/zqz3x8xKYKCS58wSLTV0lK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rIR91/btsL9NgYQMN/zqz3x8xKYKCS58wSLTV0lK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrIR91%2FbtsL9NgYQMN%2Fzqz3x8xKYKCS58wSLTV0lK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;378&quot; data-origin-width=&quot;2186&quot; data-origin-height=&quot;1180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;314&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/X3ytW/btsMbxjlMsI/wD2t1sQj6dr4kFGa2sU171/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/X3ytW/btsMbxjlMsI/wD2t1sQj6dr4kFGa2sU171/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/X3ytW/btsMbxjlMsI/wD2t1sQj6dr4kFGa2sU171/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FX3ytW%2FbtsMbxjlMsI%2FwD2t1sQj6dr4kFGa2sU171%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;103&quot; data-origin-width=&quot;2144&quot; data-origin-height=&quot;314&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입력 &amp;amp; 출력&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;696&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbnMOz/btsMbHlIzkB/RMo7DVsXKCulD3i70AZeAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbnMOz/btsMbHlIzkB/RMo7DVsXKCulD3i70AZeAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbnMOz/btsMbHlIzkB/RMo7DVsXKCulD3i70AZeAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbnMOz%2FbtsMbHlIzkB%2FRMo7DVsXKCulD3i70AZeAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;229&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;696&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2110&quot; data-origin-height=&quot;1368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TPgAe/btsMagbU7lU/CWTYC3C0O2pvIpFLUvq4CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TPgAe/btsMagbU7lU/CWTYC3C0O2pvIpFLUvq4CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TPgAe/btsMagbU7lU/CWTYC3C0O2pvIpFLUvq4CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTPgAe%2FbtsMagbU7lU%2FCWTYC3C0O2pvIpFLUvq4CK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;454&quot; data-origin-width=&quot;2110&quot; data-origin-height=&quot;1368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나의 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 &lt;a href=&quot;https://www.acmicpc.net/problem/7569&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준 - 토마토&quot;&lt;/b&gt;&lt;/a&gt;문제는 &lt;a href=&quot;https://www.acmicpc.net/problem/7576&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준7576번 문제&quot;&lt;/b&gt;&lt;/a&gt;와 거의 같은 문제입니다. 7576번 문제와 다른 점은 하나의 &lt;b&gt;위 아래로 박스가 추가&lt;/b&gt;되었다는 점입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 아래로 박스가 추가되었기 때문에 방향도 마찬가지로 &lt;b&gt;앞, 뒤가 추가&lt;/b&gt;되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접근 방법도 마찬가지로 동일합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;M x N 크기의 상자&lt;/b&gt;가 주어지고, 해당 상자의 토마토가 있을 때 다음 조건을 만족하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&lt;u&gt;&lt;b&gt;토마토가 모두 익을 때까지의 최소 날짜를 출력&lt;/b&gt;&lt;/u&gt;해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;보관 후&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;하루가 지나면&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;익은 토마토들의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;인접한 곳&lt;/b&gt;에 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;익지 않은 토마토들&lt;/b&gt;은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;익은 토마토의 영향을 받아 익게 된다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;&lt;b&gt;저장될 때부터&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;모든 토마토가 익어있는 상태이면 0을 출력&lt;/b&gt;해야 하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;s&gt;&lt;b&gt;토마토가 모두 익지는 못하는 상황&lt;/b&gt;&lt;/s&gt;이면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;-1을 출력&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock floatLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;653&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciczzg/btsMafKRp24/pDkGhCJKIBO7FWnJZRrgzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciczzg/btsMafKRp24/pDkGhCJKIBO7FWnJZRrgzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciczzg/btsMafKRp24/pDkGhCJKIBO7FWnJZRrgzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fciczzg%2FbtsMafKRp24%2FpDkGhCJKIBO7FWnJZRrgzk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;626&quot; data-origin-width=&quot;417&quot; data-origin-height=&quot;653&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왼쪽 그림과 같이 앞 뒤에 있는 위치까지 생각하여 계산해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 3차원 배열에서 한 토마토의 위치에서 &lt;b&gt;상, 하, 좌, 우&lt;/b&gt;와 더불어 &lt;b&gt;앞, 뒤&lt;/b&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;총 6방향&lt;/b&gt;&lt;/span&gt;으로 토마토가 익어나갈 수 있음을 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 &lt;u&gt;&lt;b&gt;3차원적 전파&lt;/b&gt;&lt;/u&gt;를 BFS를 통해 구현하여 모든 토마토가 익는데 걸리는 &lt;b&gt;최소 시간&lt;/b&gt;을 계산할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 현재 토마토가 (1,1,1) 위치에 있다면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상: (0,1,1)&lt;/li&gt;
&lt;li&gt;하: (2,1,1)&lt;/li&gt;
&lt;li&gt;좌: (1,0,1)&lt;/li&gt;
&lt;li&gt;우: (1,2,1)&lt;/li&gt;
&lt;li&gt;앞: (1,1,0)&lt;/li&gt;
&lt;li&gt;뒤: (1,1,2)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 6방향으로 토마토가 익어나갈 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;2847&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cmnIC5/btsMavs9z9v/Lsw8ufxnWXUBF0fkBVLLmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cmnIC5/btsMavs9z9v/Lsw8ufxnWXUBF0fkBVLLmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cmnIC5/btsMavs9z9v/Lsw8ufxnWXUBF0fkBVLLmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcmnIC5%2FbtsMavs9z9v%2FLsw8ufxnWXUBF0fkBVLLmk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;1249&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1552&quot; data-origin-height=&quot;2847&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드는 크게 4가지로 구성되어있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; static 변수&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;N, M, H&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;상자의 &lt;b&gt;세로(행)&lt;/b&gt;, &lt;b&gt;가로(열&lt;/b&gt;), &lt;b&gt;높이&lt;/b&gt;를 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure id=&quot;og_1738911326697&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[JAVA] 좌표와 2차원 배열 매핑의 이해 (좌표 ➡️ 배열)&quot; data-og-description=&quot;프로그래밍을&amp;nbsp;하다&amp;nbsp;보면&amp;nbsp;좌표와&amp;nbsp;배열을&amp;nbsp;매핑하는&amp;nbsp;작업이&amp;nbsp;필요할&amp;nbsp;때가&amp;nbsp;많습니다.&amp;nbsp;특히 2차원 배열을 다루는 알고리즘 문제에서는 좌표 (x, y)를 배열에 올바르게 맵핑하는 것이 중요합니다&quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/224&quot; data-og-url=&quot;https://pixx.tistory.com/224&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wHqH2/hyYb5Il5GK/LNY5zcOawkCW2UmsTaRUI0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/djl1tl/hyYclErvpH/ZXvG1zkf8LsOc6h4JTwt70/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/nVoxh/hyYcbV8vn1/6SKRi4SkzYRW71t08dNwVK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/224&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/224&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wHqH2/hyYb5Il5GK/LNY5zcOawkCW2UmsTaRUI0/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/djl1tl/hyYclErvpH/ZXvG1zkf8LsOc6h4JTwt70/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512,https://scrap.kakaocdn.net/dn/nVoxh/hyYcbV8vn1/6SKRi4SkzYRW71t08dNwVK/img.png?width=512&amp;amp;height=512&amp;amp;face=0_0_512_512');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[JAVA] 좌표와 2차원 배열 매핑의 이해 (좌표 ➡️ 배열)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;프로그래밍을&amp;nbsp;하다&amp;nbsp;보면&amp;nbsp;좌표와&amp;nbsp;배열을&amp;nbsp;매핑하는&amp;nbsp;작업이&amp;nbsp;필요할&amp;nbsp;때가&amp;nbsp;많습니다.&amp;nbsp;특히 2차원 배열을 다루는 알고리즘 문제에서는 좌표 (x, y)를 배열에 올바르게 맵핑하는 것이 중요합니다&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;N과 M을 좌표형식으로 받아야하기 때문에 &lt;b&gt;기존의 행열&lt;/b&gt;처럼&lt;s&gt;&lt;b&gt; [행][열], [가로][세로]&lt;/b&gt;&lt;/s&gt;가 아닌 &lt;u&gt;&lt;b&gt;M은 가로&lt;/b&gt;, &lt;b&gt;N은 세로&lt;/b&gt;&lt;/u&gt;로 입력받습니다. 이는 좌표평면에서&lt;b&gt; (x,y) 형식&lt;/b&gt;을 따르기 위함입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;box&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;토마토의 상태를 저장하는 &lt;b&gt;3차원 배열&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;queue&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;BFS에서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;익은 토마토의 위치를 저장&lt;/b&gt;&lt;/span&gt;하는 큐&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;days&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;토마토가 모두 익는데 걸리는 &lt;b&gt;최소 날짜&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dx, dy, dz&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;b&gt;6방향&lt;/b&gt;(상,하,좌,우,앞,뒤)을 나타내는 &lt;b&gt;방향 배열&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 static 변수들은 전역적으로 사용되어 메서드 간에 데이터를 공유하는 데 사용됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;main 문&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;main 문제에서는 &lt;b&gt;BufferedReader클래스&lt;/b&gt;를 사용하여 입력을 빠르게 받아주고, &lt;b&gt;StringTokenizer 클래스&lt;/b&gt;를 사용하여 &lt;b&gt;공백을 기준&lt;/b&gt;으로 &lt;b&gt;토큰으로 분리&lt;/b&gt;해주었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그리고&lt;b&gt; static 변수를 초기화&lt;/b&gt;해주고, 토마토의 상태를 저장하는 배열인 box에다가 값을 넣어줍니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;마지막으로 bfs함수를 호출합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;bfs 함수&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;bfs함수에서는 각 레벨별로 그래프 탐색을 시작합니다. &lt;b&gt;size 만큼 반복문&lt;/b&gt;을 돌림으로써 &lt;u&gt;&lt;b&gt;같은 날짜에 익은 토마토들을 한꺼번에 처리&lt;/b&gt;&lt;/u&gt;할 수 있습니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;size는 &lt;b&gt;현재 레벨에서 처리해야 할 토마토의 개수&lt;/b&gt;를 나타내기 때문입니다.&lt;br /&gt;&lt;br /&gt;예를 들어 첫 번째 레벨에서&lt;b&gt; size가 3&lt;/b&gt;이라면, 이는 &lt;b&gt;처음부터 익어있던 토마토가 3개&lt;/b&gt;라는 의미이고, 이 3개의 토마토가 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;동시에&lt;/b&gt;&lt;/span&gt; 주변 토마토들에게 영향을 미치게 됩니다.&lt;br /&gt;&lt;br /&gt;이처럼 size를 통해 &lt;b&gt;같은 시점&lt;/b&gt;에 영향을 미치는 토마토들을 함께 처리함으로써, &lt;b&gt;정확한 일수 계산이 가능&lt;/b&gt;해집니다. 만약 size로 구분하지 않는다면, 서로 다른 날짜에 익어야 할 토마토들이 섞여서 처리될 수 있기 때문입니다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐에서 &lt;b&gt;현재 위치&lt;/b&gt;를 꺼내고(poll), 해당 위치에서 &lt;b&gt;6방향(상,하,좌,우,앞,뒤)으로의 탐색&lt;/b&gt;을 진행합니다.&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;범위 체크&lt;/b&gt;: 새로운 위치(nx,ny,nz)가 상자 범위 내에 있는지 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;익지 않은 토마토 체크&lt;/b&gt;: box[nz][nx][ny] == 0 인지 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;토마토 익히기&lt;/b&gt;: 조건을 만족하면 해당 위치의 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;토마토를 익힘(1로 변경)&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;위치 저장&lt;/b&gt;: 새롭게 익은 토마토의 위치를 &lt;b&gt;큐에 추가&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레벨의 모든 토마토를 처리한 후, &lt;s&gt;&lt;b&gt;큐가 비어있지 않다면&lt;/b&gt;&lt;/s&gt;(다음 날에 익을 토마토가 있다면) &lt;b&gt;days를 증가&lt;/b&gt;시킵니다.&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;큐에는 &lt;b&gt;새롭게 익은 토마토의 위치&lt;/b&gt;가 저장되어 있습니다. 즉, 다음날에 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;영향&lt;/b&gt;&lt;/span&gt;을 미칠 수 있는 &lt;b&gt;토마토들의 위치가 저장&lt;/b&gt;되어 있는 것입니다.&lt;br /&gt;&lt;br /&gt;만약 큐가 비어있다면, 이는 &lt;b&gt;더 이상 익을 수 있는 토마토가 없다는 것을 의미&lt;/b&gt;합니다. 이는 모든 토마토가 익었거나(&lt;b&gt;정상 종료&lt;/b&gt;), 더 이상 익힐 수 없는 토마토가 남아있는 경우(&lt;b&gt;비정상 종료&lt;/b&gt;)가 될 수 있습니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 과정을 큐가 빌 때까지(더 이상 익을 토마토가 없을 때까지) 반복합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;checkTomato 함수&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;checkTomate 함수에서는 간단하게 전체 박스의 토마토를 순회하면서 &lt;b&gt;0이 있는 지 없는 지 체크&lt;/b&gt;를 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;0이 있다는 의미는 BFS함수를 통해 탐색을 했음에도 &lt;b&gt;익지 않은 토마토가 남아있다&lt;/b&gt;는 의미입니다. 이는 &lt;b&gt;토마토가 모두 익지 못하는 상황&lt;/b&gt;이므로 &lt;b&gt;-1을 반환&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 0이 없다면 모든 토마토가 익었다는 의미이므로 &lt;b&gt;days를 반환&lt;/b&gt;하여 토마토가 모두 익는데 걸린 최소 일수를 출력합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Coding Test/백준</category>
      <category>BFS</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/709</guid>
      <comments>https://pixx.tistory.com/709#entry709comment</comments>
      <pubDate>Fri, 7 Feb 2025 16:05:10 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.07 - VO와 DTO는 같은 의미인가❓</title>
      <link>https://pixx.tistory.com/708</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ssish/btsL94ogYsx/ksFnEvojBQECJu9TnoO2aK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ssish/btsL94ogYsx/ksFnEvojBQECJu9TnoO2aK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ssish/btsL94ogYsx/ksFnEvojBQECJu9TnoO2aK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSsish%2FbtsL94ogYsx%2FksFnEvojBQECJu9TnoO2aK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;데이터를 다루는 객체를 설계하다 보면 &lt;b&gt;VO(Value Object)&lt;/b&gt;와 &lt;b&gt;DTO(Data Transfer Object)&lt;/b&gt;를 자주 마주하게 됩니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;얼핏 보면 비슷해 보이는 이 두 객체는 각각의 특성과 사용 목적이 명확히 다릅니다. 이번 글에서는 &lt;b&gt;VO와 DTO의 차이점&lt;/b&gt;에 대해 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;VO(Value Object)란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;VO는 &lt;b&gt;도메인&lt;/b&gt;에서 &lt;b&gt;한 개&lt;/b&gt; 또는 &lt;b&gt;그 이상의 &lt;u&gt;속성&lt;/u&gt;&lt;u&gt;들을 묶어서 특정 값을 나타내는 객체&lt;/u&gt;&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 VO(Value Object)는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;값을 표현하는 객체&lt;/b&gt;&lt;/span&gt;로, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;불변(immutable)&lt;/b&gt;&lt;/span&gt; 특성을 가지며, &lt;b&gt;동일한 값&lt;/b&gt;을 가지면&lt;b&gt; 같은 객체로 취급&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;VO 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738856400613&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// VO: 값 자체를 표현, 불변
public class Money {
    private final int amount;  // 불변(final)
    
    public Money(int amount) {
        this.amount = amount;
    }
    
    // 새로운 객체 생성
    public Money add(Money other) {
        return new Money(this.amount + other.amount);
    }
    
    // 값이 같으면 같은 객체
    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof Money)) return false;
        return amount == ((Money)obj).amount;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;VO의 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt; 불변성(Immutable)&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;번 생성된 후 &lt;b&gt;값을&lt;/b&gt; &lt;s&gt;&lt;b&gt;변경&lt;/b&gt;&lt;/s&gt;할 수 없음&lt;/li&gt;
&lt;li&gt;값 변경이 필요한 경우 &lt;b&gt;새로운 객체 생성&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt; 동등성(Equality)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 속성값이 &lt;b&gt;같다면&lt;/b&gt; &lt;b&gt;같은 객체로 판단&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;equals()와 hashCode() 메서드 재정의 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;DTO(Data Transfer Object)란❓&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;523&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/x3GwY/btsMa6Fpdmm/NKPnPrF4tkhP9zW2fhD4B1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x3GwY/btsMa6Fpdmm/NKPnPrF4tkhP9zW2fhD4B1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x3GwY/btsMa6Fpdmm/NKPnPrF4tkhP9zW2fhD4B1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx3GwY%2FbtsMa6Fpdmm%2FNKPnPrF4tkhP9zW2fhD4B1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;399&quot; height=&quot;372&quot; data-origin-width=&quot;523&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;DTO는 계층 간 &lt;u&gt;&lt;b&gt;데이터 전송을 위해 사용되는 객체&lt;/b&gt;&lt;/u&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DTO(Data Transfer Object)&lt;/b&gt;는 애플리케이션의 다양한 레이어나 시스템 간에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;데이터를 전송&lt;/b&gt;&lt;/u&gt;하기 위해 사용하는 &lt;b&gt;단순화된 데이터 구조&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #353638; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DTO&lt;/b&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터 전송에 필요한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;필드만&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;포함&lt;/b&gt;하며, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;비즈니스 로직이나 메서드는 포함&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;하지 않아 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;데이터의 효율적 전송&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;관리가 용이&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;DTO 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738856432646&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// DTO: 데이터 전달용
public class UserDTO {
    private String name;    // 가변
    private int age;       // 가변
    
    // getter/setter
    public void setName(String name) {
        this.name = name;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;DTO의 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&lt;span&gt; 가변성(Mutable&lt;/span&gt;)&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;setter&lt;/b&gt;를 통한&lt;u&gt;&lt;b&gt; 값 변경 가능&lt;/b&gt;&lt;/u&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 전달이 주 목적&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt;&lt;span&gt;&lt;span&gt; 동일성(Identity&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;인스턴스가 다르면&lt;/b&gt; &lt;b&gt;다른 객체로 취급&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;값이 모두 같아도 &lt;b&gt;별개의 객체&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt; 단순 데이터 전달&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Getter/setter 외 비즈니스 로직 &lt;s&gt;&lt;b&gt;미포함&lt;/b&gt;&lt;/s&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;DTO(Data Transfer Object)란❓&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 150px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.5426%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.124%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;VO (Value Object)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;DTO (Data Tranfer Object)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.5426%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.124%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;값 자체를 표현&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;데이터 전달&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 15.5426%; height: 40px; text-align: center;&quot;&gt;&lt;b&gt;가변 / 불변&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.124%; height: 40px; text-align: center;&quot;&gt;&lt;b&gt;✅ 불변성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 40px; text-align: center;&quot;&gt;&lt;b&gt;setter 존재 시 &lt;span style=&quot;color: #006dd7;&quot;&gt;가변&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;setter 미 존재 시 &lt;span style=&quot;color: #ee2323;&quot;&gt;불변&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 15.5426%; height: 25px; text-align: center;&quot;&gt;&lt;b&gt;동등 결정&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.124%; height: 25px; text-align: center;&quot;&gt;&lt;b&gt;송성값이 모두 같으면 같은 객체 &lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;✅&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 25px; text-align: center;&quot;&gt;&lt;b&gt;속성값이 모두 같아도 같은 객체 &lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;❌&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 15.5426%; height: 25px; text-align: center;&quot;&gt;&lt;b&gt;로직&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.124%; height: 25px; text-align: center;&quot;&gt;&lt;b&gt;getter/setter외의 로직을 포함할 수 있다.&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 25px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;getter/setter외의 로직을 갖지 않는다.&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 15.5426%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;사용 예시&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 51.124%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;금액, 좌표, 날짜 등&amp;nbsp;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;API 요청 / 응답 데이터&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 설계의 대가이자 리팩토링, 엔터프라이즈 애플리케이션 아키텍처 패턴의 선구자인 &lt;b&gt;마틴 파울러&lt;/b&gt;의 저서에 따르면 &lt;b&gt;DTO와 VO의 개념이 혼용되어 개발자 커뮤니티에 혼란을 초래했다&lt;/b&gt;고 언급한 바 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 저를 포함하여 많은 개발자들이 두 개념을 유사하게 인식하는 이유는 &lt;b&gt;&lt;u&gt;둘 다 데이터를 전달&lt;/u&gt;하는 역할을 하기 때문&lt;/b&gt;인 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;VO&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;동일한 값을 가지면 같은 객체로 판단하는 &lt;span style=&quot;color: #ee2323;&quot;&gt;불변 객체&lt;/span&gt;&lt;/b&gt;이며, &lt;b&gt;비즈니스 로직을 포함&lt;/b&gt;할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면, &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;DTO&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;단순한 데이터 전달 객체&lt;/b&gt;로, &lt;s&gt;&lt;b&gt;불변성을 보장&lt;/b&gt;&lt;/s&gt;하지 않으며 &lt;s&gt;&lt;b&gt;비즈니스 로직을 포함&lt;/b&gt;&lt;/s&gt;하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>dto</category>
      <category>til</category>
      <category>vo</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/708</guid>
      <comments>https://pixx.tistory.com/708#entry708comment</comments>
      <pubDate>Fri, 7 Feb 2025 13:02:17 +0900</pubDate>
    </item>
    <item>
      <title>[백준, 14888번] 연산자 끼워넣기 (브루트 포스, 백트래킹, Java)</title>
      <link>https://pixx.tistory.com/707</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kDy0r/btsL9RhTSWq/GNslj0tjje0pkMCo06kua0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kDy0r/btsL9RhTSWq/GNslj0tjje0pkMCo06kua0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kDy0r/btsL9RhTSWq/GNslj0tjje0pkMCo06kua0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkDy0r%2FbtsL9RhTSWq%2FGNslj0tjje0pkMCo06kua0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문제설명&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2430&quot; data-origin-height=&quot;1278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ohy1W/btsL95fOoWw/qt8kA9t9IdplMIhKHdHcSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ohy1W/btsL95fOoWw/qt8kA9t9IdplMIhKHdHcSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ohy1W/btsL95fOoWw/qt8kA9t9IdplMIhKHdHcSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fohy1W%2FbtsL95fOoWw%2Fqt8kA9t9IdplMIhKHdHcSK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;368&quot; data-origin-width=&quot;2430&quot; data-origin-height=&quot;1278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2574&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MdhVr/btsL966Q9xm/CTZR4uyDxzMzmXRotVpzv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MdhVr/btsL966Q9xm/CTZR4uyDxzMzmXRotVpzv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MdhVr/btsL966Q9xm/CTZR4uyDxzMzmXRotVpzv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMdhVr%2FbtsL966Q9xm%2FCTZR4uyDxzMzmXRotVpzv0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;138&quot; data-origin-width=&quot;2574&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입력 &amp;amp; 출력&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2408&quot; data-origin-height=&quot;572&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUv75p/btsL87rTEWp/wewI52k45T6Bjkd2Qlgyc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUv75p/btsL87rTEWp/wewI52k45T6Bjkd2Qlgyc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUv75p/btsL87rTEWp/wewI52k45T6Bjkd2Qlgyc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUv75p%2FbtsL87rTEWp%2FwewI52k45T6Bjkd2Qlgyc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;166&quot; data-origin-width=&quot;2408&quot; data-origin-height=&quot;572&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2224&quot; data-origin-height=&quot;1294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Px6Lz/btsL8HtK2QB/rluok8BPiM1hL8Axek1zG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Px6Lz/btsL8HtK2QB/rluok8BPiM1hL8Axek1zG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Px6Lz/btsL8HtK2QB/rluok8BPiM1hL8Axek1zG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPx6Lz%2FbtsL8HtK2QB%2Frluok8BPiM1hL8Axek1zG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;407&quot; data-origin-width=&quot;2224&quot; data-origin-height=&quot;1294&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나의 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14888&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준 - 연산자 끼워넣기&quot;&lt;/b&gt;&lt;/a&gt; 문제는 N개의 수열이 주어지고, N-1개의 연산자가 +, -, * ,/ 순서대로 주어질 때 각 수와 연산자를 조합해서 최댓값과 최솟값을 구하는 문제입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 때 식의 계산은 &lt;s&gt;&lt;b&gt;기존의 연산자 우선 순위를 무시&lt;/b&gt;&lt;/s&gt;하고 앞에서부터 진행해야 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;수열의 &lt;b&gt;끝까지&lt;/b&gt; &lt;b&gt;연산자를 조합&lt;/b&gt;해서 &lt;b&gt;계산&lt;/b&gt;해야 하며, 각 연산자의 &lt;b&gt;개수가 제한&lt;/b&gt;되어 있어 특정 연산자를 더 이상 사용할 수 없는 경우가 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738822567422&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;수열: [1, 2, 3, 4, 5]
연산자: [+(1개), -(2개), *(1개), /(0개)]&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 입력이 주어질 때&amp;nbsp;&lt;b&gt; '+' 연산자&lt;/b&gt;는 &lt;b&gt;1번 사용&lt;/b&gt;을 하면 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;s&gt;&lt;b&gt;더 이상 사용&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;하지 못합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 특성 때문에 &lt;u&gt;&lt;b&gt;가능한 모든 경우를 탐색&lt;/b&gt;&lt;/u&gt;하되, &lt;b&gt;특정 연산자를 더 이상 사용할 수 없는 경우&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;탐색을 중단&lt;/b&gt;하는 &lt;b&gt;백트래킹 방식&lt;/b&gt;&lt;/u&gt;을 사용하면 효율적으로 문제를 해결할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;168&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ngldu/btsL9n85HtK/b8C2pA1mwJS9tY12ptAo40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ngldu/btsL9n85HtK/b8C2pA1mwJS9tY12ptAo40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ngldu/btsL9n85HtK/b8C2pA1mwJS9tY12ptAo40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fngldu%2FbtsL9n85HtK%2Fb8C2pA1mwJS9tY12ptAo40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;429&quot; height=&quot;168&quot; data-origin-width=&quot;429&quot; data-origin-height=&quot;168&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;예제 입력2를 수열과 연산자로 표현하면 위와 같습니다. 이 수열과 연산자를 &lt;b&gt;DFS 알고리즘&lt;/b&gt;과 &lt;b&gt;백트래킹&lt;/b&gt;을 통해 접근하는 과정을 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;613&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPcOjz/btsL8NniGKA/tR9ccQPkk0b5E0o0NG8YA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPcOjz/btsL8NniGKA/tR9ccQPkk0b5E0o0NG8YA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPcOjz/btsL8NniGKA/tR9ccQPkk0b5E0o0NG8YA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPcOjz%2FbtsL8NniGKA%2FtR9ccQPkk0b5E0o0NG8YA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;538&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;613&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 문제의 핵심은 &lt;b&gt;DFS와 백트래킹&lt;/b&gt;을 활용하여 가능한 &lt;b&gt;모든 연산자 조합을 탐색&lt;/b&gt;하는 것입니다. 위 그림과 같이, &lt;b&gt;매 단계&lt;/b&gt;에서 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;사용 가능한 연산자&lt;/b&gt;&lt;/span&gt;를 선택하여&lt;b&gt; 연산을 수행&lt;/b&gt;하고, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;해당 연산자의 개수를 감소&lt;/b&gt;&lt;/span&gt;시킵니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 &lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;하늘색 노드&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;현재 사용 가능한 연산자&lt;/b&gt;&lt;/span&gt;를, &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;분홍색 노드&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;이미 사용한 연산자&lt;/b&gt;&lt;/span&gt;를 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS를 통해&lt;b&gt; 더 깊은 단계로 진행&lt;/b&gt;하면서 &lt;b&gt;남은 연산자들로 계산&lt;/b&gt;을 이어가고, 최종적으로 수열의 &lt;b&gt;끝까지 도달&lt;/b&gt;하면 그 &lt;b&gt;결과값을 저장&lt;/b&gt;합니다. 이러한 과정을 통해 가능한 모든 조합의 결과값들 중 &lt;i&gt;&lt;b&gt;최댓값(35) &lt;/b&gt;&lt;/i&gt;과 &lt;i&gt;&lt;b&gt;최솟값(17)&lt;/b&gt;&lt;/i&gt;을 찾아낼 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;2758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbwUxL/btsL8IlSWq1/nPWdezHGkJklLi1dY8F9Qk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbwUxL/btsL8IlSWq1/nPWdezHGkJklLi1dY8F9Qk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbwUxL/btsL8IlSWq1/nPWdezHGkJklLi1dY8F9Qk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbwUxL%2FbtsL8IlSWq1%2FnPWdezHGkJklLi1dY8F9Qk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;1128&quot; data-origin-width=&quot;1712&quot; data-origin-height=&quot;2758&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;코드는 크게 2가지로 구분되어 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. main 문&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;main 문에서는 입력을 BufferedReader 클래스와 StringTokeinzer클래스를 사용하여 빠른 입력처리와 토큰을 사용하여 분리를 해주었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. dfs 함수&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;dfs함수에서는 중요한 부분은 크게 2가지로 나뉩니다. DFS 알고리즘에서 중요한 &lt;b&gt;탈출 조건&lt;/b&gt;과 &lt;b&gt;재귀 호출&lt;/b&gt;입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;num[]&lt;/b&gt; : 순열을 저장한 배열&lt;/li&gt;
&lt;li&gt;&lt;b&gt;op[]&lt;/b&gt; : 연산자의 개수를 순서대로 저장한 배열&lt;/li&gt;
&lt;li&gt;&lt;b&gt;count&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;사용한 연산자의 개수&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;다음에 사용할 숫자의 인덱스를 결정 (count + 1)&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;currValue&lt;/b&gt; : 현재까지의 계산 결과&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DFS 함수는 &lt;b&gt;크게 두 부분&lt;/b&gt;으로 구성됩니다. &lt;b&gt;먼저 탈출 조건을 확인&lt;/b&gt;하고, &lt;b&gt;그 다음 가능한 연산자들을 탐색&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;탈출 조건은 단순합니다. 문제에서&lt;b&gt; N개의 숫자&lt;/b&gt;와 &lt;b&gt;N-1개의 연산자&lt;/b&gt;가 주어지므로, &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;사용한 연산자의 개수(count)&lt;/b&gt;&lt;/span&gt;가&lt;b&gt; N-1과 같아지면&lt;/b&gt; &lt;u&gt;&lt;b&gt;모든 연산자를 사용했다는 의미&lt;/b&gt;&lt;/u&gt;입니다. 이 시점에서 &lt;b&gt;현재까지의 계산 결과&lt;/b&gt;와 &lt;b&gt;이전에 저장된 최댓값, 최솟값&lt;/b&gt;을 &lt;b&gt;비교하여 갱신&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자 탐색 과정에서는 &lt;b&gt;네 가지 연산자(+, -, *, /)&lt;/b&gt;에 대해 반복문을 수행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 연산자의 남은 개수가 &lt;b&gt;0보다 크다면&lt;/b&gt;, &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;해당 연산자를 사용할 수 있다&lt;/b&gt;&lt;/span&gt;는 의미입니다. 연산자를 선택하면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;그 개수를 1 감소&lt;/b&gt;&lt;/span&gt;시키고, 선택한 연산자로 계산을 수행한 결과값과 함께 &lt;u&gt;&lt;b&gt;다음 단계(count + 1)로 재귀 호출을 진행&lt;/b&gt;&lt;/u&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 과정을 통해 가능한 &lt;b&gt;모든 연산자 조합을 탐색&lt;/b&gt;하면서, 최적의 결과값을 찾아낼 수 있습니다.&lt;/p&gt;</description>
      <category>Coding Test/백준</category>
      <category>백트래킹</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/707</guid>
      <comments>https://pixx.tistory.com/707#entry707comment</comments>
      <pubDate>Thu, 6 Feb 2025 16:04:08 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.06 - 호출 스택(Call Stack)의 동작 원리와 예제로 이해하기</title>
      <link>https://pixx.tistory.com/706</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4F0RU/btsL9exaGSx/mEqK4WVrrSQDkanegYVQL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4F0RU/btsL9exaGSx/mEqK4WVrrSQDkanegYVQL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4F0RU/btsL9exaGSx/mEqK4WVrrSQDkanegYVQL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4F0RU%2FbtsL9exaGSx%2FmEqK4WVrrSQDkanegYVQL1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;321&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;호출 스택(Call Stack)이란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;콜 스택(Call Stack)&lt;/b&gt;은 프로그램에서 &lt;u&gt;&lt;b&gt;메서드(함수) 호출을 추적하는 메모리 영역&lt;/b&gt;&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; LIFO(Last In, First Out) 구조&lt;/b&gt;를 가지며, &lt;b&gt;가장 마지막에 호출된 함수&lt;/b&gt;가 &lt;b&gt;먼저 실행 완료&lt;/b&gt;되어 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제거&lt;/b&gt;&lt;/span&gt;됩니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;콜 스택의 기본 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;LIFO(Last In First Out) 방식&lt;/b&gt;으로 동작&lt;/li&gt;
&lt;li&gt;&lt;b&gt;각 스레드마다 &lt;u&gt;독립적&lt;/u&gt;인 콜스택 보유&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;메소드 호출 시 스택 프레임(Stack Frame) 생성&lt;/li&gt;
&lt;li&gt;메소드 실행 완료 시 해당 프레임 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;콜 스택의 동작 원리&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;함수 호출 시 스택 프레임(Stack Frame) &lt;span style=&quot;color: #006dd7;&quot;&gt;추가&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수가 호출될 때, 해당 함수의 &lt;b&gt;매개변수, 지역 변수, 반환 주소&lt;/b&gt; 등의 정보가 담긴 &lt;b&gt;스택 프레임&lt;/b&gt;이 스택에 쌓입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함수 실행 완료 시 스택 프레임 &lt;span style=&quot;color: #ee2323;&quot;&gt;제거&lt;/span&gt;&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 실행이 끝나면, 해당 &lt;b&gt;스택 프레임이 제거(Pop)&lt;/b&gt; 되며, 이전 함수로 돌아갑니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메인 함수 종료 시 스택 비움&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그램의 main() 함수까지 종료되면, &lt;b&gt;스택이 완전히 비워집니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;호출 스택(Call Stack) 동작 과정&lt;/h3&gt;
&lt;pre id=&quot;code_1738770311167&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt; public class CallStack {
    public static void main(String[] args) {
        System.out.println(&quot;main() 호출&quot;);
        first();
        System.out.println(&quot;main() 종료&quot;);
    }

    public static void first() {
        System.out.println(&quot;first() 호출&quot;);
        second();
        System.out.println(&quot;first() 종료&quot;);
    }

    public static void second() {
        System.out.println(&quot;second() 호출&quot;);
        third();
        System.out.println(&quot;second() 종료&quot;);
    }

    public static void third() {
        System.out.println(&quot;third() 호출&quot;);
        System.out.println(&quot;Hello from third()&quot;);
        System.out.println(&quot;third() 종료&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;실행 결과&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738770379608&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;main() 호출
first() 호출
second() 호출
third() 호출
Hello from third()
third() 종료
second() 종료
first() 종료
main() 종료&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 실행 결과에서 알 수 있듯이 메소드가 호출되는 &lt;u&gt;&lt;b&gt;순서대로 스택에 쌓이고(push),&lt;/b&gt;&lt;/u&gt; 각 메소드의 실행이 &lt;b&gt;완료&lt;/b&gt;되면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;역순으로 스택에서 제거&lt;/b&gt;&lt;/span&gt;&lt;b&gt;(pop)&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;처음 main() 메소드가 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;호출&lt;/b&gt;&lt;/span&gt;되고&lt;/li&gt;
&lt;li&gt;main() 내부에서 first()가 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;호출&lt;/b&gt;&lt;/span&gt;되고&lt;/li&gt;
&lt;li&gt;first() 내부에서 second()가 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;호출&lt;/b&gt;&lt;/span&gt;되고&lt;/li&gt;
&lt;li&gt;second() 내부에서 third()가 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;호출&lt;/b&gt;&lt;/span&gt;됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 third() 메소드의 실행이 완료되면서부터 &lt;u&gt;&lt;b&gt;역순&lt;/b&gt;&lt;/u&gt;으로&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;third()가 종료되어 스택에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제거&lt;/b&gt;&lt;/span&gt;되고&lt;/li&gt;
&lt;li&gt;second()가 종료되어 스택에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제거&lt;/b&gt;&lt;/span&gt;되고&lt;/li&gt;
&lt;li&gt;first()가 종료되어 스택에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제거&lt;/b&gt;&lt;/span&gt;되고&lt;/li&gt;
&lt;li&gt;마지막으로 main()이 종료되어 스택에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제거&lt;/b&gt;&lt;/span&gt;됩니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 바로 콜스택의 &lt;b&gt;LIFO(Last In First Out) 구조&lt;/b&gt;를 보여줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/706</guid>
      <comments>https://pixx.tistory.com/706#entry706comment</comments>
      <pubDate>Thu, 6 Feb 2025 00:50:52 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.05 - 하노이 탑 알고리즘, 왜 재귀여야 할까❓</title>
      <link>https://pixx.tistory.com/704</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s4U6p/btsL6Tm4ehZ/cGbgNExEmdBqhSpWOG6zik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s4U6p/btsL6Tm4ehZ/cGbgNExEmdBqhSpWOG6zik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s4U6p/btsL6Tm4ehZ/cGbgNExEmdBqhSpWOG6zik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs4U6p%2FbtsL6Tm4ehZ%2FcGbgNExEmdBqhSpWOG6zik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하노이 탑 알고리즘은 다음과 같은 규칙을 가집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;한 번에 하나의 원반만 이동 가능&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;&lt;i&gt;&lt;b&gt;큰 원반이 작은 원반 위에 올 수 없음&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 규칙을 보면 &lt;b&gt;맨 위의 원반부터 이동&lt;/b&gt;하므로 &lt;b&gt;선입선출 구조인 큐&lt;/b&gt;나 &lt;b&gt;배열&lt;/b&gt;의 사용을 고려할 수 있습니다. 하지만 하노이 탑은 &lt;u&gt;&lt;b&gt;대표적인 재귀 문제&lt;/b&gt;&lt;/u&gt;로 알려져 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서는 하노이 탑 알고리즘에서 &lt;b&gt;재귀 호출이 더 적합한 이유&lt;/b&gt;에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;왜 하노이 탑 문제에서 재귀를 사용해야할까❓&amp;nbsp;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;하노이 탑 문제 간단 소개&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하노이 탑은 &lt;b&gt;세 개의 기둥&lt;/b&gt;과&lt;b&gt; 크기가 다른 원판&lt;/b&gt;들로 구성된 퍼즐입니다.&lt;/li&gt;
&lt;li&gt;모든 원판을 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;처음 기둥&lt;/b&gt;&lt;/span&gt;에서 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;마지막 기둥&lt;/b&gt;&lt;/span&gt;으로 옮기되, &lt;b&gt;큰 원판 위에 작은 원판만이 올 수 있습니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;이러한 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;분할 정복(Divide and Conquer) 방식&lt;/b&gt;&lt;/span&gt;은 &lt;b&gt;재귀 호출과 자연스럽게 어울&lt;/b&gt;립니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 문제의 자기 유사성&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;하노이 탑&lt;/b&gt;은 &quot;&lt;u&gt;&lt;b&gt;더 작은 하노이 탑 문제&lt;/b&gt;&lt;/u&gt;&quot;로 나눌 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;n개의 원판&lt;/b&gt;을 이동하는 문제는 &quot;&lt;u&gt;&lt;b&gt;(n-1)개의 원판을 이동하는 문제&lt;/b&gt;&lt;/u&gt;&quot;로 분해할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 상태 관리의 단순화&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;큐&lt;/b&gt;나 &lt;b&gt;배열&lt;/b&gt;을 사용하면 &lt;b&gt;각 기둥의 상태를 &lt;span style=&quot;color: #ee2323;&quot;&gt;직접 관리&lt;/span&gt;&lt;/b&gt;해야 합니다.&lt;/li&gt;
&lt;li&gt;반면 &lt;b&gt;재귀를 사용&lt;/b&gt;하면 &lt;u&gt;&lt;b&gt;&quot;어떤 원판을 어디로 옮길지&quot;에만 집중&lt;/b&gt;&lt;/u&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;재귀 호출의 &lt;b&gt;콜 스택&lt;/b&gt;이 자연스럽게 원판의 순서를 보장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. 직관적인 문제 해결 방식&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;큰 문제&lt;/b&gt;를 &lt;b&gt;동일한 형태의 작은 문제&lt;/b&gt;로 나누어 해결하는 방식이 직관적입니다.&lt;/li&gt;
&lt;li&gt;원판 3개를 옮기는 과정을 생각해보면:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위의 &lt;b&gt;2개 원판&lt;/b&gt;을 &lt;b&gt;보조 기둥으로 이동&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가장 큰 원판&lt;/b&gt;을 &lt;b&gt;목적지로 이동&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2개 원판&lt;/b&gt;을 &lt;b&gt;다시 목적지로 이동&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. 코드의 간결성&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복문으로 구현할 경우 여러 조건문과 상태 체크가 필요합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;재귀를 사용&lt;/b&gt;하면 문제의 본질적인 로직만 남겨 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;코드가 간결&lt;/b&gt;&lt;/span&gt;해집니다.&lt;/li&gt;
&lt;li&gt;코드의 가독성과 유지보수성이 향상됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;5. 스택을 활용한 비재귀적 접근 가능성&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하노이 탑 문제는 본질적으로 &lt;b&gt;재귀적&lt;/b&gt;이지만, 명시적으로 &lt;b&gt;스택(Stack) 자료구조&lt;/b&gt;를 활용하면&lt;b&gt; 반복문으로도 구현&lt;/b&gt;할 수 있습니다.&lt;/li&gt;
&lt;li&gt;그러나 이 방법은 재귀 호출이 내부적으로 활용하는 &lt;b&gt;콜 스택(Call Stack)&lt;/b&gt;을 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;직접 관리&lt;/b&gt;&lt;/span&gt;해야 하므로 코드가 복잡해질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>til</category>
      <category>재귀</category>
      <category>하노이 탑</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/704</guid>
      <comments>https://pixx.tistory.com/704#entry704comment</comments>
      <pubDate>Wed, 5 Feb 2025 01:56:58 +0900</pubDate>
    </item>
    <item>
      <title>[정보처리기사] 합격 후기 및 학습 사이트 추천</title>
      <link>https://pixx.tistory.com/702</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;제가 응시했던 회차는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;2022년 2회 정보처리기사 시험&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; 블로그를 옮기면서 미처 옮기지 못했고, 시험을 오래전에 보긴했지만 제가 봤던 2022년 2회차 시험은 필기와 실기 모두 낮은 합격률을 보였기 때문에 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;합격 후기 및 공부방법에 대해서 정리하고자합니다..!&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;688&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckrCLW/btsL9O5PvWv/vzgGtl8NOCvhKtXaOdnL9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckrCLW/btsL9O5PvWv/vzgGtl8NOCvhKtXaOdnL9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckrCLW/btsL9O5PvWv/vzgGtl8NOCvhKtXaOdnL9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckrCLW%2FbtsL9O5PvWv%2FvzgGtl8NOCvhKtXaOdnL9K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;473&quot; height=&quot;688&quot; data-origin-width=&quot;473&quot; data-origin-height=&quot;688&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;179&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCbIVR/btsL76z7SxD/w8MjxTmiV24CijjEtEgwtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCbIVR/btsL76z7SxD/w8MjxTmiV24CijjEtEgwtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCbIVR/btsL76z7SxD/w8MjxTmiV24CijjEtEgwtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCbIVR%2FbtsL76z7SxD%2Fw8MjxTmiV24CijjEtEgwtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;815&quot; height=&quot;179&quot; data-origin-width=&quot;815&quot; data-origin-height=&quot;179&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;정보처리기사 - 필기 책 : 시나공&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;536&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OZY7T/btsL9auLjDe/dekowibWbeVAlKYDNA60c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OZY7T/btsL9auLjDe/dekowibWbeVAlKYDNA60c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OZY7T/btsL9auLjDe/dekowibWbeVAlKYDNA60c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOZY7T%2FbtsL9auLjDe%2FdekowibWbeVAlKYDNA60c0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;399&quot; height=&quot;536&quot; data-origin-width=&quot;399&quot; data-origin-height=&quot;536&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필기는 시나공책을 구매했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다른 자격증들은 수제비를 구매했지만 이번에는 시나공도 경험을 해보고 싶어 시나공으로 결정을 했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;전공자이지만 당시에는 더욱 더 말하는 감자였습니다...ㅎ&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필기는 아무래도 문제를 많이 풀어보고&lt;b&gt; 암기가 중요&lt;/b&gt;하다고 생각했기 때문에 1달 전 부터 &lt;b&gt;2회독&lt;/b&gt;을 하고 난 뒤 &lt;b&gt;기출문제&lt;/b&gt;를 일주일 동안 풀었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;지금은 필기는 CBT를 통해서 보는 것 같기도 했는데 당시에는 실기와 마찬가지로 직접 가서 봐야했었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;422&quot; data-origin-height=&quot;667&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vdbXB/btsL8WXOCc2/K6kZui2CKhWkWfUIMppke1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vdbXB/btsL8WXOCc2/K6kZui2CKhWkWfUIMppke1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vdbXB/btsL8WXOCc2/K6kZui2CKhWkWfUIMppke1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvdbXB%2FbtsL8WXOCc2%2FK6kZui2CKhWkWfUIMppke1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;632&quot; data-origin-width=&quot;422&quot; data-origin-height=&quot;667&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;정보처리기사 - 실기 책 : 수제비&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;496&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbqg21/btsL7D5YTub/2nwhqpHgJSFHXQKfEDHy41/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbqg21/btsL7D5YTub/2nwhqpHgJSFHXQKfEDHy41/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbqg21/btsL7D5YTub/2nwhqpHgJSFHXQKfEDHy41/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbbqg21%2FbtsL7D5YTub%2F2nwhqpHgJSFHXQKfEDHy41%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;439&quot; data-origin-width=&quot;395&quot; data-origin-height=&quot;496&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;실기 책은 &lt;b&gt;수제비&lt;/b&gt;를 구매했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필기에서 시나공을 경험했지만, 실기에서는 &lt;b&gt;암기&lt;/b&gt;나 &lt;b&gt;이해&lt;/b&gt;보다는 &lt;b&gt;문제를 좀 더 많이 풀어봐야한다고 생각&lt;/b&gt;했기 때문에 수제비의 트레이드 마크인 &lt;u&gt;&lt;b&gt;두음법칙&lt;/b&gt;&lt;/u&gt;과 &lt;b&gt;개념&lt;/b&gt;이 잘 정리되어있어서 &lt;b&gt;문제 풀이에 집중&lt;/b&gt;할 수 있었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;정보처리기사는 위에 자료에서 알 수 있듯이 필기보다 실기의 합격률이 낮습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 필기의 준비 기간보다 좀 더 써서 여유롭게 2달전 부터 천천히 회독을 시작했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필기와 마찬가지로 &lt;b&gt;2회독&lt;/b&gt;을 하고, 똑같이 &lt;b&gt;문제풀이에 집중&lt;/b&gt;했습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;도움을 준 사이트&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;아무래도 SQLD나 ADsP와 같은 자격증보다 좀 더 어렵기도하고, 시간이 많이 소요되는 자격증이었습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;필기와 실기 모두 공통적으로 도움을 준 사이트와 카페를 공유하고자 합니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;giphy.gif&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RhpH2/btsL89bz7dk/x1MlkU3Wag2uqqy6j4dPt0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RhpH2/btsL89bz7dk/x1MlkU3Wag2uqqy6j4dPt0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RhpH2/btsL89bz7dk/x1MlkU3Wag2uqqy6j4dPt0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/RhpH2/btsL89bz7dk/x1MlkU3Wag2uqqy6j4dPt0/img.gif&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;300&quot; height=&quot;300&quot; data-filename=&quot;giphy.gif&quot; data-origin-width=&quot;500&quot; data-origin-height=&quot;500&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. 전자 문제집 CBT&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure id=&quot;og_1738772780850&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;정보처리기사 필기 기출문제 및 CBT 2022년 04월 24일(2회) - 정보처리기사 필기 기출문제 전자문제&quot; data-og-description=&quot;위 이미지를 클릭하시면 전자문제집 CBT 서버에 접속 됩니다. (해설, 모의고사, 오답노트, 워드, 컴활, 기능사 등 상설검정 CBT 프로그램 기능 포함) 전자문제집 CBT란? 인터넷으로 문제를 풀고 자동&quot; data-og-host=&quot;www.comcbt.com&quot; data-og-source-url=&quot;https://www.comcbt.com/xe/iz/5851061&quot; data-og-url=&quot;https://www.comcbt.com/xe/iz/5851061&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/pLNVf/hyYb8EJUC2/4TSRcsk5czMHJuVHPwBvLk/img.jpg?width=290&amp;amp;height=80&amp;amp;face=0_0_290_80&quot;&gt;&lt;a href=&quot;https://www.comcbt.com/xe/iz/5851061&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.comcbt.com/xe/iz/5851061&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/pLNVf/hyYb8EJUC2/4TSRcsk5czMHJuVHPwBvLk/img.jpg?width=290&amp;amp;height=80&amp;amp;face=0_0_290_80');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;정보처리기사 필기 기출문제 및 CBT 2022년 04월 24일(2회) - 정보처리기사 필기 기출문제 전자문제&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;위 이미지를 클릭하시면 전자문제집 CBT 서버에 접속 됩니다. (해설, 모의고사, 오답노트, 워드, 컴활, 기능사 등 상설검정 CBT 프로그램 기능 포함) 전자문제집 CBT란? 인터넷으로 문제를 풀고 자동&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.comcbt.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. 시나공 CBT 동영상&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure id=&quot;og_1738772875569&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;시나공&quot; data-og-description=&quot;컴활, 정보처리, 워드프로세서 등 IT 자격증 전문. 해설 포함 CBT, 최신 기출 자료 무료, 실기 채점 프로그램 제공&quot; data-og-host=&quot;www.sinagong.co.kr&quot; data-og-source-url=&quot;https://www.sinagong.co.kr/pds/001001001/books&quot; data-og-url=&quot;https://www.sinagong.co.kr&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cuz1aX/hyX7SQ3pU1/JNEU14ql3WedUHZcjsEB90/img.png?width=349&amp;amp;height=349&amp;amp;face=0_0_349_349,https://scrap.kakaocdn.net/dn/cmV26c/hyYb8xZCBx/QFDoMSO0ECNYAqBod6jtfk/img.png?width=349&amp;amp;height=349&amp;amp;face=0_0_349_349,https://scrap.kakaocdn.net/dn/59KSx/hyYb9czPYD/fsKGIHCpwLGzbStEhZSekk/img.jpg?width=752&amp;amp;height=297&amp;amp;face=0_0_752_297&quot;&gt;&lt;a href=&quot;https://www.sinagong.co.kr/pds/001001001/books&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.sinagong.co.kr/pds/001001001/books&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cuz1aX/hyX7SQ3pU1/JNEU14ql3WedUHZcjsEB90/img.png?width=349&amp;amp;height=349&amp;amp;face=0_0_349_349,https://scrap.kakaocdn.net/dn/cmV26c/hyYb8xZCBx/QFDoMSO0ECNYAqBod6jtfk/img.png?width=349&amp;amp;height=349&amp;amp;face=0_0_349_349,https://scrap.kakaocdn.net/dn/59KSx/hyYb9czPYD/fsKGIHCpwLGzbStEhZSekk/img.jpg?width=752&amp;amp;height=297&amp;amp;face=0_0_752_297');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;시나공&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;컴활, 정보처리, 워드프로세서 등 IT 자격증 전문. 해설 포함 CBT, 최신 기출 자료 무료, 실기 채점 프로그램 제공&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.sinagong.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;3. 필기 기출 문제 CBT&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure id=&quot;og_1738772924486&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;정보처리기사 객관식 필기 기출문제 CBT 목록 - 킨즈&quot; data-og-description=&quot;&quot; data-og-host=&quot;www.kinz.kr&quot; data-og-source-url=&quot;https://www.kinz.kr/subject/7872&quot; data-og-url=&quot;https://www.kinz.kr/subject/7872&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://www.kinz.kr/subject/7872&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.kinz.kr/subject/7872&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;정보처리기사 객관식 필기 기출문제 CBT 목록 - 킨즈&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.kinz.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;4. 수제비 카페&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;figure id=&quot;og_1738772995072&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;수제비- IT 커뮤니티 (정보처리기사... : 네이버 카페&quot; data-og-description=&quot;수제비-수험생 입장에서 제대로 쓴 비법서(정보처리기사, 정보처리산업기사, 빅데이터 분석기사, 컴활 등)&quot; data-og-host=&quot;cafe.naver.com&quot; data-og-source-url=&quot;https://cafe.naver.com/soojebi?iframe_url=/ArticleList.nhn%3Fsearch.clubid=29835300%26search.menuid=77%26search.boardtype=L&quot; data-og-url=&quot;https://cafe.naver.com/soojebi&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Co3xT/hyX7OOMvoF/o4JWN28THT2C8LnW3s4s2K/img.png?width=150&amp;amp;height=150&amp;amp;face=0_0_150_150&quot;&gt;&lt;a href=&quot;https://cafe.naver.com/soojebi?iframe_url=/ArticleList.nhn%3Fsearch.clubid=29835300%26search.menuid=77%26search.boardtype=L&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://cafe.naver.com/soojebi?iframe_url=/ArticleList.nhn%3Fsearch.clubid=29835300%26search.menuid=77%26search.boardtype=L&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Co3xT/hyX7OOMvoF/o4JWN28THT2C8LnW3s4s2K/img.png?width=150&amp;amp;height=150&amp;amp;face=0_0_150_150');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;수제비- IT 커뮤니티 (정보처리기사... : 네이버 카페&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;수제비-수험생 입장에서 제대로 쓴 비법서(정보처리기사, 정보처리산업기사, 빅데이터 분석기사, 컴활 등)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;cafe.naver.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;5.  서술형 요약 정리 notion&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1738773120862&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[정처기] 서술형 대비 요약정리 | Notion&quot; data-og-description=&quot;Made with Notion, the all-in-one connected workspace with publishing capabilities.&quot; data-og-host=&quot;nanalike.notion.site&quot; data-og-source-url=&quot;https://nanalike.notion.site/35e0e234d27948afba77f062939f7491?v=2cb39e3c4fdc4fcaa0c00383ca7abdb4&quot; data-og-url=&quot;https://nanalike.notion.site/35e0e234d27948afba77f062939f7491&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Fm812/hyYce51HnW/aZ3h1QB5r5HkDaH5mfqbak/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/s76lG/hyYcc8cPax/0rwTdCyJkKR0JPlkFJ8z2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://nanalike.notion.site/35e0e234d27948afba77f062939f7491?v=2cb39e3c4fdc4fcaa0c00383ca7abdb4&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://nanalike.notion.site/35e0e234d27948afba77f062939f7491?v=2cb39e3c4fdc4fcaa0c00383ca7abdb4&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Fm812/hyYce51HnW/aZ3h1QB5r5HkDaH5mfqbak/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630,https://scrap.kakaocdn.net/dn/s76lG/hyYcc8cPax/0rwTdCyJkKR0JPlkFJ8z2K/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[정처기] 서술형 대비 요약정리 | Notion&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Made with Notion, the all-in-one connected workspace with publishing capabilities.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;nanalike.notion.site&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;6.  프로그래밍 언어&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1738773189621&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;profile&quot; data-og-title=&quot;흥달쌤&quot; data-og-description=&quot;흥달쌤과 함께하는 IT 채널입니다. 정보처리기사 자격증 관련된 강의 및 실무 노하우, 프로그래밍 언어(JAVA, C언어, Python) 특강 등이 진행됩니다. 앞으로 진행 예정인 동영상은 IT 관련된 이야기 &quot; data-og-host=&quot;www.youtube.com&quot; data-og-source-url=&quot;https://www.youtube.com/@HeungSsaem&quot; data-og-url=&quot;https://www.youtube.com/channel/UCtGmUJ92gdjC5GwzGYj7Tug&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bChZWV/hyX7359wtB/7PCOML9D8RB0ZhVOd5kivk/img.jpg?width=900&amp;amp;height=900&amp;amp;face=288_91_541_366,https://scrap.kakaocdn.net/dn/VzgHb/hyYb52jIP7/Vd5Y0qRbHHgslmZRu8Vwt1/img.jpg?width=900&amp;amp;height=900&amp;amp;face=288_91_541_366&quot;&gt;&lt;a href=&quot;https://www.youtube.com/@HeungSsaem&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.youtube.com/@HeungSsaem&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bChZWV/hyX7359wtB/7PCOML9D8RB0ZhVOd5kivk/img.jpg?width=900&amp;amp;height=900&amp;amp;face=288_91_541_366,https://scrap.kakaocdn.net/dn/VzgHb/hyYb52jIP7/Vd5Y0qRbHHgslmZRu8Vwt1/img.jpg?width=900&amp;amp;height=900&amp;amp;face=288_91_541_366');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;흥달쌤&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;흥달쌤과 함께하는 IT 채널입니다. 정보처리기사 자격증 관련된 강의 및 실무 노하우, 프로그래밍 언어(JAVA, C언어, Python) 특강 등이 진행됩니다. 앞으로 진행 예정인 동영상은 IT 관련된 이야기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.youtube.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>자격증</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/702</guid>
      <comments>https://pixx.tistory.com/702#entry702comment</comments>
      <pubDate>Tue, 4 Feb 2025 16:30:01 +0900</pubDate>
    </item>
    <item>
      <title>[백준, 11729번] 하노이 탑 이동 순서 (재귀 , Java)</title>
      <link>https://pixx.tistory.com/701</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ExufN/btsL5DSXLS9/75zKL1k6ibkIEo1pEoxrT0/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ExufN/btsL5DSXLS9/75zKL1k6ibkIEo1pEoxrT0/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ExufN/btsL5DSXLS9/75zKL1k6ibkIEo1pEoxrT0/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FExufN%2FbtsL5DSXLS9%2F75zKL1k6ibkIEo1pEoxrT0%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문제설명&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2366&quot; data-origin-height=&quot;1016&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/neEsN/btsL7CLr6oF/1fDFHfGh0stdEqLvTydpLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/neEsN/btsL7CLr6oF/1fDFHfGh0stdEqLvTydpLK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/neEsN/btsL7CLr6oF/1fDFHfGh0stdEqLvTydpLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FneEsN%2FbtsL7CLr6oF%2F1fDFHfGh0stdEqLvTydpLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;301&quot; data-origin-width=&quot;2366&quot; data-origin-height=&quot;1016&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2396&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/50qQq/btsL6JR6dA4/zhGkt0V2ukOEkVSpd1WZtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/50qQq/btsL6JR6dA4/zhGkt0V2ukOEkVSpd1WZtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/50qQq/btsL6JR6dA4/zhGkt0V2ukOEkVSpd1WZtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F50qQq%2FbtsL6JR6dA4%2FzhGkt0V2ukOEkVSpd1WZtk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;158&quot; data-origin-width=&quot;2396&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입력 &amp;amp; 출력&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QEBi8/btsL5kFVapq/vJp48srgyLQFUmRWq6xTSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QEBi8/btsL5kFVapq/vJp48srgyLQFUmRWq6xTSk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QEBi8/btsL5kFVapq/vJp48srgyLQFUmRWq6xTSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQEBi8%2FbtsL5kFVapq%2FvJp48srgyLQFUmRWq6xTSk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;354&quot; data-origin-width=&quot;2386&quot; data-origin-height=&quot;1208&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나의 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/11729&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준 - 하노이 탑 이동 순서&quot;&lt;/b&gt;&lt;/a&gt; 문제는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;하노이탑 알고리즘&lt;/b&gt;&lt;/span&gt;을 사용하는 대표적인 문제입니다. 다음과 같은 &lt;b&gt;제약사항&lt;/b&gt;이 있는 상황에서 목적지 까지 옮기는 횟수와 순서를 출력하는 문제입니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #333333; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;color: #555555;&quot;&gt;&lt;i&gt;&lt;b&gt;한 번에 한 개의 원판만을 다른 탑으로 옮길 수 있다.&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;li style=&quot;color: #555555;&quot;&gt;&lt;i&gt;&lt;b&gt;쌓아 놓은 원판은 항상 위의 것이 아래의 것보다 작아야 한다.&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;1354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nx0iw/btsL6aJuZ7a/k6Kb3auwKFVhDZLzGttjt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nx0iw/btsL6aJuZ7a/k6Kb3auwKFVhDZLzGttjt0/img.png&quot; data-alt=&quot;하노이 탑 전체 이동 순서&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nx0iw/btsL6aJuZ7a/k6Kb3auwKFVhDZLzGttjt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnx0iw%2FbtsL6aJuZ7a%2Fk6Kb3auwKFVhDZLzGttjt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;540&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;1354&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;하노이 탑 전체 이동 순서&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 &lt;b&gt;첫 번째 기둥&lt;/b&gt;에서 &lt;b&gt;마지막 기&lt;/b&gt;둥까지의 &lt;b&gt;이동순서&lt;/b&gt;가 나오며, 하노이 탑(Hanoi Tower) 알고리즘의 &lt;b&gt;최소 이동 횟수&lt;/b&gt;는 다음 공식으로 계산됩니다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;2^n - 1&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 공식을 알고있으면 최소 이동 횟수는 간단하게 구할 수 있지만, 문제의 핵심은 &lt;u&gt;&lt;b&gt;이동 순서를 출력&lt;/b&gt;&lt;/u&gt;해야한다는 것 입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 목표는 모든 원판을 &lt;b&gt;첫 번째 장대&lt;/b&gt;에서 &lt;b&gt;세 번째 장대&lt;/b&gt;로 옮기는 것입니다. 이때 주어진 &lt;b&gt;제약 조건을 지켜야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가장 큰 원판을 목적지로 옮기기 위해서는&lt;/b&gt;, 먼저 그 위에 있는&lt;u&gt;&lt;b&gt; 모든 원판들을 임시 기둥으로 이동&lt;/b&gt;&lt;/u&gt;시켜야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음 가&lt;b&gt;장 큰 원판을 목적지 기둥으로 옮기고&lt;/b&gt;, 마지막으로 &lt;b&gt;임시 기둥&lt;/b&gt;에 있는 원판들을&lt;b&gt; 크기 순서에 맞게&lt;/b&gt; &lt;b&gt;목적지 기둥으로 이동&lt;/b&gt;시키면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정리하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;  기본 원리 (재귀)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;가장 작은 원판(1)부터 이동&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작은 원판들이 이동할 공간(tmp 기둥)을 확보&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;큰 원판을 목표 기둥(end)으로 이동&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임시로 옮겨둔 작은 원판들을 다시 목표 기둥으로 이동&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;1414&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NBulZ/btsL6tPxL5J/hOMdwoCM9ikzoFa9RFKHg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NBulZ/btsL6tPxL5J/hOMdwoCM9ikzoFa9RFKHg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NBulZ/btsL6tPxL5J/hOMdwoCM9ikzoFa9RFKHg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNBulZ%2FbtsL6tPxL5J%2FhOMdwoCM9ikzoFa9RFKHg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;671&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;1414&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀 함수의 마지막 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;&lt;b&gt;매개변수 count&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;현재 이동해야 할 원판의 개수&lt;/b&gt;를 나타냅니다. &lt;b&gt;실제 원판의 이동 과정&lt;/b&gt;은&lt;b&gt; StringBuilder를 사용&lt;/b&gt;하여 기록하고 출력합니다.&lt;/p&gt;</description>
      <category>Coding Test/백준</category>
      <category>하노이 탑</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/701</guid>
      <comments>https://pixx.tistory.com/701#entry701comment</comments>
      <pubDate>Tue, 4 Feb 2025 16:28:38 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.04 - Docker : Container Inspect로 컨테이너 세부 정보 확인하기</title>
      <link>https://pixx.tistory.com/700</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYvlFI/btsL6XV9dRA/xiMPPhccRv70hUiCoCF8ik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYvlFI/btsL6XV9dRA/xiMPPhccRv70hUiCoCF8ik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYvlFI/btsL6XV9dRA/xiMPPhccRv70hUiCoCF8ik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYvlFI%2FbtsL6XV9dRA%2FxiMPPhccRv70hUiCoCF8ik%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;figure id=&quot;og_1738591623881&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Docker] Docker 주요 명령어 알아보기  &quot; data-og-description=&quot;Docker 이미지 관련 명령어이미지 가져오기docker pull [이미지명]Docker Hub 또는 다른 레지스트리에서 이미지를 다운로드합니다.이미지 빌드docker build -t [이미지명]:[태그] [경로]Dockerfile을 사용하여 &quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/312&quot; data-og-url=&quot;https://pixx.tistory.com/312&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/nVNjX/hyX73Y7Arp/YZtMb4h2RqmwPK1LpCJTH0/img.jpg?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/90JKV/hyX7Q6vTU7/oXil2Kyre5ccULv8gQNmM0/img.jpg?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/cZhNoo/hyX73kvw6v/iIPdg1HFTV9LCvSZHyEVQ1/img.png?width=935&amp;amp;height=250&amp;amp;face=0_0_935_250&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/312&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/312&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/nVNjX/hyX73Y7Arp/YZtMb4h2RqmwPK1LpCJTH0/img.jpg?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/90JKV/hyX7Q6vTU7/oXil2Kyre5ccULv8gQNmM0/img.jpg?width=225&amp;amp;height=225&amp;amp;face=0_0_225_225,https://scrap.kakaocdn.net/dn/cZhNoo/hyX73kvw6v/iIPdg1HFTV9LCvSZHyEVQ1/img.png?width=935&amp;amp;height=250&amp;amp;face=0_0_935_250');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Docker] Docker 주요 명령어 알아보기  &lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Docker 이미지 관련 명령어이미지 가져오기docker pull [이미지명]Docker Hub 또는 다른 레지스트리에서 이미지를 다운로드합니다.이미지 빌드docker build -t [이미지명]:[태그] [경로]Dockerfile을 사용하여&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 포스팅에서 정리했던 주요 명령어 중에서 network, volume에 대한 &lt;b&gt;상세정보를 확인&lt;/b&gt;하는 명령어인 &lt;b&gt;&quot;inspect&quot;&lt;/b&gt; 말고도 docker를 사용하다보면 &lt;b&gt;컨테이너나의 상세 정보를 확인&lt;/b&gt;해야 할 때가 있습니다. 이럴 때 사용하는 것이 바로 &lt;u&gt;&lt;b&gt;docker container inspect &lt;/b&gt;&lt;/u&gt;명령어입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;docker container inspect 명령어&lt;/b&gt;&lt;/span&gt;에 대해서 간단히 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Docker Container Inspect&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;기본 사용법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738591908820&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker container inspect container_name_or_id&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 확인 정보&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1.&lt;span&gt;&amp;nbsp;컨테이너 기본 정보&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;컨테이너 ID&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;생성 시간&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;현재 상태&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Docker 버전&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2.&lt;span&gt; 네트워크 설정&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;IP 주소&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;MAC 주소&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포트 바인딩&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 모드&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;스토리지 설정&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;볼륨 마운트 정보&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;바인드 마운트 경로&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;임시 마운트 정보&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4.&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;리소스 제한&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;CPU 할당량&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메모리 제한&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;ulimits 설정&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;inspect : 필터링&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738592162124&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# IP 주소만 확인
docker container inspect -f '{{.NetworkSettings.IPAddress}}' container_name

# 모든 마운트 포인트 확인
docker container inspect -f '{{.Mounts}}' container_name

# 환경변수 목록 확인
docker container inspect -f '{{.Config.Env}}' container_name&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;Docker Container Inspect 활용하기&lt;/h3&gt;
&lt;figure id=&quot;og_1738592546628&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Docker] Docker 컨테이너에서 호스트 머신에 접근하기: host.docker.internal&quot; data-og-description=&quot;개요Docker를 사용하다 보면 컨테이너 내부에서 로컬 머신의 애플리케이션이나 데이터베이스에 접근해야 할 때가 있습니다.이때 사용할 수 있는 기능이 바로 host.docker.internal 입니다.&amp;nbsp;본 글에서&quot; data-og-host=&quot;pixx.tistory.com&quot; data-og-source-url=&quot;https://pixx.tistory.com/697&quot; data-og-url=&quot;https://pixx.tistory.com/697&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bnSqpc/hyYcdFJIjY/XN4L1Up3Ke7iJx4tbyEgp1/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/chDC2i/hyYb7er7Re/3iaICFEtMLaJKBbF9mbk10/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/boeVyV/hyYb5VfkBF/HkVPHtSW1ZcyBerytySHGk/img.png?width=1111&amp;amp;height=747&amp;amp;face=0_0_1111_747&quot;&gt;&lt;a href=&quot;https://pixx.tistory.com/697&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://pixx.tistory.com/697&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bnSqpc/hyYcdFJIjY/XN4L1Up3Ke7iJx4tbyEgp1/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/chDC2i/hyYb7er7Re/3iaICFEtMLaJKBbF9mbk10/img.png?width=238&amp;amp;height=212&amp;amp;face=0_0_238_212,https://scrap.kakaocdn.net/dn/boeVyV/hyYb5VfkBF/HkVPHtSW1ZcyBerytySHGk/img.png?width=1111&amp;amp;height=747&amp;amp;face=0_0_1111_747');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Docker] Docker 컨테이너에서 호스트 머신에 접근하기: host.docker.internal&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개요Docker를 사용하다 보면 컨테이너 내부에서 로컬 머신의 애플리케이션이나 데이터베이스에 접근해야 할 때가 있습니다.이때 사용할 수 있는 기능이 바로 host.docker.internal 입니다.&amp;nbsp;본 글에서&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;pixx.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 포스팅에서의 로컬 머신의 mongoDB 데이터베이스와 간단한 Node 애플리케이션 코드 중 &lt;b&gt;&quot;host.docker.internal&quot;&lt;/b&gt; 도메인이 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738592581053&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongoose.connect(
  'mongodb://host.docker.internal:27017/swfavorites',
  { useNewUrlParser: true },
  (err) =&amp;gt; {
    if (err) {
      console.log(err);
    } else {
      app.listen(3000);
    }
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;host.docker.internal&lt;/b&gt;은 Docker 컨테이너에서 &lt;b&gt;호스트 머신&lt;/b&gt;에 접근할 때 사용하는 &lt;b&gt;특별한 도메인&lt;/b&gt;입니다. 그러나 MongoDB를 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;Docker 컨테이너로 실행&lt;/b&gt;&lt;/span&gt;할 경우에는 이 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;도메인을 사용&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;할 수 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대신, MongoDB &lt;u&gt;&lt;b&gt;컨테이너의 IP 주소를 사용&lt;/b&gt;&lt;/u&gt;해야 합니다. 이 IP 주소는 다음 명령어로 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738592917240&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker container inspect mongodb-container&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력된&lt;b&gt; JSON 정보&lt;/b&gt;에서 &lt;b&gt;NetworkSettings.IPAddress 값&lt;/b&gt;을 찾아 &lt;b&gt;MongoDB 연결 문자열에 사용&lt;/b&gt;하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQ6PXe/btsL6BTo0U9/NG5UjNbe5S1jPcIfkPlUx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQ6PXe/btsL6BTo0U9/NG5UjNbe5S1jPcIfkPlUx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQ6PXe/btsL6BTo0U9/NG5UjNbe5S1jPcIfkPlUx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQ6PXe%2FbtsL6BTo0U9%2FNG5UjNbe5S1jPcIfkPlUx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;514&quot; height=&quot;382&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1738592957981&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongoose.connect(
  'mongodb://container-ip:27017/swfavorites', // 127.17.0.2
  { useNewUrlParser: true },
  (err) =&amp;gt; {
    if (err) {
      console.log(err);
    } else {
      app.listen(3000);
    }
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&quot;inspect&quot;명령어를 사용하면 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;위와 같이&lt;span&gt; 정보들이 나오는데, 여기서 IPAddress를 보면 이 IP주소를 사용하면됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/700</guid>
      <comments>https://pixx.tistory.com/700#entry700comment</comments>
      <pubDate>Tue, 4 Feb 2025 00:31:14 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.03 - Java 배열 초기화: Arrays.fill()과 반복문의 성능 비교</title>
      <link>https://pixx.tistory.com/698</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GRee8/btsL31ePOBn/Qm8E1weNNzvKZQi6dsb1Pk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GRee8/btsL31ePOBn/Qm8E1weNNzvKZQi6dsb1Pk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GRee8/btsL31ePOBn/Qm8E1weNNzvKZQi6dsb1Pk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGRee8%2FbtsL31ePOBn%2FQm8E1weNNzvKZQi6dsb1Pk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;Java에서 배열을 초기화할 때 주로 사용하는 &lt;b&gt;두 가지 방법&lt;/b&gt;이 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt; Arrays.fill() 메서드&lt;/b&gt;&lt;/span&gt;를 사용하는 방법과 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;for 반복문&lt;/b&gt;&lt;/span&gt;을 사용하는 방법입니다. 오늘은 이 두 방식의 성능을 비교하고 실제 어떤 상황에서 어떤 방법을 선택하는 것이 좋을지 알아보겠습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;두 가지 초기화 방법&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;1. Arrays.fill() 사용&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738514090122&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[] arr1 = new int[size];
Arrays.fill(arr1, 5);&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;2. for 반복문 사용&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738514094393&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[] arr2 = new int[size];
for(int i = 0; i &amp;lt; size; i++) {
    arr2[i] = 5;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;성능 테스트&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;다양한 크기의 배열에서 두 방식의 성능을 비교해보았습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1738514111345&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ArrayInitializationTest {
    public static void main(String[] args) {
        test(10_000_000);     // 천만
        test(50_000_000);     // 오천만
        test(100_000_000);    // 일억
        test(200_000_000);    // 이억
    }
    
    public static void test(int size) {
        System.out.println(&quot;\n배열 크기: &quot; + size);
        
        long startFill = System.nanoTime();
        int[] arr1 = new int[size];
        Arrays.fill(arr1, 5);
        long endFill = System.nanoTime();
        
        long startFor = System.nanoTime();
        int[] arr2 = new int[size];
        for(int i = 0; i &amp;lt; size; i++) {
            arr2[i] = 5;
        }
        long endFor = System.nanoTime();
        
        System.out.println(&quot;Arrays.fill() 시간: &quot; + 
            (endFill - startFill) / 1_000_000.0 + &quot; ms&quot;);
        System.out.println(&quot;for문 시간: &quot; + 
            (endFor - startFor) / 1_000_000.0 + &quot; ms&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size14&quot;&gt;&lt;i&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;실행 결과&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;355&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgbh2N/btsL5Pqi0w1/7za3vz7zwGEQ4jmiqdjWq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgbh2N/btsL5Pqi0w1/7za3vz7zwGEQ4jmiqdjWq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgbh2N/btsL5Pqi0w1/7za3vz7zwGEQ4jmiqdjWq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgbh2N%2FbtsL5Pqi0w1%2F7za3vz7zwGEQ4jmiqdjWq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;587&quot; height=&quot;355&quot; data-origin-width=&quot;587&quot; data-origin-height=&quot;355&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;위와 같이 실행 결과가 나오는데, 물론 매 &lt;b&gt;실행마다 결과는 달라집니다.&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그러나 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;반복문&lt;/b&gt;&lt;/span&gt;이 &lt;u&gt;&lt;b&gt;배열의 크기가 큰 경우 대체로 더 좋은 성능&lt;/b&gt;&lt;/u&gt;을 보이는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이는 &lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;Arrays.fill() 메서드&lt;/b&gt;&lt;/span&gt;가 &lt;b&gt;내부적으로 처리&lt;/b&gt;하는 작업들이 &lt;b&gt;큰 배열에서는 오히려&lt;span style=&quot;color: #ef5369;&quot;&gt; 오버헤드&lt;/span&gt;로 작용&lt;/b&gt;할 수 있다는 것을 의미합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;특히 배열 크기가 매우 큰 경우(1억 이상)에서는 반복문이 &lt;b&gt;Arrays.fill()보다 약 2-3배 정도 더 빠른 성능을 보이는 경향&lt;/b&gt;이 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;55&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vYxHV/btsL4qkZGwR/M96kXjHQpk2GdEqB2Ov4Sk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vYxHV/btsL4qkZGwR/M96kXjHQpk2GdEqB2Ov4Sk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vYxHV/btsL4qkZGwR/M96kXjHQpk2GdEqB2Ov4Sk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvYxHV%2FbtsL4qkZGwR%2FM96kXjHQpk2GdEqB2Ov4Sk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;269&quot; height=&quot;55&quot; data-origin-width=&quot;269&quot; data-origin-height=&quot;55&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 배열의 크기가 1억 이상일 경우는 &lt;s&gt;&lt;b&gt;일반적이지 않습니다&lt;/b&gt;&lt;/s&gt;. 따라서 일반적인 상황에서는 코드의 &lt;b&gt;가독성&lt;/b&gt;과 &lt;b&gt;유지보수성&lt;/b&gt;을 고려하여 &lt;u&gt;&lt;b&gt;Arrays.fill() 메서드&lt;/b&gt;&lt;/u&gt;를 사용하는 것이 더 좋은 선택일 것입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Arrays.fill()은 메서드 &lt;b&gt;이름 자체&lt;/b&gt;로 배열을 특정 값으로 채운다는 &lt;b&gt;의도가 명확&lt;/b&gt;하게 드러나고, 실제 사용되는 &lt;u&gt;&lt;b&gt;배열 크기에서는 성능 차이가 크지 않기 때문&lt;/b&gt;&lt;/u&gt;입니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>arrays.fill</category>
      <category>til</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/698</guid>
      <comments>https://pixx.tistory.com/698#entry698comment</comments>
      <pubDate>Mon, 3 Feb 2025 01:48:52 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] Docker 컨테이너에서 호스트 머신에 접근하기: host.docker.internal</title>
      <link>https://pixx.tistory.com/697</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__20_-removebg-preview.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CPOTj/btsL5OEQNUH/VCPHwbG7qanvkvWMAkyngk/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CPOTj/btsL5OEQNUH/VCPHwbG7qanvkvWMAkyngk/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CPOTj/btsL5OEQNUH/VCPHwbG7qanvkvWMAkyngk/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCPOTj%2FbtsL5OEQNUH%2FVCPHwbG7qanvkvWMAkyngk%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;238&quot; height=&quot;212&quot; data-filename=&quot;다운로드__20_-removebg-preview.png&quot; data-origin-width=&quot;238&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker를 사용하다 보면 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;컨테이너 내부&lt;/b&gt;&lt;/span&gt;에서 &lt;b&gt;로컬 머신의 애플리케이션이나 데이터베이스&lt;/b&gt;에 접근해야 할 때가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이때 사용할 수 있는 기능이 바로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;host.docker.internal&lt;/b&gt;&lt;/span&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서는 ~ 할 수 있는 &quot;host.docker.internal&quot;에 대해서 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;host.docker.internal이란❓&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;컨테이너 내부&lt;/b&gt;&lt;/span&gt;에서 &lt;b&gt;호스트 머신(로컬 컴퓨터)의 &lt;u&gt;네트워크에 접근&lt;/u&gt;&lt;/b&gt;할 수 있도록 제공되는 &lt;b&gt;특별한 도메인&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;b&gt;컨테이너가 실행되는 &lt;u&gt;호스트 머신의 IP를 자동으로 매핑&lt;/u&gt;&lt;/b&gt;해 주는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;localhost&lt;/b&gt;&lt;/span&gt;는 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;컨테이너 내부&lt;/span&gt;를 가리키기 때문에&lt;/b&gt; &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;&quot;host.docker.internal&quot;&lt;/b&gt;&lt;/span&gt;을 사용해야 &lt;b&gt;호스트 머신의 서비스(DB 등)&lt;/b&gt; 에 접근할 수 있습니다. 주로 &lt;b&gt;개발 환경&lt;/b&gt;에서 유용하게 사용됩니다.&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;주요 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Docker Desktop&lt;/b&gt;을 사용할 때&lt;b&gt; Docker&lt;/b&gt;가 &lt;b&gt;자동으로 제공하는 DNS 이름&lt;/b&gt;입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;컨테이너 내부&lt;/b&gt;에서 이 주소를 사용하면 &lt;u&gt;&lt;b&gt;호스트 머신의 localhost에 접근&lt;/b&gt;&lt;/u&gt;할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;host.docker.internal 사용해보기&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;시나리오&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1111&quot; data-origin-height=&quot;747&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biWu4t/btsL3i86bM7/EaeGliDSZd76rzHrxscxu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biWu4t/btsL3i86bM7/EaeGliDSZd76rzHrxscxu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biWu4t/btsL3i86bM7/EaeGliDSZd76rzHrxscxu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiWu4t%2FbtsL3i86bM7%2FEaeGliDSZd76rzHrxscxu0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;269&quot; data-origin-width=&quot;1111&quot; data-origin-height=&quot;747&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffc9af;&quot;&gt;&lt;b&gt;MongoDB&lt;/b&gt;&lt;/span&gt;는 &lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;호스트 머신(로컬)&lt;/b&gt;&lt;/span&gt;에서 실행 중 (포트 27017)&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #99cefa;&quot;&gt;&lt;b&gt;Node.js 애플리케이션&lt;/b&gt;&lt;/span&gt;은 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;도커 컨테이너 내부&lt;/b&gt;&lt;/span&gt;에서 실행&lt;/li&gt;
&lt;li&gt;컨테이너에서 'localhost'로 MongoDB 접근 시도 시 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;연결 실패&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;애플리케이션 코드&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738482044219&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;''''''''
생략
''''''''

mongoose.connect(
  'mongodb://localhost:27017/swfavorites',
  { useNewUrlParser: true },
  (err) =&amp;gt; {
    if (err) {
      console.log(err);
    } else {
      app.listen(3000);
    }
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본 글에서 확인할 것은 컨테이너 내부에서 &lt;b&gt;로컬 머신에 접근할 수 있는 지&lt;/b&gt;를 확인해보는 것이기 때문에 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;애플리케이션 코드의 &lt;b&gt;일부를 발췌&lt;/b&gt;했습니다.&lt;/span&gt; 위 코드로 컨테이너를 실행하면 아래와 같은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;에러가 발생&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2056&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nxgsj/btsL2QLDjOn/Dys5PmgFtXzldbmwNs5yk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nxgsj/btsL2QLDjOn/Dys5PmgFtXzldbmwNs5yk1/img.png&quot; data-alt=&quot;이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nxgsj/btsL2QLDjOn/Dys5PmgFtXzldbmwNs5yk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnxgsj%2FbtsL2QLDjOn%2FDys5PmgFtXzldbmwNs5yk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;98&quot; data-origin-width=&quot;2056&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 에러는 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;s&gt;&lt;b&gt;컨테이너가 호스트 머신에 연결&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;하지 못했다는 의미입니다. 이는 예상된 결과인데, &lt;b&gt;MongoDB는 로컬 머신에서 실행&lt;/b&gt;되고 있고 &lt;b&gt;애플리케이션은 도커 컨테이너 내부&lt;/b&gt;에서 실행되고 있기 때문입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span&gt;수정된 애플리케이션 코드 : host.docker.internal&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1738484153769&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mongoose.connect(
  'mongodb://host.docker.internal:27017/swfavorites',
  { useNewUrlParser: true },
  (err) =&amp;gt; {
    if (err) {
      console.log(err);
    } else {
      app.listen(3000);
    }
  }
);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;host.docker.internal 도입&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;localhost를 &lt;b&gt;도커가 이해할 수 있는 특별한 도메인&lt;/b&gt;으로 바꿔줘야 합니다. 이것이 바로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;&quot;host.docker.internal&quot;&lt;/b&gt;&lt;/span&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도메인 변환 과정&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 특수 도메인은&lt;b&gt; 도커에 의해&lt;span style=&quot;color: #006dd7;&quot;&gt; 자동&lt;/span&gt;으로 인식&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도커 컨테이너 내부&lt;/b&gt;에서 &lt;b&gt;호스트 머신&lt;/b&gt;의 &lt;b&gt;실제 IP 주소로 &lt;u&gt;자동 변환&lt;/u&gt;&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연결 프로세스&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨테이너는 host.docker.internal을 통해 호스트 머신을 찾습니다.&lt;/li&gt;
&lt;li&gt;호스트 머신의 27017 포트에서 실행 중인 MongoDB에 연결됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;host.docker.internal은 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;개발 환경&lt;/b&gt;&lt;/span&gt;에서 &lt;b&gt;컨테이너&lt;/b&gt;와 &lt;b&gt;호스트 머신 간&lt;/b&gt;의 &lt;b&gt;통신을 단순화하는 유용한 도구&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 실제 운영 환경에서는 &lt;b&gt;보안&lt;/b&gt;과 &lt;b&gt;안정성&lt;/b&gt;을 고려한 &lt;b&gt;적절한 네트워크 구성이 필요&lt;/b&gt;하며 &lt;b&gt;개발 환경에서 사용하는 것이 권장&lt;/b&gt;됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DevOps/Docker</category>
      <category>host.docker.internal</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/697</guid>
      <comments>https://pixx.tistory.com/697#entry697comment</comments>
      <pubDate>Sun, 2 Feb 2025 17:34:18 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.02 - 그래프 탐색(DFS, BFS)에서 방문 배열(visited)의 차원 결정하기</title>
      <link>https://pixx.tistory.com/696</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFsH1s/btsL4PqN8qG/bNAFiJHXHzjHwjSioA4RIk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFsH1s/btsL4PqN8qG/bNAFiJHXHzjHwjSioA4RIk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFsH1s/btsL4PqN8qG/bNAFiJHXHzjHwjSioA4RIk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFsH1s%2FbtsL4PqN8qG%2FbNAFiJHXHzjHwjSioA4RIk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알고리즘 문제를 풀다 보면 &lt;b&gt;그래프 탐색 알고리즘(BFS, DFS)&lt;/b&gt; 을 사용할 때, &lt;b&gt;중복 방문을 방지하기 위해 boolean 배열을 활용&lt;/b&gt;하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 방문 체크용 boolean 배열을 &lt;b&gt;1차원으로 사용할지, 2차원으로 사용할지&lt;/b&gt; 헷갈리는 경우가 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;이는 &lt;b&gt;탐색 대상이 되는 그래프의 구조&lt;/b&gt;를 확인하면 쉽게 결정할 수 있습니다. 본 글에서는 &lt;b&gt;그래프의 형태에 따라 boolean 배열을 어떻게 설정&lt;/b&gt;해야 하는지 정리하고자 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;1차원 boolean 배열을 사용하는 경우&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;그래프가 일반적인 &lt;span style=&quot;background-color: #ffc1c8;&quot;&gt;정점(Node) 중심의 탐색&lt;/span&gt;&lt;/b&gt;일 때&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인접 리스트 &lt;/b&gt;또는&lt;b&gt; 인접 행렬&lt;/b&gt;로 &lt;b&gt;그래프가 표현된 경우&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;정점 개수가 N개라면, boolean[N] 크기의 방문 배열을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예제: 그래프의 각 정점을 방문하는 경우&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738422632882&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;boolean[] visited = new boolean[N]; // 정점 방문 여부 저장&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1738422639388&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void dfs(int node) {
    visited[node] = true;
    for (int next : graph[node]) { // 현재 노드와 연결된 노드들 탐색
        if (!visited[next]) {
            dfs(next);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;2차원 boolean 배열을 사용하는 경우&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;그래프가 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;좌표(Point) 중심의 탐색&lt;/span&gt;&lt;/b&gt;일 때&lt;/li&gt;
&lt;li&gt;즉, &lt;b&gt;2D 격자&lt;/b&gt;를 탐색하는 경우
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예: &lt;i&gt;&lt;b&gt;NxM 크기의 지도, 미로, 체스판 등&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;(x, y) 위치를 방문했는지를 저장하려면 boolean[N][M] 크기의 배열을 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;예제: 미로 탐색 (BFS / DFS)&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1738422699937&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;boolean[][] visited = new boolean[N][M]; // 2D 방문 배열&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1738422707015&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void bfs(int x, int y) {
    Queue&amp;lt;int[]&amp;gt; queue = new LinkedList&amp;lt;&amp;gt;();
    queue.add(new int[]{x, y});
    visited[x][y] = true;

    while (!queue.isEmpty()) {
        int[] cur = queue.poll();
        int cx = cur[0], cy = cur[1];

        for (int d = 0; d &amp;lt; 4; d++) { // 4방향 이동 (상하좌우)
            int nx = cx + dx[d], ny = cy + dy[d];

            if (nx &amp;gt;= 0 &amp;amp;&amp;amp; ny &amp;gt;= 0 &amp;amp;&amp;amp; nx &amp;lt; N &amp;amp;&amp;amp; ny &amp;lt; M &amp;amp;&amp;amp; !visited[nx][ny]) {
                visited[nx][ny] = true;
                queue.add(new int[]{nx, ny});
            }
        }
    }
}​&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결론&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;✅ &lt;b&gt;그래프 &lt;/b&gt;탐색&lt;b&gt;(&lt;u&gt;정점&lt;/u&gt; 기준) &amp;rarr; &lt;/b&gt;boolean[N] &lt;b&gt;(1차원)&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;✅ &lt;b&gt;격자(&lt;u&gt;좌표&lt;/u&gt; 기준) &lt;/b&gt;탐색 &lt;b&gt;&amp;rarr; &lt;/b&gt;boolean[N][M] &lt;b&gt;(2차원)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, &lt;b&gt;탐색 대상이 &quot;정점&quot;이면 1차원, &quot;좌표&quot;이면 2차원&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>TIL,일일 회고</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/696</guid>
      <comments>https://pixx.tistory.com/696#entry696comment</comments>
      <pubDate>Sun, 2 Feb 2025 00:15:21 +0900</pubDate>
    </item>
    <item>
      <title>[백준, 1697번] 숨바꼭질 (BFS, 너비 우선 탐색, Java)</title>
      <link>https://pixx.tistory.com/695</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dACSrs/btsL2AhKADM/GScOdNUjnihsVYKAmeBa91/tfile.dat&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dACSrs/btsL2AhKADM/GScOdNUjnihsVYKAmeBa91/tfile.dat&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dACSrs/btsL2AhKADM/GScOdNUjnihsVYKAmeBa91/tfile.dat&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdACSrs%2FbtsL2AhKADM%2FGScOdNUjnihsVYKAmeBa91%2Ftfile.dat&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;225&quot; height=&quot;225&quot; data-filename=&quot;다운로드__16_-removebg-preview.png&quot; data-origin-width=&quot;225&quot; data-origin-height=&quot;225&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;문제설명&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;914&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bL8zSG/btsL4ZtgUCZ/K9eNdYQOSlob7kgnWbKJk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bL8zSG/btsL4ZtgUCZ/K9eNdYQOSlob7kgnWbKJk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bL8zSG/btsL4ZtgUCZ/K9eNdYQOSlob7kgnWbKJk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbL8zSG%2FbtsL4ZtgUCZ%2FK9eNdYQOSlob7kgnWbKJk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;266&quot; data-origin-width=&quot;2404&quot; data-origin-height=&quot;914&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;입력 &amp;amp; 출력&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2374&quot; data-origin-height=&quot;948&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Klbsn/btsL36GNo6s/UZgPu65igCb8qmu3hesMN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Klbsn/btsL36GNo6s/UZgPu65igCb8qmu3hesMN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Klbsn/btsL36GNo6s/UZgPu65igCb8qmu3hesMN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKlbsn%2FbtsL36GNo6s%2FUZgPu65igCb8qmu3hesMN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;280&quot; data-origin-width=&quot;2374&quot; data-origin-height=&quot;948&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;나의 풀이&lt;/span&gt;&lt;/h3&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;문제 접근 방법&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1697&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;b&gt;&quot;백준 - 숨바꼭질&quot;&lt;/b&gt;&lt;/a&gt; 문제는 &lt;b&gt;수빈(N)&lt;/b&gt;이와 &lt;b&gt;동생(K)&lt;/b&gt;의 위치가 주어질 때 &lt;b&gt;동생을 찾을 수 있는 가장 빠른 시간을 출력&lt;/b&gt;하는 문제입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;수빈이는 &lt;b&gt;걷거나&lt;/b&gt; &lt;b&gt;순간이동&lt;/b&gt;을 할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;수빈이의 위치가 x라면&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;걷기 : x + 1, X -1&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot;&gt;순간이동 : x * 2&lt;/span&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 수빈이가 동생을 찾을 수 있는 &lt;b&gt;최단 시간&lt;/b&gt;을 구하는 것이기 때문에 &lt;b&gt;BFS&lt;/b&gt; 문제의 대표적인 형태입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;728&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ebHbIf/btsL5mhsZZF/UhL3xlHn7ijqH4K3qPFRLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ebHbIf/btsL5mhsZZF/UhL3xlHn7ijqH4K3qPFRLK/img.png&quot; data-alt=&quot;트리 계층도&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ebHbIf/btsL5mhsZZF/UhL3xlHn7ijqH4K3qPFRLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FebHbIf%2FbtsL5mhsZZF%2FUhL3xlHn7ijqH4K3qPFRLK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;372&quot; data-origin-width=&quot;978&quot; data-origin-height=&quot;728&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;트리 계층도&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 시작 노드에서 시작해서 &lt;b&gt;수빈이가 이동할 수 있는 위치&lt;/b&gt;를 &lt;b&gt;탐색&lt;/b&gt;하고, 최단시간이니깐 &lt;b&gt;BFS를 사용하여 해결&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 위치에서 수빈이는 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;1초 후&lt;/b&gt;&lt;/span&gt;에 X-1, X+1, X*2로 이동할 수 있으며, &lt;b&gt;Time이 증가할 때마다&lt;/b&gt; &lt;b&gt;모든 가능한 위치&lt;/b&gt;를 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;큐에 넣어 순서대로 탐색&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 BFS로 탐색하면 &lt;u&gt;&lt;b&gt;처음 목표 위치(동생의 위치)에 도달했을 때가 항상 최단 시간&lt;/b&gt;&lt;/u&gt;이 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 트리 계층도대로 예제 입력을 표현하자면 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2059&quot; data-origin-height=&quot;1274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7LrDZ/btsL3OsQE5n/oiOCJJPN7L03QaCRQ2fwH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7LrDZ/btsL3OsQE5n/oiOCJJPN7L03QaCRQ2fwH1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7LrDZ/btsL3OsQE5n/oiOCJJPN7L03QaCRQ2fwH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7LrDZ%2FbtsL3OsQE5n%2FoiOCJJPN7L03QaCRQ2fwH1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;371&quot; data-origin-width=&quot;2059&quot; data-origin-height=&quot;1274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같이 &lt;b&gt;수빈이의 위치(5)&lt;/b&gt;에서 시작해서 레벨 단위로 &lt;b&gt;수빈이가 탐색할 수 있는 위치&lt;/b&gt;를 &lt;b&gt;큐&lt;/b&gt;에 넣고, 동생의 위치인 &lt;b&gt;17을 찾을 때까지 BFS로 탐색&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt; 각 시간(Time)마다&lt;/b&gt; 큐에서 위치를 꺼내서&lt;i&gt;&lt;b&gt; -1, +1, &amp;times;2 연산 &lt;/b&gt;&lt;/i&gt;을 통해 &lt;b&gt;이동할 수 있는 &lt;u&gt;모든 위치&lt;/u&gt;를 다음 레벨의 큐에 넣습니다&lt;/b&gt;.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Time 4에서 16에서 +1 연산을 통해 동생의 위치인 17에 도달하게 되어 최단 시간인 4초를 구할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;중복을 피하기 위해서&lt;/b&gt;&lt;/span&gt; 방문 여부를 체크할 &lt;b&gt;visited 배열&lt;/b&gt;을 사용하여 방문한 노드를 체크해줍니다. 위 예제에서는 노드4 에서 이동이 가능한 위치는 (3,5,8)인데, 5는 이미 시작노드에서 &lt;b&gt;이미 방문&lt;/b&gt;했으므로 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;제외&lt;/b&gt;&lt;/span&gt;가 되는 것입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;전체 코드&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1533&quot; data-origin-height=&quot;2727&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFzgIV/btsL3pmAf8N/mJZKSgFndbAa8omED6o4wk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFzgIV/btsL3pmAf8N/mJZKSgFndbAa8omED6o4wk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFzgIV/btsL3pmAf8N/mJZKSgFndbAa8omED6o4wk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFzgIV%2FbtsL3pmAf8N%2FmJZKSgFndbAa8omED6o4wk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;1059&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1533&quot; data-origin-height=&quot;2727&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Coding Test/백준</category>
      <category>BFS</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/695</guid>
      <comments>https://pixx.tistory.com/695#entry695comment</comments>
      <pubDate>Sat, 1 Feb 2025 16:14:00 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.02.01 - 퍼스트 파티(First Party)와 세컨드 파티(Second Party)</title>
      <link>https://pixx.tistory.com/694</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nNglp/btsL4F2Vi7R/UzIHkTkGy6FZ1DFVR7Aod1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nNglp/btsL4F2Vi7R/UzIHkTkGy6FZ1DFVR7Aod1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nNglp/btsL4F2Vi7R/UzIHkTkGy6FZ1DFVR7Aod1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnNglp%2FbtsL4F2Vi7R%2FUzIHkTkGy6FZ1DFVR7Aod1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;퍼스트&amp;nbsp;파티(First&amp;nbsp;Party)란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;퍼스트 파티(First Party)&lt;/b&gt;는 &lt;u&gt;&lt;b&gt;데이터를 직접 수집&lt;/b&gt;하고 &lt;b&gt;보유하는 주체&lt;/b&gt;&lt;/u&gt;를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 주로 기업이 &lt;b&gt;고객과 직접 &lt;span style=&quot;color: #ee2323;&quot;&gt;상호작용&lt;/span&gt;&lt;/b&gt;을 통해 얻은 &lt;b&gt;데이터&lt;/b&gt;를 말하며, 신뢰성이 높고 활용도가 뛰어납니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;퍼스트파티 데이터의 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 3 []&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;웹사이트 방문자가 남긴 정보 (회원 가입, 로그인, 쿠키, 행동 데이터)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;고객이 구매한 내역 및 트랜잭션 데이터&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;고객이 기업과 직접 소통한 데이터 (고객 문의, 설문조사 등)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;세컨드&amp;nbsp;파티(Second&amp;nbsp;Party)란❓&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;세컨드 파티(Second Party)&lt;/b&gt;는 &lt;b&gt;퍼스트 파티 데이터&lt;/b&gt;를&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt; 다른 기업&lt;/b&gt;&lt;/span&gt;과 &lt;b&gt;공유&lt;/b&gt;하거나 &lt;b&gt;제공&lt;/b&gt;받아 &lt;b&gt;활용하는 경우&lt;/b&gt;를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt; 보통 신뢰할 수 있는 &lt;b&gt;파트너&lt;/b&gt;나 &lt;b&gt;제휴사 간의 데이터 거래&lt;/b&gt;를 통해 이루어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;세컨드파티 데이터의 예시&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-pm-slice=&quot;3 3 []&quot; data-spread=&quot;false&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;항공사와 호텔 간의 데이터 공유 (예: 항공사가 호텔에 고객 데이터를 제공하여 맞춤형 서비스를 제공)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;광고 네트워크가 특정 기업과 제휴하여 고객 데이터를 공유&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;리테일 업체가 브랜드와 데이터를 공유하여 타겟 마케팅 강화&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;퍼스트,&amp;nbsp;세컨드,&amp;nbsp;써드&amp;nbsp;파티의&amp;nbsp;차이점&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 110px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 9.65116%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.8605%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;퍼스트&amp;nbsp;파티&amp;nbsp;(First&amp;nbsp;Party)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.0464%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;세컨드&amp;nbsp;파티&amp;nbsp;(Second&amp;nbsp;Party)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.4419%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;써드&amp;nbsp;파티&amp;nbsp;(Third&amp;nbsp;Party)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 9.65116%; height: 40px; text-align: center;&quot;&gt;&lt;b&gt;데이터 출처&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.8605%; height: 40px; text-align: center;&quot;&gt;&lt;b&gt;직접&amp;nbsp;수집한&amp;nbsp;데이터&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.0464%; height: 40px; text-align: center;&quot;&gt;&lt;b&gt;신뢰할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;파트너로부터&amp;nbsp;제공받은&amp;nbsp;데이터&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.4419%; height: 40px; text-align: center;&quot;&gt;&lt;b&gt;외부&amp;nbsp;플랫폼(데이터&amp;nbsp;브로커&amp;nbsp;등)에서&amp;nbsp;수집한&amp;nbsp;데이터&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 9.65116%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;신뢰도&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.8605%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;매우 높음&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.0464%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;비교적 높음&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.4419%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;상대적으로 낮음&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 9.65116%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;활용 목적&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.8605%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;내부&amp;nbsp;분석,&amp;nbsp;마케팅&amp;nbsp;최적화&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.0464%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;파트너십을&amp;nbsp;활용한&amp;nbsp;마케팅&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.4419%; height: 20px; text-align: center;&quot;&gt;&lt;b&gt;광고&amp;nbsp;및&amp;nbsp;대규모&amp;nbsp;마케팅&amp;nbsp;캠페인&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 10px;&quot;&gt;
&lt;td style=&quot;width: 9.65116%; height: 10px; text-align: center;&quot;&gt;&lt;b&gt;개인정보 보호&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 16.8605%; height: 10px; text-align: center;&quot;&gt;&lt;b&gt;강력한&amp;nbsp;규제&amp;nbsp;준수&amp;nbsp;가능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 26.0464%; height: 10px; text-align: center;&quot;&gt;&lt;b&gt;협의된&amp;nbsp;범위&amp;nbsp;내에서&amp;nbsp;준수&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 27.4419%; height: 10px; text-align: center;&quot;&gt;&lt;b&gt;규제&amp;nbsp;준수&amp;nbsp;어려움&amp;nbsp;(GDPR,&amp;nbsp;CCPA&amp;nbsp;등의&amp;nbsp;영향)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>til</category>
      <category>세컨드 파티</category>
      <category>퍼스트 파티</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/694</guid>
      <comments>https://pixx.tistory.com/694#entry694comment</comments>
      <pubDate>Sat, 1 Feb 2025 00:19:00 +0900</pubDate>
    </item>
    <item>
      <title>[TIL, 일일 회고] 2025.01.31 - 써드파티(3rd party)</title>
      <link>https://pixx.tistory.com/693</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/by6K6N/btsL5iMMCYW/fh8WdnQBcIDeLPejqeJ8Lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/by6K6N/btsL5iMMCYW/fh8WdnQBcIDeLPejqeJ8Lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/by6K6N/btsL5iMMCYW/fh8WdnQBcIDeLPejqeJ8Lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fby6K6N%2FbtsL5iMMCYW%2Ffh8WdnQBcIDeLPejqeJ8Lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;171&quot; data-origin-width=&quot;749&quot; data-origin-height=&quot;321&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;개요&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;현대 소프트웨어 개발에서 &lt;b&gt;써드파티 API&lt;/b&gt;는 필수불가결한 요소가 되었습니다. 본 글에서는 퍼스트파티,써드파티 중 써드파티의 개념부터 실제 활용 방법, 그리고 주의해야 할 점들까지 정리하고자 합니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;써드 파트(&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;3rd Party)란❓&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;282&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dMVOlD/btsL2KSeJrt/8GZJPjd6ObscEcXbQs5LkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dMVOlD/btsL2KSeJrt/8GZJPjd6ObscEcXbQs5LkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dMVOlD/btsL2KSeJrt/8GZJPjd6ObscEcXbQs5LkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdMVOlD%2FbtsL2KSeJrt%2F8GZJPjd6ObscEcXbQs5LkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;207&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;282&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&quot;3rd Party&lt;/span&gt;&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;&quot;는 &quot;제3자&quot; 또는 &quot;외부 당사자&quot;를 나타내는 용어입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;소프트웨어 개발에서 &quot;써드파티&quot;는 특정 기업이 아닌 &lt;b&gt;외부에서 개발한&lt;/b&gt; 라이브러리, 플러그인, API 등을 의미합니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;써드파티의 종류&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 3rd Party 라이브러리&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-spread=&quot;false&quot; data-pm-slice=&quot;3 3 []&quot;&gt;
&lt;li&gt;&lt;span&gt;특정 기능을 수행하는 코드 패키지로, &lt;s&gt;&lt;b&gt;개발자가 직접 구현&lt;/b&gt;&lt;/s&gt;하지 않고 &lt;b&gt;프로젝트에서 쉽게 가져와 사용&lt;/b&gt;할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;예시:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Lombok, Gson, Apache Commons, Log4j&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. 3rd Party SDK&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-spread=&quot;false&quot; data-pm-slice=&quot;3 3 []&quot;&gt;
&lt;li&gt;&lt;span&gt;특정 플랫폼이나 서비스와 &lt;b&gt;쉽게 연동&lt;/b&gt;할 수 있도록 제공되는 &lt;b&gt;개발 도구 모음&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;API뿐만 아니라 샘플 코드, 문서, 빌드 도구 등이 포함될 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;예시:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Firebase SDK, 토스 페이먼츠 SDK, Facebook SDK, AWS SDK&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. 3rd Party API&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-spread=&quot;false&quot; data-pm-slice=&quot;3 3 []&quot;&gt;
&lt;li&gt;&lt;span&gt;외부 서비스와 상호작용할 수 있도록 제공되는 API로, 특정 기능을 호출하여 사용할 수 있음&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;예시:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;b&gt;Google Maps API, Stripe API, OpenAI API, Twilio API&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;써드 파티(&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;3rd Party) API란❓&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;써드파티 API&lt;/b&gt;는 &lt;span&gt;특정 기업이나 서비스에서 개발하여 &lt;u&gt;&lt;b&gt;외부 개발자들이 사용할 수 있도록 공개한 API&lt;/b&gt;&lt;/u&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;쉽게 말해, &lt;b&gt;다른 회사에서 제공하는 기능&lt;/b&gt;을 우리 서비스에 쉽게 &lt;b&gt;연동&lt;/b&gt;할 수 있도록 만들어진 &lt;b&gt;API&lt;/b&gt;입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어, 우리가 웹사이트나 앱에 &quot;카카오 로그인&quot;, &quot;네이버 지도&quot;, &quot;토스페이먼츠 결제&quot; 같은 기능을 추가할 때 해당 기업에서 제공하는 API를 활용하면 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;&lt;b&gt;직접 기능을 개발&lt;/b&gt;&lt;/s&gt;&lt;/span&gt;하지 않고도 &lt;b&gt;쉽게 적용&lt;/b&gt;할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;span style=&quot;border-bottom: 12px solid #dcf1fb; padding: 0px 0px 0px 0.2em; font-weight: bold;&quot;&gt;&lt;b&gt;써드파티 API의 특징&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;1. 외부 제공&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;특정 기업(제공자)이 개발하고, &lt;b&gt;외부&lt;/b&gt; 개발자나 기업이 사용할 수 있도록 공개한 API입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;2. 특정 기능 제공&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결제, 지도, 번역, 로그인, 메시징, AI 등의 기능을 제공하여 개발자가 빠르게 서비스에 적용할 수 있도록 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;3. 인증 필요&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;대부분 &lt;b&gt;API 키(API Key)&lt;/b&gt; 또는 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;b&gt;OAuth 인증&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; 방식을 사용하여 &lt;u&gt;&lt;b&gt;보안이 강화&lt;/b&gt;&lt;/u&gt;되어 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;span style=&quot;border-radius: 15px 15px 15px 0; border-bottom: 5px solid #B9C4C4; padding: 0.5em; background: #CEDADA; font-weight: bold;&quot;&gt;&lt;span&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;4. 공식 문서 제공&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;API 사용법, 예제 코드, 응답 형식 등을 정리한 공식 문서가 함께 제공됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;써드 파티(&lt;span style=&quot;color: #374151; text-align: start;&quot;&gt;3rd Party) API의 장점&lt;/span&gt;&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;개발 시간 단축&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;직접 개발할 필요 없이 검증된 기능을 바로 사용&lt;/li&gt;
&lt;li&gt;복잡한 기능도 간단한 API 호출로 구현 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비용 절감&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자체 개발 대비 저렴한 비용&lt;/li&gt;
&lt;li&gt;유지보수 부담 감소&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전문성 활용&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 분야 전문 기업의 기술력 활용&lt;/li&gt;
&lt;li&gt;지속적인 업데이트와 보안 관리 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;padding: 0.6em 0.5em 0.6em 0.5em; margin: 0.5em 0em; color: #000; border-left: 10px solid #0f2443; border-bottom: 2px solid #e5e5e5; background-color: #ffffff; font-weight: bold;&quot; data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;써드파티 API&lt;/b&gt;는 현대 개발에서&lt;b&gt; 중요한 도구&lt;/b&gt;이지만, &lt;b&gt;신중한 선택&lt;/b&gt;과 &lt;b&gt;올바른 활용&lt;/b&gt;이 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보안, 성능, 비용 등 다양한 측면을 고려하여 프로젝트에 &lt;b&gt;적합한 API를 선택&lt;/b&gt;하고, 모범 사례를 따라 구현한다면 &lt;b&gt;개발 생산성을 크게 향상&lt;/b&gt;시킬 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>TIL,일일 회고</category>
      <category>til</category>
      <category>써드파티</category>
      <category>써드파티 api</category>
      <author>지누박</author>
      <guid isPermaLink="true">https://pixx.tistory.com/693</guid>
      <comments>https://pixx.tistory.com/693#entry693comment</comments>
      <pubDate>Fri, 31 Jan 2025 23:32:21 +0900</pubDate>
    </item>
  </channel>
</rss>