<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>chungmani 님의 블로그</title>
    <link>https://chungmani.tistory.com/</link>
    <description>Done is better than perfect.</description>
    <language>ko</language>
    <pubDate>Tue, 4 Aug 2026 21:28:39 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>chungmani</managingEditor>
    <image>
      <title>chungmani 님의 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/8685036/attach/3ce3519526b5473bb83756d975a30879</url>
      <link>https://chungmani.tistory.com</link>
    </image>
    <item>
      <title>AWS VPC와 EC2 기초 정리</title>
      <link>https://chungmani.tistory.com/58</link>
      <description>&lt;p data-end=&quot;173&quot; data-start=&quot;108&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 AWS에서 직접 &lt;b&gt;VPC를 구성하고 Public Subnet에 EC2를 생성한 뒤 SSH로 접속&lt;/b&gt;해보았다.&lt;/p&gt;
&lt;p data-end=&quot;238&quot; data-start=&quot;175&quot; data-ke-size=&quot;size16&quot;&gt;처음에는 VPC, Subnet, EC2가 전부 따로 노는 개념처럼 보였는데 직접 구성해보니 다음과 같은 관계였다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;AWS
│
└── VPC
     │
     ├── Public Subnet
     │      │
     │      └── EC2 &amp;larr; 오늘 생성한 서버
     │
     └── Private Subnet&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&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;style6&quot; /&gt;
&lt;h2 data-end=&quot;390&quot; data-start=&quot;379&quot; data-section-id=&quot;1a2fikg&quot; data-ke-size=&quot;size26&quot;&gt;1. VPC란?&lt;/h2&gt;
&lt;p data-end=&quot;432&quot; data-start=&quot;409&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;VPC(Virtual Private Cloud)&lt;/b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;는 AWS 클라우드 안에 만드는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;사용자 전용 가상 네트워크&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;432&quot; data-start=&quot;409&quot; data-ke-size=&quot;size16&quot;&gt;AWS를 아주 거대한 땅이라고 한다면 그중에서 내가 사용할 공간을 하나 떼어서 울타리를 치고,&lt;/p&gt;
&lt;p data-end=&quot;495&quot; data-start=&quot;469&quot; data-ke-size=&quot;size16&quot;&gt;&quot;여기부터 여기까지는 내가 사용할 네트워크야&quot; &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;라고 만든 공간이 &lt;/span&gt;&lt;b&gt;VPC&lt;/b&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-end=&quot;495&quot; data-start=&quot;469&quot; 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;style6&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;852&quot; data-start=&quot;837&quot; data-section-id=&quot;1aglkp5&quot; data-ke-size=&quot;size26&quot;&gt;2. Subnet이란?&lt;/h2&gt;
&lt;p data-end=&quot;906&quot; data-start=&quot;854&quot; data-ke-size=&quot;size16&quot;&gt;VPC라는 큰 네트워크 공간을 다시 작은 네트워크 영역으로 나눈 것이 &lt;b&gt;Subnet&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;916&quot; data-start=&quot;908&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;VPC = 회사 건물 전체

Subnet = 건물 내부의 구역&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;p data-end=&quot;990&quot; data-start=&quot;966&quot; data-ke-size=&quot;size16&quot;&gt;두 종류의 Subnet을 만들었다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;VPC
│
├── Public Subnet
│
└── Private Subnet&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;h3 data-end=&quot;1067&quot; data-start=&quot;1050&quot; data-section-id=&quot;1p94a0s&quot; data-ke-size=&quot;size23&quot;&gt;Public Subnet&lt;/h3&gt;
&lt;p data-end=&quot;1133&quot; data-start=&quot;1069&quot; data-ke-size=&quot;size16&quot;&gt;인터넷과 직접 통신할 수 있도록 &lt;b&gt;Internet Gateway로 가는 라우팅 경로가 설정된 Subnet&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-end=&quot;1187&quot; data-start=&quot;1135&quot; data-ke-size=&quot;size16&quot;&gt;오늘 생성한 EC2는 외부에서 직접 접속해야 했기 때문에 Public Subnet에 배치했다.&lt;/p&gt;
&lt;h3 data-end=&quot;1207&quot; data-start=&quot;1189&quot; data-section-id=&quot;1sbzik0&quot; data-ke-size=&quot;size23&quot;&gt;Private Subnet&lt;/h3&gt;
&lt;p data-end=&quot;1242&quot; data-start=&quot;1209&quot; data-ke-size=&quot;size16&quot;&gt;인터넷에서 직접 접근하지 못하도록 구성하는 Subnet이다.&lt;/p&gt;
&lt;p data-end=&quot;1293&quot; data-start=&quot;1244&quot; data-ke-size=&quot;size16&quot;&gt;나중에는 DB나 외부에 직접 노출할 필요가 없는 서버 등을 이런 영역에 배치할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;1293&quot; data-start=&quot;1244&quot; 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;style6&quot; /&gt;
&lt;h2 data-end=&quot;1408&quot; data-start=&quot;1382&quot; data-section-id=&quot;1xl5ah7&quot; data-ke-size=&quot;size26&quot;&gt;3. 왜 Subnet을 2개씩 만들었을까?&lt;/h2&gt;
&lt;p data-end=&quot;1452&quot; data-start=&quot;1410&quot; data-ke-size=&quot;size16&quot;&gt;이번에는 &lt;b&gt;2개의 Availability Zone(AZ)&lt;/b&gt;을 사용했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;                VPC
                 │
        ┌────────┴────────┐
        │                 │
       AZ 2a             AZ 2b
        │                 │
   ┌────┴────┐       ┌────┴────┐
 Public   Private    Public   Private&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;p data-end=&quot;1833&quot; data-start=&quot;1779&quot; data-ke-size=&quot;size16&quot;&gt;여러 AZ를 사용하는 가장 큰 이유는 &lt;b&gt;고가용성(High Availability)&lt;/b&gt; 때문이다.&lt;/p&gt;
&lt;p data-end=&quot;1895&quot; data-start=&quot;1835&quot; data-ke-size=&quot;size16&quot;&gt;한 AZ에 장애가 발생하더라도 다른 AZ의 리소스를 이용해 서비스를 계속 운영할 수 있도록 구성할 수 있다.&lt;/p&gt;
&lt;p data-end=&quot;2094&quot; data-start=&quot;2054&quot; 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;style6&quot; /&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-end=&quot;2273&quot; data-start=&quot;2263&quot; data-section-id=&quot;1man7o6&quot; data-ke-size=&quot;size26&quot;&gt;4. EC2란?&lt;/h2&gt;
&lt;h3 data-end=&quot;2291&quot; data-start=&quot;2275&quot; data-section-id=&quot;12emr4f&quot; data-ke-size=&quot;size23&quot;&gt;EC2를 쉽게 생각하면&lt;/h3&gt;
&lt;p data-end=&quot;2330&quot; data-start=&quot;2293&quot; data-ke-size=&quot;size16&quot;&gt;AWS에서 &lt;b&gt;컴퓨터 한 대를 빌리는 서비스&lt;/b&gt;라고 생각하면 된다.&lt;/p&gt;
&lt;p data-end=&quot;2390&quot; data-start=&quot;2332&quot; data-ke-size=&quot;size16&quot;&gt;내 책상 위에 있는 컴퓨터가 아니라 AWS 데이터센터에 있는 가상 서버를 인터넷을 통해 사용하는 것이다.&lt;/p&gt;
&lt;p data-end=&quot;2467&quot; data-start=&quot;2392&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;EC2(Elastic Compute Cloud)&lt;/b&gt;는 AWS에서 가상 서버를 생성하고 사용할 수 있도록 제공하는 컴퓨팅 서비스다.&lt;/p&gt;
&lt;p data-end=&quot;2467&quot; data-start=&quot;2392&quot; 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;style6&quot; /&gt;
&lt;h2 data-end=&quot;4053&quot; data-start=&quot;4043&quot; data-section-id=&quot;1bzf8fa&quot; data-ke-size=&quot;size26&quot;&gt;5. SSH란?&lt;/h2&gt;
&lt;p data-end=&quot;4098&quot; data-start=&quot;4055&quot; data-ke-size=&quot;size16&quot;&gt;EC2를 만들었지만 AWS 데이터센터에 직접 가서 키보드를 연결할 수는 없다.&lt;/p&gt;
&lt;p data-end=&quot;4121&quot; data-start=&quot;4100&quot; data-ke-size=&quot;size16&quot;&gt;그래서 사용하는 것이 &lt;b&gt;SSH&lt;/b&gt;다.&lt;/p&gt;
&lt;p data-end=&quot;4191&quot; data-start=&quot;4123&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SSH(Secure Shell)&lt;/b&gt;는 원격 컴퓨터에 안전하게 접속하여 명령어를 실행할 수 있도록 해주는 프로토콜이다.&lt;/p&gt;
&lt;p data-end=&quot;4204&quot; data-start=&quot;4193&quot; data-ke-size=&quot;size16&quot;&gt;구조는 다음과 같다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;내 Windows PC
      │
      │ SSH
      │ TCP 22
      ▼
     EC2
 Amazon Linux&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;p data-end=&quot;4580&quot; data-start=&quot;4573&quot; 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;style6&quot; /&gt;
&lt;h2 data-end=&quot;4609&quot; data-start=&quot;4587&quot; data-section-id=&quot;y7ok2q&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;6. Key Pair와 .pem&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;4638&quot; data-start=&quot;4611&quot; data-ke-size=&quot;size16&quot;&gt;EC2 생성 과정에서 Key Pair도 생성했다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;aws-cloud-key.pem&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;p data-end=&quot;4708&quot; data-start=&quot;4671&quot; data-ke-size=&quot;size16&quot;&gt;SSH 접속 시 비밀번호 대신 이 Private Key를 사용했다.&lt;/p&gt;
&lt;p data-end=&quot;4720&quot; data-start=&quot;4710&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;chmod 400 aws-cloud-key.pem&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;4770&quot; data-start=&quot;4763&quot; data-ke-size=&quot;size16&quot;&gt;그리고 접속 전에 위 명령어를 실행했다.&lt;/p&gt;
&lt;p data-end=&quot;4810&quot; data-start=&quot;4772&quot; data-ke-size=&quot;size16&quot;&gt;이는 Private Key 파일에 대한 권한을 제한하기 위한 것이다.&lt;/p&gt;
&lt;p data-end=&quot;4852&quot; data-start=&quot;4812&quot; data-ke-size=&quot;size16&quot;&gt;.pem 파일은 &lt;b&gt;절대로 GitHub 등에 업로드하면 안 된다.&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;❌ AWS Access Key
❌ Secret Access Key
❌ .pem Private Key
❌ DB Password
❌ API Token&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;p data-end=&quot;4979&quot; data-start=&quot;4949&quot; data-ke-size=&quot;size16&quot;&gt;이런 값들은 Git으로 관리하지 않는 습관이 중요하다.&lt;/p&gt;
&lt;p data-end=&quot;6745&quot; data-start=&quot;6586&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>AWS</category>
      <category>aws</category>
      <category>개발자</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/58</guid>
      <comments>https://chungmani.tistory.com/58#entry58comment</comments>
      <pubDate>Mon, 3 Aug 2026 21:30:22 +0900</pubDate>
    </item>
    <item>
      <title>REPLACE, SUBSTRING, CONCAT 함수 정리</title>
      <link>https://chungmani.tistory.com/57</link>
      <description>&lt;h2 data-end=&quot;203&quot; data-start=&quot;190&quot; data-section-id=&quot;1ob1ed2&quot; data-ke-size=&quot;size26&quot;&gt;1. REPLACE&lt;/h2&gt;
&lt;p data-end=&quot;252&quot; data-start=&quot;205&quot; data-ke-size=&quot;size16&quot;&gt;문자열에서 특정 문자를 다른 문자로 변경할 때 사용하는 함수&lt;/p&gt;
&lt;h4 data-end=&quot;263&quot; data-start=&quot;254&quot; data-section-id=&quot;17ow5kz&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-end=&quot;263&quot; data-start=&quot;254&quot; data-section-id=&quot;17ow5kz&quot; data-ke-size=&quot;size20&quot;&gt;기본 문법&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;REPLACE(문자열, 변경할 문자열, 변경될 문자열)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;314&quot; data-start=&quot;308&quot; data-section-id=&quot;1hrqnwy&quot; data-ke-size=&quot;size20&quot;&gt;예시&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT REPLACE('Hello World', 'World', 'SQL');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;381&quot; data-start=&quot;375&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Hello SQL&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-end=&quot;426&quot; data-start=&quot;411&quot; data-section-id=&quot;yqrg7c&quot; data-ke-size=&quot;size26&quot;&gt;2. SUBSTRING&lt;/h2&gt;
&lt;p data-end=&quot;464&quot; data-start=&quot;428&quot; data-ke-size=&quot;size16&quot;&gt;문자열의 일부를 잘라서 가져오는 함수&lt;/p&gt;
&lt;h4 data-end=&quot;475&quot; data-start=&quot;466&quot; data-section-id=&quot;17ow5kz&quot; data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-end=&quot;475&quot; data-start=&quot;466&quot; data-section-id=&quot;17ow5kz&quot; data-ke-size=&quot;size20&quot;&gt;기본 문법&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;SUBSTRING(문자열, 시작위치, 길이)&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시작위치는 1부터 시작&lt;/p&gt;
&lt;blockquote data-end=&quot;536&quot; data-start=&quot;514&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;536&quot; data-start=&quot;516&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-end=&quot;544&quot; data-start=&quot;538&quot; data-section-id=&quot;1hrqnwy&quot; data-ke-size=&quot;size23&quot;&gt;예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT SUBSTRING('Database', 1, 4);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;p data-end=&quot;600&quot; data-start=&quot;594&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;Data&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&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;/div&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;style6&quot; /&gt;
&lt;h2 data-end=&quot;637&quot; data-start=&quot;625&quot; data-section-id=&quot;1rolxf0&quot; data-ke-size=&quot;size26&quot;&gt;3. CONCAT&lt;/h2&gt;
&lt;p data-end=&quot;679&quot; data-start=&quot;639&quot; data-ke-size=&quot;size16&quot;&gt;여러 문자열을 하나로 이어 붙일 때 사용하는 함수&lt;/p&gt;
&lt;h3 data-end=&quot;690&quot; data-start=&quot;681&quot; data-section-id=&quot;17ow5kz&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h4 data-end=&quot;690&quot; data-start=&quot;681&quot; data-section-id=&quot;17ow5kz&quot; data-ke-size=&quot;size20&quot;&gt;기본 문법&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;CONCAT(문자열1, 문자열2, ...)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-end=&quot;734&quot; data-start=&quot;728&quot; data-section-id=&quot;1hrqnwy&quot; data-ke-size=&quot;size20&quot;&gt;예시&lt;/h4&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT CONCAT('Hello', ' ', 'SQL');&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;790&quot; data-start=&quot;784&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;Hello SQL&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>SQL</category>
      <category>SQL</category>
      <category>개발자</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/57</guid>
      <comments>https://chungmani.tistory.com/57#entry57comment</comments>
      <pubDate>Fri, 31 Jul 2026 21:22:12 +0900</pubDate>
    </item>
    <item>
      <title>클라우드</title>
      <link>https://chungmani.tistory.com/56</link>
      <description>&lt;h2 data-end=&quot;75&quot; data-start=&quot;66&quot; data-section-id=&quot;n08uv2&quot; data-ke-size=&quot;size26&quot;&gt;클라우드란?&lt;/h2&gt;
&lt;p data-end=&quot;151&quot; data-start=&quot;77&quot; data-ke-size=&quot;size16&quot;&gt;클라우드(Cloud)란 인터넷을 통해 서버, 저장소, 데이터베이스, 네트워크 등의 IT 자원을 필요한 만큼 빌려 사용하는 서비스이다.&lt;/p&gt;
&lt;p data-end=&quot;224&quot; data-start=&quot;153&quot; data-ke-size=&quot;size16&quot;&gt;예전에는 직접 서버를 구매하고 관리해야 했지만, 클라우드를 사용하면 필요한 만큼만 사용하고 비용도 사용한 만큼만 지불하면 된다.&lt;/p&gt;
&lt;p data-end=&quot;224&quot; data-start=&quot;153&quot; 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;style6&quot; /&gt;
&lt;p data-end=&quot;383&quot; data-start=&quot;331&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;403&quot; data-start=&quot;390&quot; data-section-id=&quot;1epxmo3&quot; data-ke-size=&quot;size26&quot;&gt;클라우드 서비스 종류&lt;/h2&gt;
&lt;p data-end=&quot;455&quot; data-start=&quot;405&quot; data-ke-size=&quot;size16&quot;&gt;클라우드는 제공 범위에 따라 크게 &lt;b&gt;IaaS, PaaS, SaaS&lt;/b&gt; 세 가지로 나뉜다.&lt;/p&gt;
&lt;p data-end=&quot;455&quot; data-start=&quot;405&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-end=&quot;502&quot; data-start=&quot;462&quot; data-section-id=&quot;1amflt4&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;1. IaaS (Infrastructure as a Service)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;537&quot; data-start=&quot;504&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인프라(서버, 네트워크, 스토리지)를 제공하는 서비스&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;572&quot; data-start=&quot;539&quot; data-ke-size=&quot;size16&quot;&gt;사용자는 운영체제 설치부터 프로그램 실행까지 직접 관리한다.&lt;/p&gt;
&lt;h3 data-end=&quot;580&quot; data-start=&quot;574&quot; data-section-id=&quot;1hrlj9m&quot; data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;641&quot; data-start=&quot;582&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;596&quot; data-start=&quot;582&quot; data-section-id=&quot;13cqm0l&quot;&gt;서버를 직접 생성 가능&lt;/li&gt;
&lt;li data-end=&quot;611&quot; data-start=&quot;597&quot; data-section-id=&quot;1u8ruga&quot;&gt;운영체제 설치 및 관리&lt;/li&gt;
&lt;li data-end=&quot;620&quot; data-start=&quot;612&quot; data-section-id=&quot;qy38fi&quot;&gt;높은 자유도&lt;/li&gt;
&lt;li data-end=&quot;641&quot; data-start=&quot;621&quot; data-section-id=&quot;wswvog&quot;&gt;개발자가 서버를 직접 관리해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;653&quot; data-start=&quot;643&quot; data-section-id=&quot;vogpfq&quot; data-ke-size=&quot;size23&quot;&gt;대표 서비스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;722&quot; data-start=&quot;655&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;664&quot; data-start=&quot;655&quot; data-section-id=&quot;17n9ypl&quot;&gt;AWS EC2&lt;/li&gt;
&lt;li data-end=&quot;698&quot; data-start=&quot;665&quot; data-section-id=&quot;10xk9k1&quot;&gt;Microsoft Azure Virtual Machine&lt;/li&gt;
&lt;li data-end=&quot;722&quot; data-start=&quot;699&quot; data-section-id=&quot;1bdfska&quot;&gt;Google Compute Engine&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;730&quot; data-start=&quot;724&quot; data-section-id=&quot;1hrjeoy&quot; data-ke-size=&quot;size23&quot;&gt;비유&lt;/h3&gt;
&lt;blockquote data-end=&quot;752&quot; data-start=&quot;732&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;752&quot; data-start=&quot;734&quot; data-ke-size=&quot;size16&quot;&gt;빈 땅을 빌려 집을 직접 짓는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;793&quot; data-start=&quot;759&quot; data-section-id=&quot;1jzemtm&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h3 data-end=&quot;793&quot; data-start=&quot;759&quot; data-section-id=&quot;1jzemtm&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;2. PaaS (Platform as a Service)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-end=&quot;830&quot; data-start=&quot;795&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;애플리케이션을 실행할 수 있는 플랫폼까지 제공하는 서비스&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;884&quot; data-start=&quot;832&quot; data-ke-size=&quot;size16&quot;&gt;운영체제나 서버 관리는 서비스 제공자가 해주고, 개발자는 코드 작성과 배포에만 집중하면 된다.&lt;/p&gt;
&lt;h3 data-end=&quot;892&quot; data-start=&quot;886&quot; data-section-id=&quot;1hrlj9m&quot; data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;937&quot; data-start=&quot;894&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;907&quot; data-start=&quot;894&quot; data-section-id=&quot;1ihiwx2&quot;&gt;서버 관리 필요 없음&lt;/li&gt;
&lt;li data-end=&quot;924&quot; data-start=&quot;908&quot; data-section-id=&quot;b01phw&quot;&gt;코드만 배포하면 실행 가능&lt;/li&gt;
&lt;li data-end=&quot;937&quot; data-start=&quot;925&quot; data-section-id=&quot;w581su&quot;&gt;개발 생산성이 높음&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;949&quot; data-start=&quot;939&quot; data-section-id=&quot;vogpfq&quot; data-ke-size=&quot;size23&quot;&gt;대표 서비스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1003&quot; data-start=&quot;951&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;974&quot; data-start=&quot;951&quot; data-section-id=&quot;175mx41&quot;&gt;AWS Elastic Beanstalk&lt;/li&gt;
&lt;li data-end=&quot;994&quot; data-start=&quot;975&quot; data-section-id=&quot;rnrctq&quot;&gt;Google App Engine&lt;/li&gt;
&lt;li data-end=&quot;1003&quot; data-start=&quot;995&quot; data-section-id=&quot;1mrvysm&quot;&gt;Heroku&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1011&quot; data-start=&quot;1005&quot; data-section-id=&quot;1hrjeoy&quot; data-ke-size=&quot;size23&quot;&gt;비유&lt;/h3&gt;
&lt;blockquote data-end=&quot;1038&quot; data-start=&quot;1013&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;1038&quot; data-start=&quot;1015&quot; data-ke-size=&quot;size16&quot;&gt;이미 지어진 집을 빌려 가구만 배치하는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-end=&quot;1079&quot; data-start=&quot;1045&quot; data-section-id=&quot;69ibx4&quot; data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-end=&quot;1079&quot; data-start=&quot;1045&quot; data-section-id=&quot;69ibx4&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #f3c000;&quot;&gt;3. SaaS (Software as a Service)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-end=&quot;1112&quot; data-start=&quot;1081&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;완성된 소프트웨어를 인터넷을 통해 사용하는 서비스&lt;/b&gt;&lt;/p&gt;
&lt;p data-end=&quot;1149&quot; data-start=&quot;1114&quot; data-ke-size=&quot;size16&quot;&gt;사용자는 설치나 관리 없이 로그인만 하면 바로 사용할 수 있다.&lt;/p&gt;
&lt;h3 data-end=&quot;1157&quot; data-start=&quot;1151&quot; data-section-id=&quot;1hrlj9m&quot; data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1209&quot; data-start=&quot;1159&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1169&quot; data-start=&quot;1159&quot; data-section-id=&quot;1l666m&quot;&gt;설치 필요 없음&lt;/li&gt;
&lt;li data-end=&quot;1189&quot; data-start=&quot;1170&quot; data-section-id=&quot;j6zyzh&quot;&gt;웹 브라우저만 있으면 사용 가능&lt;/li&gt;
&lt;li data-end=&quot;1209&quot; data-start=&quot;1190&quot; data-section-id=&quot;y86ens&quot;&gt;유지보수는 서비스 제공자가 담당&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1221&quot; data-start=&quot;1211&quot; data-section-id=&quot;vogpfq&quot; data-ke-size=&quot;size23&quot;&gt;대표 서비스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-end=&quot;1279&quot; data-start=&quot;1223&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li data-end=&quot;1230&quot; data-start=&quot;1223&quot; data-section-id=&quot;16zvg6e&quot;&gt;Gmail&lt;/li&gt;
&lt;li data-end=&quot;1245&quot; data-start=&quot;1231&quot; data-section-id=&quot;1ajm10t&quot;&gt;Google Drive&lt;/li&gt;
&lt;li data-end=&quot;1261&quot; data-start=&quot;1246&quot; data-section-id=&quot;1o1e1rg&quot;&gt;Microsoft 365&lt;/li&gt;
&lt;li data-end=&quot;1269&quot; data-start=&quot;1262&quot; data-section-id=&quot;178nx5q&quot;&gt;Slack&lt;/li&gt;
&lt;li data-end=&quot;1279&quot; data-start=&quot;1270&quot; data-section-id=&quot;6gc00l&quot;&gt;ChatGPT&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-end=&quot;1287&quot; data-start=&quot;1281&quot; data-section-id=&quot;1hrjeoy&quot; data-ke-size=&quot;size23&quot;&gt;비유&lt;/h3&gt;
&lt;blockquote data-end=&quot;1306&quot; data-start=&quot;1289&quot; data-ke-style=&quot;style2&quot;&gt;
&lt;p data-end=&quot;1306&quot; data-start=&quot;1291&quot; data-ke-size=&quot;size16&quot;&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;style6&quot; /&gt;
&lt;h1 data-end=&quot;1334&quot; data-start=&quot;1313&quot; data-section-id=&quot;56j1e3&quot;&gt;IaaS, PaaS, SaaS 비교&lt;/h1&gt;
&lt;div&gt;&lt;br /&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 101px;&quot; border=&quot;1&quot; data-end=&quot;1563&quot; data-start=&quot;1336&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;Iaas&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;Paas&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;SaaS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;1435&quot; data-start=&quot;1394&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1402&quot; data-start=&quot;1394&quot;&gt;제공 범위&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1413&quot; data-start=&quot;1402&quot; data-col-size=&quot;sm&quot;&gt;서버, 네트워크&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1422&quot; data-start=&quot;1413&quot; data-col-size=&quot;sm&quot;&gt;개발 플랫폼&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1435&quot; data-start=&quot;1422&quot; data-col-size=&quot;sm&quot;&gt;완성된 소프트웨어&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;1475&quot; data-start=&quot;1436&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1444&quot; data-start=&quot;1436&quot;&gt;서버 관리&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1454&quot; data-start=&quot;1444&quot; data-col-size=&quot;sm&quot;&gt;사용자가 직접&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1464&quot; data-start=&quot;1454&quot; data-col-size=&quot;sm&quot;&gt;서비스 제공자&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1475&quot; data-start=&quot;1464&quot; data-col-size=&quot;sm&quot;&gt;서비스 제공자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;1501&quot; data-start=&quot;1476&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1484&quot; data-start=&quot;1476&quot;&gt;개발 가능&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1489&quot; data-start=&quot;1484&quot; data-col-size=&quot;sm&quot;&gt;가능&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1494&quot; data-start=&quot;1489&quot; data-col-size=&quot;sm&quot;&gt;가능&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1501&quot; data-start=&quot;1494&quot; data-col-size=&quot;sm&quot;&gt;불가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 21px;&quot; data-end=&quot;1563&quot; data-start=&quot;1502&quot;&gt;
&lt;td style=&quot;height: 21px;&quot; data-col-size=&quot;sm&quot; data-end=&quot;1511&quot; data-start=&quot;1502&quot;&gt;대표 서비스&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1521&quot; data-start=&quot;1511&quot; data-col-size=&quot;sm&quot;&gt;AWS EC2&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1545&quot; data-start=&quot;1521&quot; data-col-size=&quot;sm&quot;&gt;AWS Elastic Beanstalk&lt;/td&gt;
&lt;td style=&quot;height: 21px;&quot; data-end=&quot;1563&quot; data-start=&quot;1545&quot; data-col-size=&quot;sm&quot;&gt;Gmail, ChatGPT&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;</description>
      <category>AWS</category>
      <category>IaaS</category>
      <category>paas</category>
      <category>SaaS</category>
      <category>개발자</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/56</guid>
      <comments>https://chungmani.tistory.com/56#entry56comment</comments>
      <pubDate>Thu, 30 Jul 2026 20:26:27 +0900</pubDate>
    </item>
    <item>
      <title>SQL ORDER BY 정리</title>
      <link>https://chungmani.tistory.com/55</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. ORDER BY&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ORDER BY는 SELECT로 조회한 결과를 &lt;b&gt;특정 컬럼을 기준으로 정렬&lt;/b&gt;할 때 사용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 &lt;b&gt;오름차순(ASC)&lt;/b&gt; 으로 정렬된다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT *
FROM users
ORDER BY age;
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. ASC : 오름차순&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작은 값 &amp;rarr; 큰 값 순서로 정렬&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT *
FROM users
ORDER BY age ASC;
&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;철수&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;영희&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;민수&lt;/td&gt;
&lt;td&gt;30&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. DESC : 내림차순&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큰 값 &amp;rarr; 작은 값 순서로 정렬&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT *
FROM users
ORDER BY age DESC;
&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;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;민수&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;영희&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;철수&lt;/td&gt;
&lt;td&gt;20&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 contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 여러 컬럼으로 정렬하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정렬 기준을 여러 개 지정할 수도 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT *
FROM users
ORDER BY age ASC, name ASC;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 먼저 age를 기준으로 정렬하고, 나이가 같은 데이터가 있다면 name을 기준으로 추가 정렬됨.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;민수&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;철수&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;영희&lt;/td&gt;
&lt;td&gt;25&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;</description>
      <category>SQL</category>
      <category>SQL</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/55</guid>
      <comments>https://chungmani.tistory.com/55#entry55comment</comments>
      <pubDate>Wed, 29 Jul 2026 20:59:22 +0900</pubDate>
    </item>
    <item>
      <title>SQL 집계 함수와 GROUP BY</title>
      <link>https://chungmani.tistory.com/54</link>
      <description>&lt;p data-end=&quot;227&quot; data-start=&quot;183&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-end=&quot;259&quot; data-start=&quot;234&quot; data-section-id=&quot;1glylh0&quot; data-ke-size=&quot;size26&quot;&gt;1. COUNT() &amp;mdash; 데이터 개수 세기&lt;/h2&gt;
&lt;p data-end=&quot;294&quot; data-start=&quot;261&quot; data-ke-size=&quot;size16&quot;&gt;조건에 맞는 데이터가 &lt;b&gt;몇 개인지&lt;/b&gt; 확인할 때 사용&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT COUNT(*)
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;370&quot; data-start=&quot;336&quot; data-ke-size=&quot;size16&quot;&gt;users 테이블에 있는 전체 행의 개수를 반환한다.&lt;/p&gt;
&lt;p data-end=&quot;391&quot; data-start=&quot;372&quot; data-ke-size=&quot;size16&quot;&gt;특정 컬럼의 개수를 셀 수도 있다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT COUNT(email)
FROM users;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;474&quot; data-start=&quot;437&quot; data-ke-size=&quot;size16&quot;&gt;email 값이 NULL이 아닌 데이터의 개수를 센다.&lt;/p&gt;
&lt;p data-end=&quot;474&quot; data-start=&quot;437&quot; 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;style6&quot; /&gt;
&lt;h2 data-end=&quot;544&quot; data-start=&quot;527&quot; data-section-id=&quot;wppohx&quot; data-ke-size=&quot;size26&quot;&gt;2. MAX() &amp;mdash; 최댓값&lt;/h2&gt;
&lt;p data-end=&quot;576&quot; data-start=&quot;546&quot; data-ke-size=&quot;size16&quot;&gt;특정 컬럼에서 &lt;b&gt;가장 큰 값&lt;/b&gt;을 찾을 때 사용&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT MAX(price)
FROM products;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;650&quot; data-start=&quot;623&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;style6&quot; /&gt;
&lt;h2 data-end=&quot;709&quot; data-start=&quot;692&quot; data-section-id=&quot;16ow81i&quot; data-ke-size=&quot;size26&quot;&gt;3. MIN() &amp;mdash; 최솟값&lt;/h2&gt;
&lt;p data-end=&quot;742&quot; data-start=&quot;711&quot; data-ke-size=&quot;size16&quot;&gt;특정 컬럼에서 &lt;b&gt;가장 작은 값&lt;/b&gt;을 찾을 때 사용&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT MIN(price)
FROM products;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;817&quot; data-start=&quot;789&quot; data-ke-size=&quot;size16&quot;&gt;상품 중 &lt;b&gt;가장 저렴한 가격&lt;/b&gt;을 조회한다.&lt;/p&gt;
&lt;p data-end=&quot;817&quot; data-start=&quot;789&quot; 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;style6&quot; /&gt;
&lt;h2 data-end=&quot;877&quot; data-start=&quot;860&quot; data-section-id=&quot;1m7mhlt&quot; data-ke-size=&quot;size26&quot;&gt;4. AVG() &amp;mdash; 평균값&lt;/h2&gt;
&lt;p data-end=&quot;899&quot; data-start=&quot;879&quot; data-ke-size=&quot;size16&quot;&gt;특정 컬럼의 &lt;b&gt;평균&lt;/b&gt;을 계산한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT AVG(price)
FROM products;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;972&quot; data-start=&quot;946&quot; data-ke-size=&quot;size16&quot;&gt;전체 상품의 &lt;b&gt;평균 가격&lt;/b&gt;을 조회한다.&lt;/p&gt;
&lt;p data-end=&quot;972&quot; data-start=&quot;946&quot; 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;style6&quot; /&gt;
&lt;h2 data-end=&quot;1042&quot; data-start=&quot;1014&quot; data-section-id=&quot;1kzydjj&quot; data-ke-size=&quot;size26&quot;&gt;5. GROUP BY &amp;mdash; 같은 종류끼리 그룹화&lt;/h2&gt;
&lt;p data-end=&quot;1092&quot; data-start=&quot;1044&quot; data-ke-size=&quot;size16&quot;&gt;GROUP BY는 특정 컬럼을 기준으로 데이터를 &lt;b&gt;그룹으로 묶을 때&lt;/b&gt; 사용한다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;product_namecategoryprice
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1289&quot; data-start=&quot;1130&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1289&quot; data-start=&quot;1181&quot;&gt;
&lt;tr data-end=&quot;1214&quot; data-start=&quot;1181&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1194&quot; data-start=&quot;1181&quot;&gt;Galaxy S25&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1201&quot; data-start=&quot;1194&quot;&gt;전자제품&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1214&quot; data-start=&quot;1201&quot;&gt;1,200,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1247&quot; data-start=&quot;1215&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1227&quot; data-start=&quot;1215&quot;&gt;iPhone 16&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1234&quot; data-start=&quot;1227&quot;&gt;전자제품&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1247&quot; data-start=&quot;1234&quot;&gt;1,350,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1268&quot; data-start=&quot;1248&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1253&quot; data-start=&quot;1248&quot;&gt;셔츠&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1258&quot; data-start=&quot;1253&quot;&gt;의류&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1268&quot; data-start=&quot;1258&quot;&gt;50,000&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1289&quot; data-start=&quot;1269&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1274&quot; data-start=&quot;1269&quot;&gt;바지&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1279&quot; data-start=&quot;1274&quot;&gt;의류&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1289&quot; data-start=&quot;1279&quot;&gt;70,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1312&quot; data-start=&quot;1291&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1312&quot; data-start=&quot;1291&quot; data-ke-size=&quot;size16&quot;&gt;카테고리별 상품 개수를 구하고 싶다면:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;SELECT category, COUNT(*)
FROM products
GROUP BY category;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1385&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-end=&quot;1388&quot; data-start=&quot;1385&quot; data-ke-size=&quot;size16&quot;&gt;결과:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;categoryCOUNT(*)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-end=&quot;1448&quot; data-start=&quot;1390&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody data-end=&quot;1448&quot; data-start=&quot;1425&quot;&gt;
&lt;tr data-end=&quot;1437&quot; data-start=&quot;1425&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1432&quot; data-start=&quot;1425&quot;&gt;전자제품&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1437&quot; data-start=&quot;1432&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr data-end=&quot;1448&quot; data-start=&quot;1438&quot;&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1443&quot; data-start=&quot;1438&quot;&gt;의류&lt;/td&gt;
&lt;td data-col-size=&quot;sm&quot; data-end=&quot;1448&quot; data-start=&quot;1443&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-end=&quot;1508&quot; data-start=&quot;1450&quot; data-ke-size=&quot;size16&quot;&gt;GROUP BY category가 &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;style6&quot; /&gt;
&lt;h2 data-end=&quot;1533&quot; data-start=&quot;1515&quot; data-section-id=&quot;1uu3h4c&quot; data-ke-size=&quot;size26&quot;&gt;집계 함수 + GROUP BY&lt;/h2&gt;
&lt;p data-end=&quot;1572&quot; data-start=&quot;1535&quot; data-ke-size=&quot;size16&quot;&gt;GROUP BY는 집계 함수와 함께 사용하면 정말 많이 쓰인다.&lt;/p&gt;
&lt;h3 data-end=&quot;1589&quot; data-start=&quot;1574&quot; data-section-id=&quot;5koy2e&quot; data-ke-size=&quot;size23&quot;&gt;카테고리별 평균 가격&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT category, AVG(price)
FROM products
GROUP BY category;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1679&quot; data-start=&quot;1664&quot; data-section-id=&quot;15g6x7n&quot; data-ke-size=&quot;size23&quot;&gt;카테고리별 최고 가격&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT category, MAX(price)
FROM products
GROUP BY category;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1769&quot; data-start=&quot;1754&quot; data-section-id=&quot;rid9z7&quot; data-ke-size=&quot;size23&quot;&gt;카테고리별 최저 가격&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT category, MIN(price)
FROM products
GROUP BY category;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-end=&quot;1859&quot; data-start=&quot;1844&quot; data-section-id=&quot;6r34vv&quot; data-ke-size=&quot;size23&quot;&gt;카테고리별 상품 개수&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div id=&quot;code-block-viewer&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;SELECT category, COUNT(*)
FROM products
GROUP BY category;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&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;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>SQL</category>
      <category>SQL</category>
      <category>개발자</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/54</guid>
      <comments>https://chungmani.tistory.com/54#entry54comment</comments>
      <pubDate>Tue, 28 Jul 2026 21:50:32 +0900</pubDate>
    </item>
    <item>
      <title>Spring MVC의 ArgumentResolver 등록하고 사용하기</title>
      <link>https://chungmani.tistory.com/53</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. ArgumentResolver란?&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Argument = 메서드의 매개변수&lt;/li&gt;
&lt;li&gt;Resolver = 해결해주는 객체&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArgumentResolver는 Spring MVC가 컨트롤러 메서드를 호출할 때 필요한 매개변수(Argument)를 어떻게 만들어서 넣어줄지 결정하는 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@GetMapping(&quot;/users/{userId}&quot;)
public UserResponse getUser(@PathVariable Long userId) {
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring MVC는 요청 URL에 있는 userId 값을 가져와서 메서드의 Long userId 파라미터에 넣어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@PostMapping(&quot;/users&quot;)
public void createUser(@RequestBody SignupRequest request) {
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 Spring MVC는 HTTP 요청 Body의 JSON 데이터를 읽어서 SignupRequest 객체로 변환한 뒤 컨트롤러 메서드에 전달한다.&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;을 추가하고 싶을 때 사용할 수 있는 것이 ArgumentResolver이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 왜 ArgumentResolver가 필요한가?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JWT 인증을 구현하다 보면 로그인한 사용자의 정보를 컨트롤러에서 사용해야 하는 경우가 많다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 사용자가 비밀번호를 변경한다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 로그인한 사용자의 ID가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 생각하면 다음과 같은 정보가 필요할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;HTTP 요청
    &amp;darr;
Authorization Header
    &amp;darr;
JWT 토큰
    &amp;darr;
JWT 검증
    &amp;darr;
userId
email
userRole
    &amp;darr;
컨트롤러에서 사용
&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;그런데 모든 컨트롤러에서 JWT를 직접 파싱한다면 코드가 매우 복잡해질 수 있다.&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;String token = ...
Long userId = ...
String email = ...
UserRole role = ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 인증 관련 로직이 여러 컨트롤러에 반복될 가능성이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 인증 과정에서 얻은 사용자 정보를 하나의 객체로 만들어 컨트롤러의 파라미터로 바로 전달할 수 있도록 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 역할을 ArgumentResolver가 담당하도록 구현할 수 있다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3.&amp;nbsp; AuthUserArgumentResolver&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 프로젝트에서는 다음과 같은 ArgumentResolver를 사용했다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver {
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 중요한 부분은 HandlerMethodArgumentResolver 인터페이스를 구현했다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring MVC는 이 인터페이스를 구현한 객체를 ArgumentResolver로 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 직접 구현해야 하는 핵심 메서드는 두 가지다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@Override
public boolean supportsParameter(MethodParameter parameter) {
    ...
}

@Override
public Object resolveArgument(
        @Nullable MethodParameter parameter,
        @Nullable ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest,
        @Nullable WebDataBinderFactory binderFactory
) {
    ...
}
&lt;/code&gt;&lt;/pre&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. supportsParameter()의 역할&lt;/h2&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Override
public boolean supportsParameter(MethodParameter parameter) {

    boolean hasAuthAnnotation =
            parameter.getParameterAnnotation(Auth.class) != null;

    boolean isAuthUserType =
            parameter.getParameterType().equals(AuthUser.class);

    if (hasAuthAnnotation != isAuthUserType) {
        throw new AuthException(
                &quot;@Auth와 AuthUser 타입은 함께 사용되어야 합니다.&quot;
        );
    }

    return hasAuthAnnotation;
}
&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;Spring MVC가 컨트롤러의 파라미터를 하나씩 확인할 때 supportsParameter()를 통해 판단한다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@PutMapping(&quot;/users&quot;)
public void changePassword(
        @Auth AuthUser authUser,
        @RequestBody UserChangePasswordRequest request
) {
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;@Auth AuthUser authUser
        &amp;darr;
AuthUserArgumentResolver에게 물어봄
        &amp;darr;
supportsParameter()
        &amp;darr;
&quot;이 파라미터 내가 처리할 수 있어!&quot;
        &amp;darr;
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;Spring MVC는 해당 ArgumentResolver의 resolveArgument()를 호출한다.&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;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@RequestBody UserChangePasswordRequest request
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AuthUserArgumentResolver가 처리할 대상이 아니다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. @Auth와 AuthUser를 함께 사용하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드에서는 다음 두 가지를 확인하고 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;boolean hasAuthAnnotation =
        parameter.getParameterAnnotation(Auth.class) != null;

boolean isAuthUserType =
        parameter.getParameterType().equals(AuthUser.class);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;@Auth
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어노테이션이 붙어 있는지 확인&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;AuthUser
&lt;/code&gt;&lt;/pre&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;반대로 이런 식으로 사용하면 잘못된 사용이다.&lt;/p&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;@Auth String userId
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;AuthUser authUser
&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;이런 경우도 우리가 만든 인증용 ArgumentResolver의 의도와 맞지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 다음 로직을 사용한다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;if (hasAuthAnnotation != isAuthUserType) {
    throw new AuthException(
            &quot;@Auth와 AuthUser 타입은 함께 사용되어야 합니다.&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;따라서 @Auth가 붙어 있고 AuthUser 타입인 경우에만 이 Resolver가 해당 파라미터를 처리하게 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. resolveArgument()의 역할&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 파라미터에 넣어줄 객체를 만드는 작업을 resolveArgument()에서 한다.&lt;/p&gt;
&lt;pre class=&quot;typescript&quot;&gt;&lt;code&gt;@Override
public Object resolveArgument(
        @Nullable MethodParameter parameter,
        @Nullable ModelAndViewContainer mavContainer,
        NativeWebRequest webRequest,
        @Nullable WebDataBinderFactory binderFactory
) {
    HttpServletRequest request =
            (HttpServletRequest) webRequest.getNativeRequest();

    Long userId =
            (Long) request.getAttribute(&quot;userId&quot;);

    String email =
            (String) request.getAttribute(&quot;email&quot;);

    UserRole userRole =
            UserRole.of(
                    (String) request.getAttribute(&quot;userRole&quot;)
            );

    return new AuthUser(
            userId,
            email,
            userRole
    );
}
&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;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. WebMvcConfigurer에 ArgumentResolver 등록하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;WebMvcConfig를 만들어서 Resolver를 등록할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot;&gt;&lt;code&gt;@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer {

    private final AuthUserArgumentResolver authUserArgumentResolver;

    @Override
    public void addArgumentResolvers(
            List&amp;lt;HandlerMethodArgumentResolver&amp;gt; resolvers
    ) {
        resolvers.add(authUserArgumentResolver);
    }
}
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. Resolver를 Bean으로 등록하는 이유&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드에서는 다음과 같이 의존성 주입을 받고 있다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;private final AuthUserArgumentResolver authUserArgumentResolver;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러려면 AuthUserArgumentResolver가 Spring Bean으로 등록되어 있어야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;@Component
public class AuthUserArgumentResolver
        implements HandlerMethodArgumentResolver {
    ...
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 Spring이 해당 클래스를 Bean으로 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 WebMvcConfig에서 생성자 주입으로 받을 수 있다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;private final AuthUserArgumentResolver authUserArgumentResolver;
&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 class=&quot;dockerfile&quot;&gt;&lt;code&gt;resolvers.add(authUserArgumentResolver);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;를 통해 Spring MVC에 등록한다.&lt;/p&gt;</description>
      <category>TIL</category>
      <category>TiL</category>
      <category>개발자</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/53</guid>
      <comments>https://chungmani.tistory.com/53#entry53comment</comments>
      <pubDate>Mon, 27 Jul 2026 13:12:17 +0900</pubDate>
    </item>
    <item>
      <title>Java Enum 활용하기 - 계산기 과제로 이해하는 Enum</title>
      <link>https://chungmani.tistory.com/52</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;계산기 과제를 복습하면서 사칙연산 기호를 관리하기 위해 Enum을 사용해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 단순히 +, -, *, /를 switch문에서 직접 비교했지만, 도전 과제에서는 Enum을 활용하여 연산자 정보를 하나의 타입으로 관리해보았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 글에서는 계산기 과제에서 사용한 코드를 기준으로 Java의 Enum을 어떻게 활용할 수 있는지 정리해보자.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. Enum이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enum은 &lt;b&gt;서로 관련된 상수들을 하나의 타입으로 묶어서 관리할 수 있도록 해주는 문법&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 값들은 프로그램이 실행되는 동안 갑자기 다른 연산자로 변경될 필요가 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 &lt;b&gt;정해진 값들을 하나의 그룹으로 관리하고 싶을 때 Enum을 사용할 수 있다.&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;계산기 과제에서는 OperatorType이라는 Enum을 만들었다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;public enum OperatorType {
    SUM('+'),
    SUB('-'),
    MUL('*'),
    DIV('/');

    private char op;

    private OperatorType(char op) {
        this.op = op;
    }

    public char getOp() {
        return op;
    }
}
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. Enum 상수에 인자값을 넣을 수 있다&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enum도 일반적인 클래스처럼 필드와 생성자를 가질 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음 코드에서:&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;SUM('+')
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;'+'는 SUM이라는 Enum 상수에 전달되는 값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Enum 내부의 생성자가 이 값을 받는다.&lt;/p&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;private OperatorType(char op) {
    this.op = op;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 다음과 같은 흐름이다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;SUM('+')
    &amp;darr;
생성자 호출
    &amp;darr;
OperatorType(char op)
    &amp;darr;
this.op = '+'
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 SUM이라는 Enum 상수는 내부적으로 +라는 연산 기호 정보를 가지고 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 값들도 동일하다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;SUM('+') &amp;rarr; '+'
SUB('-') &amp;rarr; '-'
MUL('*') &amp;rarr; '*'
DIV('/') &amp;rarr; '/'
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 연산자에 대한 정보를 Enum 안에서 함께 관리할 수 있다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. Enum의 필드 값을 가져오기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Enum 내부에 저장한 op 값을 가져오기 위해 Getter 메서드를 만들었다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public char getOp() {
    return op;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 SUM의 연산 기호를 가져오고 싶다면 다음과 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;OperatorType.SUM.getOp(); // '+'를 반환한다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Enum의 모든 값을 배열로 가져오기 - values()&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산기에서는 사용자가 입력한 연산 기호와 Enum에 저장된 연산 기호를 비교해야 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 사용한 것이 바로 values() 메서드이다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;OperatorType[] op = OperatorType.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;values()는 해당 Enum에 선언된 &lt;b&gt;모든 Enum 상수를 배열로 반환&lt;/b&gt;한다.&lt;/p&gt;
&lt;pre class=&quot;json&quot;&gt;&lt;code&gt;[SUM, SUB, MUL, DIV]
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 향상된 for문으로 Enum의 모든 값 확인하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 values()로 가져온 Enum 배열을 반복문으로 확인할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;OperatorType[] op = OperatorType.values();

for (OperatorType operatorType : op) {

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드는 배열의 값을 하나씩 꺼내서 operatorType에 넣는다.&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;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 사용자 입력값과 Enum의 값을 비교하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산기에서는 사용자가 연산 기호를 입력한다.&lt;/p&gt;
&lt;pre class=&quot;markdown&quot;&gt;&lt;code&gt;+
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 입력한 값은 char 타입의 cal 변수에 저장된다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;char cal = sc.nextLine().charAt(0);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 이 입력값이 어떤 연산자인지 Enum을 통해 찾아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해 values()로 모든 Enum 값을 가져오고 반복문을 사용했다.&lt;/p&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;OperatorType[] op = OperatorType.values();
OperatorType matchedOp = null;

for (OperatorType operatorType : op) {
    if (cal == operatorType.getOp()) {
        matchedOp = operatorType;
    }
}
&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 찾은 Enum을 switch문에서 활용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자를 찾은 후에는 matchedOp를 switch문의 조건으로 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;switch (matchedOp) {
    case SUM -&amp;gt; result = num1 + num2;

    case SUB -&amp;gt; result = num1 - num2;

    case MUL -&amp;gt; result = num1 * num2;

    case DIV -&amp;gt; {
        if (num2 == 0) {
            System.out.println(&quot;나눗셈 연산에서 분모는 0이 올 수 없습니다.&quot;);
            return 0;
        }

        result = num1 / num2;
    }
}
&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;p data-ke-size=&quot;size16&quot;&gt;대신 Enum의 상수 자체를 기준으로 분기한다.&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>enum</category>
      <category>Java</category>
      <category>TiL</category>
      <category>개발자</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/52</guid>
      <comments>https://chungmani.tistory.com/52#entry52comment</comments>
      <pubDate>Fri, 24 Jul 2026 21:56:15 +0900</pubDate>
    </item>
    <item>
      <title>싱글톤(Singleton) 패턴이란?</title>
      <link>https://chungmani.tistory.com/51</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 싱글톤이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤(Singleton)은 &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;일반적으로 객체를 생성하면 new를 사용할 때마다 새로운 인스턴스가 만들어진다.&lt;/p&gt;
&lt;pre class=&quot;vbnet&quot;&gt;&lt;code&gt;MyClass a = new MyClass();
MyClass b = new MyClass();
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 a와 b는 서로 다른 객체이다.&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;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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 싱글톤은 어디에 사용할까?&lt;/h2&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;대표적인 예시는 다음과 같다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;① 설정(Configuration) 객체&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램 전체에서 공통으로 사용하는 설정 정보를 관리하는 객체이다.&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;애플리케이션
 ├─ A 기능 ─┐
 ├─ B 기능 ─┼──&amp;gt; 하나의 설정 객체
 └─ C 기능 ─┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 기능마다 설정 객체를 새로 만들 필요가 없기 때문에 하나를 공유할 수 있다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;② 로깅(Logger)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 곳곳에서 로그를 기록할 때 사용하는 로거 객체도 하나를 공유해서 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;log.info(&quot;회원 가입 요청&quot;);
log.info(&quot;로그인 요청&quot;);
log.error(&quot;서버 오류&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 곳에서 로그를 기록하지만 로깅을 위해 객체를 계속 새로 생성할 필요는 없다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;③ Spring Bean&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 기본적으로 &lt;b&gt;Spring Container가 Bean을 Singleton Scope로 관리&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 다음과 같은 서비스가 있다고 하자.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;@Service
public class MemberService {
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring이 이 클래스를 Bean으로 등록하면 기본적으로 하나의 MemberService 객체를 생성하고 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 다른 객체에서 의존성 주입을 요청하면 Spring Container가 관리하고 있는 Bean을 주입해준다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
@Service
public class MemberController {

    private final MemberService memberService;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 MemberController가 MemberService를 직접 new해서 만드는 것이 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Container가 관리하고 있는 MemberService Bean을 주입해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;Spring Container
      │
      ▼
MemberService 객체 하나 생성
      │
      ├──&amp;gt; Controller에 주입
      ├──&amp;gt; 다른 Service에 주입
      └──&amp;gt; 다른 곳에서도 필요하면 같은 Bean 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 구조로 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 개발자가 직접 싱글톤 패턴을 구현하지 않아도 &lt;b&gt;Spring Container가 Bean의 생명주기와 객체 생성을 관리하면서 기본적으로 Singleton 방식으로 Bean을 관리&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 싱글톤의 장점&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;① 객체 생성 비용 절약&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체를 계속 새로 만들지 않고 하나를 공유하기 때문에 객체 생성에 필요한 비용을 줄일 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;② 메모리 절약&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;동일한 객체를 여러 개 생성하지 않기 때문에 불필요한 메모리 사용을 줄일 수 있다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;③ 공통 객체 관리&lt;/h4&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 싱글톤의 단점&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;싱글톤이라고 해서 무조건 좋은 것은 아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 객체를 여러 곳에서 공유하기 때문에 &lt;b&gt;객체의 상태(State)를 잘못 관리하면 문제가 발생할 수 있다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class Singleton {

    private String username;
}
&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 class=&quot;makefile&quot;&gt;&lt;code&gt;사용자 A
   &amp;darr;
username = &quot;userA&quot;

사용자 B
   &amp;darr;
username = &quot;userB&quot;

사용자 A의 정보가
userB로 바뀌어버릴 가능성
&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 싱글톤과 Spring의 관계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring을 공부하면서 싱글톤을 이해하는 것은 매우 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 Bean을 기본적으로 Singleton Scope로 관리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;MemberService service = new MemberService();
&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;이렇게 하면 new를 실행할 때마다 새로운 객체가 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 의존성을 주입받는다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
@Service
public class MemberController {

    private final MemberService memberService;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 Spring Container가 MemberService Bean을 관리하고, 필요한 곳에 해당 Bean을 주입해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring에서는 개발자가 직접 Singleton 클래스를 만들어 관리하기보다는 &lt;b&gt;Spring Container가 객체의 생성과 생명주기를 관리하도록 맡기는 것이 일반적이다.&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>Spring</category>
      <category>개발자</category>
      <category>싱글톤</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/51</guid>
      <comments>https://chungmani.tistory.com/51#entry51comment</comments>
      <pubDate>Thu, 23 Jul 2026 21:16:55 +0900</pubDate>
    </item>
    <item>
      <title>error: cannot find symbol  @Value(&amp;quot;${jwt.secret.key}&amp;quot;) 해결</title>
      <link>https://chungmani.tistory.com/50</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 문제 상황&lt;/h2&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;514&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BcYHd/dJMcabLSHon/LLjqaZ9VhKZsIYMnOkZ0Yk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BcYHd/dJMcabLSHon/LLjqaZ9VhKZsIYMnOkZ0Yk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BcYHd/dJMcabLSHon/LLjqaZ9VhKZsIYMnOkZ0Yk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBcYHd%2FdJMcabLSHon%2FLLjqaZ9VhKZsIYMnOkZ0Yk%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;100&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;514&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckZHTZ/dJMcah6npuj/TOI6QvXaqNYgHgek7tiPi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckZHTZ/dJMcah6npuj/TOI6QvXaqNYgHgek7tiPi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckZHTZ/dJMcah6npuj/TOI6QvXaqNYgHgek7tiPi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckZHTZ%2FdJMcah6npuj%2FTOI6QvXaqNYgHgek7tiPi0%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;358&quot; height=&quot;100&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;100&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;JWT를 구현하면서 application.yml에 저장된 JWT Secret Key를 가져오기 위해 @Value 어노테이션을 사용했다.&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 원인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 원인은 Lombok과 Spring 모두 @Value라는 이름의 어노테이션을 가지고 있는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 Lombok의 @Value 이노테이션을&amp;nbsp; import하고 있었음.&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;499&quot; data-origin-height=&quot;428&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4Wqjg/dJMcai48gT2/CNdiXZ5yopMqR5ynTsnfN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4Wqjg/dJMcai48gT2/CNdiXZ5yopMqR5ynTsnfN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4Wqjg/dJMcai48gT2/CNdiXZ5yopMqR5ynTsnfN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4Wqjg%2FdJMcai48gT2%2FCNdiXZ5yopMqR5ynTsnfN0%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;499&quot; height=&quot;428&quot; data-filename=&quot;오류원인.png&quot; data-origin-width=&quot;499&quot; data-origin-height=&quot;428&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 해결 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring Framework에서 제공하는 @Value를 import하도록 수정했다.&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;595&quot; data-origin-height=&quot;390&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WKtpH/dJMcafUZ2PP/jEaEqqn5ECbMG8RIKV9Tj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WKtpH/dJMcafUZ2PP/jEaEqqn5ECbMG8RIKV9Tj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WKtpH/dJMcafUZ2PP/jEaEqqn5ECbMG8RIKV9Tj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWKtpH%2FdJMcafUZ2PP%2FjEaEqqn5ECbMG8RIKV9Tj1%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;595&quot; height=&quot;390&quot; data-filename=&quot;오류해결.png&quot; data-origin-width=&quot;595&quot; data-origin-height=&quot;390&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. Spring의 @Value란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Spring의 @Value는 &lt;b&gt;application.properties 또는 application.yml 등에 설정된 값을 주입받을 때 사용하는 어노테이션&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 application.yml에 다음과 같이 작성했다고 하자.&lt;/p&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;jwt:
  secret:
    key: my-secret-key
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java 코드에서 다음과 같이 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Value(&quot;${jwt.secret.key}&quot;)
private String secretKeyString;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 Spring이 실행될 때 설정 파일의 값을 읽어서 다음 필드에 넣어준다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;secretKeyString = &quot;my-secret-key&quot;;
&lt;/code&gt;&lt;/pre&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. Lombok의 @Value란?&lt;/h2&gt;
&lt;pre class=&quot;actionscript&quot;&gt;&lt;code&gt;import lombok.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;Lombok의 @Value는 클래스를 &lt;b&gt;불변 객체(Immutable Object)&lt;/b&gt; 로 만들어주는 어노테이션이다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;@Value
public class User {
    String username;
    String password;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lombok이 컴파일 시점에 Getter, 생성자 등을 자동으로 만들어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 필드를 변경할 수 없도록 만들어 불변 객체를 쉽게 생성할 수 있도록 도와준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 Lombok의 @Value와 Spring의 @Value는 이름만 같을 뿐 목적이 완전히 다르다.&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;style6&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;span style=&quot;color: #000000; font-size: 1.62em; letter-spacing: -1px;&quot;&gt;6. JWT에서 Spring @Value를 사용하는 이유&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;JWT를 사용할 때 Secret Key는 중요한 설정값이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 JWT를 생성하고 검증할 때 동일한 Secret Key를 사용해야 한다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;@Value(&quot;${jwt.secret.key}&quot;)
private String secretKeyString;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 설정 파일에 Secret Key를 저장하고 Spring의 @Value로 가져오면 코드에 직접 Secret Key를 작성하지 않아도 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 @PostConstruct가 실행되면서 Secret Key를 JWT에서 사용할 수 있는 SecretKey 객체로 변환한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;@PostConstruct
public void init() {
    byte[] bytes = Decoders.BASE64.decode(secretKeyString);
    this.key = Keys.hmacShaKeyFor(bytes);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체적인 흐름은 다음과 같다.&lt;/p&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;application.yml
      &amp;darr;
jwt.secret.key 설정
      &amp;darr;
Spring의 @Value
      &amp;darr;
secretKeyString에 값 주입
      &amp;darr;
@PostConstruct 실행
      &amp;darr;
SecretKey 객체 생성
      &amp;darr;
JWT 생성 및 검증에 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>트러블슈팅</category>
      <category>Spring</category>
      <category>개발자</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/50</guid>
      <comments>https://chungmani.tistory.com/50#entry50comment</comments>
      <pubDate>Wed, 22 Jul 2026 21:12:15 +0900</pubDate>
    </item>
    <item>
      <title>[SQL] SELECT와 WHERE로 원하는 데이터 조회하기</title>
      <link>https://chungmani.tistory.com/49</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. SELECT와 FROM&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL에서 데이터를 조회할 때 가장 기본적인 형태&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;SELECT&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SELECT는 데이터베이스에서 &lt;b&gt;조회할 데이터를 선택하는 명령어&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;FROM&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FROM은 &lt;b&gt;어떤 테이블에서 데이터를 가져올 것인지 지정&lt;/b&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;*&lt;/h4&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;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;food_orders 테이블에 있는 &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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 필요한 컬럼만 조회하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 데이터를 조회하는 것이 아니라 필요한 컬럼만 가져올 수도 있음.&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT 컬럼1, 컬럼2
FROM 테이블;
&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;예를 들어 food_orders 테이블에서 음식점 이름과 주문 금액만 조회한다면 다음과 같이 작성할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT restaurant_name, price
FROM food_orders;
&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;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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 컬럼에 별명(Alias) 붙이기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회한 컬럼에 별명을 지정할 수도 있음.&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT 컬럼명 AS 별명
FROM 테이블;
&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;AS를 생략하고 별명만 작성하는 것도 가능&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT 컬럼명 별명
FROM 테이블;
&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;pre class=&quot;sql&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;SELECT restaurant_name AS &quot;음식점&quot;
FROM food_orders;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회 결과에서 restaurant_name 대신 음식점이라는 이름으로 표시할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;별명을 사용할 때 주의할 점&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한글이나 특수문자를 별명으로 사용할 경우에는 큰따옴표(&quot; &quot;)를 사용&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT restaurant_name AS &quot;음식점&quot;
FROM food_orders;
&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 class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT order_no AS ord_no
FROM food_orders;
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. WHERE로 원하는 데이터만 조회하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SELECT가 &lt;b&gt;무엇을 가져올지&lt;/b&gt; 선택하는 역할이라면, WHERE는 &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;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT *
FROM 테이블
WHERE 필터링 조건;
&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;주문 금액이 10,000원 이상인 데이터만 조회&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders
WHERE price &amp;gt;= 10000;
&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열을 조건으로 사용할 때는 작은따옴표(' ')를 사용&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders
WHERE restaurant_name = '치킨집';
&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;h2 data-ke-size=&quot;size26&quot;&gt;5. WHERE에서 사용하는 비교 연산자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건을 작성할 때 다양한 비교 연산자를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자의미&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;&lt;/td&gt;
&lt;td&gt;초과&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&lt;/td&gt;
&lt;td&gt;미만&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;=&lt;/td&gt;
&lt;td&gt;같다&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;=&lt;/td&gt;
&lt;td&gt;이상&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;=&lt;/td&gt;
&lt;td&gt;이하&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&amp;gt;&lt;/td&gt;
&lt;td&gt;같지 않다&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;-- 가격이 10,000원보다 큰 데이터
WHERE price &amp;gt; 10000

-- 가격이 10,000원 이하인 데이터
WHERE price &amp;lt;= 10000

-- 특정 값과 다른 데이터
WHERE price &amp;lt;&amp;gt; 10000
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. BETWEEN&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 범위에 해당하는 데이터를 조회할 때는 BETWEEN을 사용&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;WHERE 컬럼 BETWEEN 조건1 AND 조건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;가격이 10,000원 이상 20,000원 이하인 데이터를 조회&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders
WHERE price BETWEEN 10000 AND 20000;
&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. IN&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 특정 값 중 하나에 해당하는 데이터를 조회할 때는 IN을 사용&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;WHERE 컬럼 IN (조건1, 조건2, 조건3)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders
WHERE cuisine IN ('한식', '중식', '일식');
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 개의 값을 하나씩 OR로 연결하는 것보다 IN을 사용하면 조건을 더 간결하게 작성할 수 있다.&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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. LIKE&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열에서 특정 패턴을 가진 데이터를 찾을 때는 LIKE를 사용&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WHERE 컬럼 LIKE '패턴'
&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;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;특정 문자로 시작하는 데이터&lt;/h4&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WHERE 컬럼 LIKE '치킨%'
&lt;/code&gt;&lt;/pre&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;h4 data-ke-size=&quot;size20&quot;&gt;특정 문자가 포함된 데이터&lt;/h4&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WHERE 컬럼 LIKE '%치킨%'
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;치킨이라는 문자열이 포함된 모든 데이터를 찾는다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;특정 문자로 끝나는 데이터&lt;/h4&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;WHERE 컬럼 LIKE '%치킨'
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;치킨으로 끝나는 모든 데이터를 찾는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;LIKE는 문자열의 정확한 값이 아니라 &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;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9. 논리 연산자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 조건을 함께 사용하고 싶다면 논리 연산자를 사용할 수 있다.&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;AND&lt;/li&gt;
&lt;li&gt;OR&lt;/li&gt;
&lt;li&gt;NOT&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AND&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 조건을 &lt;b&gt;모두 만족&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;n1ql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders
WHERE price &amp;gt;= 10000
AND price &amp;lt;= 20000;
&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;OR&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 조건 중 &lt;b&gt;하나라도 만족&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders
WHERE cuisine = '한식'
OR cuisine = '중식';
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;NOT&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 조건을 &lt;b&gt;제외&lt;/b&gt;할 때 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;SELECT *
FROM food_orders
WHERE NOT cuisine = '한식';
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>SQL</category>
      <category>SQL</category>
      <author>chungmani</author>
      <guid isPermaLink="true">https://chungmani.tistory.com/49</guid>
      <comments>https://chungmani.tistory.com/49#entry49comment</comments>
      <pubDate>Tue, 21 Jul 2026 21:22:12 +0900</pubDate>
    </item>
  </channel>
</rss>