<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>기죽을수록 히죽거리자</title>
    <link>https://jollyn.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 20 Aug 2026 16:00:10 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>an2z</managingEditor>
    <image>
      <title>기죽을수록 히죽거리자</title>
      <url>https://tistory1.daumcdn.net/tistory/5171470/attach/32549eddcca640c0b5361a20723b7903</url>
      <link>https://jollyn.tistory.com</link>
    </image>
    <item>
      <title>[IntelliJ] 인텔리제이 세팅 가이드</title>
      <link>https://jollyn.tistory.com/349</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;추후 인텔리제이 설치 후 세팅할 내용을 정리해두고자 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 설정&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Usages/Author 표시 : Preference &amp;gt; Editor &amp;gt; Inlay Hints &amp;gt; Code vision &amp;gt; Usages/Code author&lt;/li&gt;
&lt;li&gt;Annotation 활성화 :&amp;nbsp;&lt;/li&gt;
&lt;li&gt;LiveTemplate 추가 : Preference &amp;gt; Editor &amp;gt; Live Templates &amp;gt; Java
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;pfs : private final static&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;플러그인 설치&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/23029-catppuccin-icons&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Catppuccin Icons&lt;/a&gt; : 개인적으로 색상이 덜 화려해서 눈이 편안한 아이콘 플러그인&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/7499-gittoolbox&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;GitTooolBox&lt;/a&gt; : 누가 작업한 커밋인지 알려주는 플러그인&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/23464-langcursor&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;LangCursor&lt;/a&gt; : 입력 상태(한/영)에 따라 커서 색상을 전환해주는 플러그인&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/17400-restfulhelper&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RestfulHelper&lt;/a&gt; : &lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;엔드포인트 URL 기반의 검색을 지원하는 플러그인 (단축키 : ctrl + \)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/8575-nyan-progress-bar&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Nyan Progress Bar&lt;/a&gt; : 로딩 상태를 귀여운 고양이로 보여주는 플러그인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/10080-rainbow-brackets&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rainbow Brackets&lt;/a&gt; : 괄호를 색깔로 구분해 가독성을 높혀주는 플러그인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #333333; text-align: start;&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/24007-camelcase&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CamelCase&lt;/a&gt; : 표기법(카멜/스네이크/파스칼/낙타) 전환을 쉽게 도와주는 플러그인 (단축키 : shift + alt + U)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/9792-key-promoter-x&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Key Promoer X&lt;/a&gt; : 단축키 표시 플러그인&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;&lt;a href=&quot;https://plugins.jetbrains.com/plugin/7475-tab-shifter&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Tab Shifter&lt;/a&gt; : 화면 분할을 쉽게 도와주는 플러그인 (Main menu &amp;gt; Window &amp;gt; Tab Shifter에서 확인)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Refernce&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://adg0609.tistory.com/20&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://adg0609.tistory.com/20&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mangkyu.tistory.com/270&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mangkyu.tistory.com/270&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/개발환경</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/349</guid>
      <comments>https://jollyn.tistory.com/349#entry349comment</comments>
      <pubDate>Sun, 29 Sep 2024 17:10:43 +0900</pubDate>
    </item>
    <item>
      <title>HTTP의 GET과 POST</title>
      <link>https://jollyn.tistory.com/346</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;클라이언트가 HTTP 프로토콜을 이용해 서버로 요청을 보내는 방법인 HTTP Method에는 크게 GET 방식과 POST 방식이 있다.&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;h2 data-ke-size=&quot;size26&quot;&gt;GET, POST&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;GET은 가져온다. POST는 수행한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET은 서버에서 데이터를&amp;nbsp;&lt;b&gt;조회&lt;/b&gt;하기 위해 사용하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST는 서버에 데이터를 &lt;b&gt;수정&lt;/b&gt;하거나 새로&amp;nbsp;&lt;b&gt;추가&lt;/b&gt;하기 위해 사용하는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘의 가장 큰 차이점은 &lt;b&gt;데이터를 전송하는 방식&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET과 POST 메서드 둘 다 데이터를 서버로 보내야 하는데, &lt;b&gt;GET&lt;/b&gt;은 &lt;b&gt;Header&lt;/b&gt;에 &lt;b&gt;POST&lt;/b&gt;는 &lt;b&gt;Body&lt;/b&gt;에 데이터를 포함시켜 전송한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GET&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET은 요청을 전송할 때 필요한 데이터를 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;b&gt;URL&lt;/b&gt;에 &lt;b&gt;쿼리 스트링&lt;/b&gt;을 통해 전송한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;쿼리 스트링이란 URL 주소 끝에 ? 뒤에 붙는 파리미터들을 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;ex) https://example.com/login?id=abc&amp;amp;pw=1234&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 URL에 포함하여 전송하기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;즐겨찾기, 북마크&lt;span&gt;&amp;nbsp;&lt;/span&gt;등에 추가해 간편하게 요청할 수 있으며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;캐시&lt;/b&gt;가 가능해&amp;nbsp;동일한 요청을 반복적으로 보내지 않아도 된다. 하지만 URL에 데이터가 그대로 노출되기 때문에 &lt;b&gt;보안에 취약&lt;/b&gt;하며, URL에 전송할 수 있는 데이터 길이에 제한이 있기 때문에 &lt;b&gt;데이터 길이 제한&lt;/b&gt;이 있다.(큰 용량의 데이터를 전송하기 어려움)&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;* &lt;u&gt;캐시(Chache) 더 알아보기&lt;/u&gt;&lt;br /&gt;GET을 통해 서버에 리소스를 요청할 때 웹 캐시가 요청을 가로채 서버로부터 리소스를 다시 다운로드 하는 대신에 리소스의 복사본을 반환한다. HTTP 헤더에서 cache-control 헤더를 통해 캐시 옵션을 지정할 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;POST&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면 POST는 &lt;b&gt;Body&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;데이터를 Body로 보내기 때문에 데이터 길이 제한이 없으며, 겉으로는 어떤 데이터가 전송되었는지 노출되지 않아 &lt;b&gt;기본적인 보안&lt;/b&gt;이 이뤄진다. 하지만 GET보다 복잡하며, 캐시를 이용하지 않기 때문에 동일한 요청에 대해 반복해야 한다.&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;이때 POST로 전송되는 데이터는 보안에 완벽히 안전하다고 할 수 있을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST로 전달되는 데이터도 URL에 노출만 안될 뿐 개발자 도구만 켜서 Network 탭에서 클릭해보면 Body 데이터를 쉽게 확인할 수 있기 때문이다. 따라서 POST로 전달할 때 많은 데이터들을&amp;nbsp;&lt;b&gt;암호화&lt;/b&gt;된 상태로 전송한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;GET, POST 차이점 정리&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 90.8141%; height: 91px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 26.7719%; height: 17px; text-align: center;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; height: 17px; text-align: center;&quot;&gt;GET&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; height: 17px; text-align: center;&quot;&gt;POST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 26.7719%; height: 17px; text-align: center;&quot;&gt;데이터 전달 방식&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; height: 17px; text-align: center;&quot;&gt;URL 쿼리 스트링&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; height: 17px; text-align: center;&quot;&gt;Body&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7719%; text-align: center;&quot;&gt;목적&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; text-align: center;&quot;&gt;리소스 요청&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; text-align: center;&quot;&gt;리소스 생성, 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7719%; text-align: center;&quot;&gt;속도&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; text-align: center;&quot;&gt;빠름&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; text-align: center;&quot;&gt;보다 느림&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 26.7719%; height: 19px; text-align: center;&quot;&gt;캐시&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; height: 19px; text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; height: 19px; text-align: center;&quot;&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.7719%; text-align: center;&quot;&gt;브라우저 기록&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; text-align: center;&quot;&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 26.7719%; height: 19px; text-align: center;&quot;&gt;데이터 길이 제한&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; height: 19px; text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; height: 19px; text-align: center;&quot;&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 26.7719%; height: 19px; text-align: center;&quot;&gt;멱등성&lt;/td&gt;
&lt;td style=&quot;width: 33.6273%; height: 19px; text-align: center;&quot;&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 38.1948%; height: 19px; text-align: center;&quot;&gt;X&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;p data-ke-size=&quot;size16&quot;&gt;여기서 멱등성(idempotent)이란 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;GET은 리소스를 조회한다는 점에서 여러 번 동일한 요청을 하더라도 서버의 데이터나 상태를 변경시키지 않아 응답이 동일하므로 멱등이다.&lt;/li&gt;
&lt;li&gt;POST는 리소스를 새로 생성하거나 수정할 때 사용하므로 서버에 변경이 생겨 멱등이 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GET과 POST는 여러 차이가 있기 때문에 사용하려는 목적에 맞게 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;GET 방식은 간단하고 캐시를 이용하여 빠르데 데이터를 조회하는 데 효과적이지만 보안에 취약하고 큰 용량의 데이터를 전송하기 어려운 단점이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: left;&quot;&gt;반면, POST 방식은 보안성이 높고 큰 용량의 데이터를 전송할 수 있으며, 서버의 상태를 변경하는 작업에 적합하지만 캐시를 이용하지 않고 더 무거운 처리가 필요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/346</guid>
      <comments>https://jollyn.tistory.com/346#entry346comment</comments>
      <pubDate>Mon, 19 Feb 2024 22:43:34 +0900</pubDate>
    </item>
    <item>
      <title>[Mac] 매직 마우스 감도 조절하기</title>
      <link>https://jollyn.tistory.com/341</link>
      <description>&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감도 설정방법은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;512&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uA4pD/btsEnbhOANn/kCmjSFQBS0ZmIbqOjZNIKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uA4pD/btsEnbhOANn/kCmjSFQBS0ZmIbqOjZNIKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uA4pD/btsEnbhOANn/kCmjSFQBS0ZmIbqOjZNIKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuA4pD%2FbtsEnbhOANn%2FkCmjSFQBS0ZmIbqOjZNIKk%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;962&quot; height=&quot;512&quot; data-origin-width=&quot;962&quot; data-origin-height=&quot;512&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 최대 감도가 너무 낮다면 터미널로 더 높은 감도를 지정해줄 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2532&quot; data-origin-height=&quot;1582&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vo4NY/btsEoKcWK3p/Lzdk9srRjLWyj3kg07xrRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vo4NY/btsEoKcWK3p/Lzdk9srRjLWyj3kg07xrRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vo4NY/btsEoKcWK3p/Lzdk9srRjLWyj3kg07xrRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVo4NY%2FbtsEoKcWK3p%2FLzdk9srRjLWyj3kg07xrRk%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;2532&quot; height=&quot;1582&quot; data-origin-width=&quot;2532&quot; data-origin-height=&quot;1582&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;Lanchpad에서 터미널을 찾거나, commad+space로 '터미널'이라 검색해 터미널에 접속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접속 후 아래 명령어를 통해 감도 설정을 해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1707106919111&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;defaults write -g com.apple.mouse.scaling 5&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막 5라는 숫자가 마우스 감도를 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원하는 만큼 조절 후 재부팅하면 설정해준 감도가 적용된다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 마우스 감도를 빠르게 쓰는 편이라 13~15정도를 설정해두었다. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Etc</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/341</guid>
      <comments>https://jollyn.tistory.com/341#entry341comment</comments>
      <pubDate>Mon, 5 Feb 2024 13:29:49 +0900</pubDate>
    </item>
    <item>
      <title>몽고디비 왜 트랜잭션 안먹어? : 리플리카셋 (with docker-compose)</title>
      <link>https://jollyn.tistory.com/340</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 트랜잭션이 안되지?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몽고디비를 처음 써보면서 평소처럼 아무 생각없이 @Transaction을 사용했다.&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;테스트 환경을 격리하기 위해 별다른 작업없이 @Transaction 애노테이션을 붙혀줬는데, 다음과 같은 에러가 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1706636450502&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java.lang.IllegalStateException: Failed to retrieve PlatformTransactionManager for @Transactional test:&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;에러 메세지를 읽어보면 @Transaction 테스트를 위한 트랜잭션 매니저를 찾을 수 없는 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 트랜잭션을 처리하기 위한 트랜잭션 매니저를 자동으로 등록해주는 걸로 아는데, 왜 찾을 수 없다고 하는걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몽고디비는 트랜잭션이 필수가 아니라 트랜잭션 매니저를 등록하지 않는다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 별도로 트랜잭션 매니저를 활성화 시켜줘야 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  config/MongoConfig.java&lt;/blockquote&gt;
&lt;pre id=&quot;code_1706697553828&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class MongoConfig {

    @Bean
    public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
        return new MongoTransactionManager(dbFactory);
    }
}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 API 테스트를 하면 다른 에러가 또 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1706709586523&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;com.mongodb.MongoQueryException: Command failed with error 20 (IllegalOperation): 'Transaction numbers are only allowed on a replica set member or mongos' on server localhost:27017. 
The full response is {&quot;ok&quot;: 0.0, &quot;errmsg&quot;: &quot;Transaction numbers are only allowed on a replica set member or mongos&quot;, &quot;code&quot;: 20, &quot;codeName&quot;: &quot;IllegalOperation&quot;}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;몽고디비는 리플리카셋 구성을 해줘야 트랜잭션을 사용할 수 있다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플리카셋? 도대체 그게 뭐야! 몽고디비 쓰기 쉽지 않다.....&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 나는 해내야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플리카셋이 무엇이고 몽고디비는 왜 이걸 해야하는건지 부터 알아봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Replica Set이 뭐야?&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플리카 셋을 구축하는 이유는 다음과 같이 정리할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 안전하게 보존하기 위해서&lt;/li&gt;
&lt;li&gt;24시간 접근 가능한 데이터의 상태를 유지하기 위해서&lt;/li&gt;
&lt;li&gt;Transaction 처리를 위해서 (테스트 환경이나 개발 환경에서는 Standalone mongod 인스턴스를 Replica Set으로 변환하여 사용할 수 있지만, 프로덕션 환경에서는 Replica Set 구축이 필수적이다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플리카 셋은 보통 3개의 서버로 이뤄진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Primary Node(마스터 서버) : 메인 데이터베이스 서버&lt;/li&gt;
&lt;li&gt;Secondary Node(슬레이브 서버) : 서브 형태의 서버, 마스터 서버가 죽으면 마스터 서버를 대신함&lt;/li&gt;
&lt;li&gt;Arbiter Node(아비터 서버) : 감시용 서버, 문제가 생각 서버를 대신해 동작할 다른 서버를 시정하는 등의 역할&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;도커로 MongoDB 리플리카셋 구축하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 docker를 사용해 몽고디비를 구동하고 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;따라서 docker-compose 파일로 리플리카셋 구축하는 방법을 알아보도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;docker-compose를 구성하기 전 리플리카셋 내부 인증을 위한 키 파일을 생성해줘야 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1714640533586&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;openssl rand -base64 756 &amp;gt; &amp;lt;path-to-keyfile&amp;gt;
chmod 400 &amp;lt;path-to-keyfile&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 몽고디비 관련 파일을 한 곳에서 관리할 수 있도록 /mongo 하위로 경로를 지정해주었다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  docker/mongo/mongdb.key&lt;/blockquote&gt;
&lt;pre id=&quot;code_1707110179753&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;openssl rand -base64 756 &amp;gt; mongodb.key
chmod 400 mongodb.key&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런 다음, docker-compose 파일로 3개의 몽고디비 컨테이너를 생성한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  docker/dokcer-compose.yml&lt;/blockquote&gt;
&lt;pre id=&quot;code_1706847650934&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3.9&quot;

services:
  mongo1:
    image: mongo
    container_name: mongo1 #컨테니어 이름
    restart: always #컨테이너가 종료될때 항상 재시작
    ports: #호스트 포트(왼쪽)와 컨테이너 내부 포트(오른쪽)를 매핑
      - 27017:27017
    environment: #컨테이너 내부에서 실행되는 애플리케이션에 환경을 전달
      - MONGO_INITDB_ROOT_USERNAME={username}
      - MONGO_INITDB_ROOT_PASSWORD={password}
    command: mongod --replSet rs --keyFile /etc/mongodb.key --bind_ip_all #컨테이너가 시작될 때 실행할 명령
    networks: #서비스가 사용할 컨테이너 네트워크 지정(여러개의 서비스를 하나의 네트워크로 연결시 서비스간 통신 가능)
      - mongoNet
    volumes:
      - ./mongo/data/data1:/data/db
      - ./mongo/mongodb.key:/etc/mongodb.key
      - ./mongo/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js #초기 데이터를 위한 init script
  mongo2:
    image: mongo
    container_name: mongo2
    restart: always
    ports:
      - 27018:27017
    networks:
      - mongoNet
    environment:
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=1234
    command: mongod --replSet rs --keyFile /etc/mongodb.key --bind_ip_all
    volumes:
      - ./mongo/data/data2:/data/db
      - ./mongo/mongodb.key:/etc/mongodb.key
  mongo3:
    image: mongo
    container_name: mongo3
    restart: always
    ports:
      - 27019:27017
    networks:
      - mongoNet
    environment:
      - MONGO_INITDB_ROOT_USERNAME=root
      - MONGO_INITDB_ROOT_PASSWORD=1234
    command: mongod --replSet rs --keyFile /etc/mongodb.key --bind_ip_all
    volumes:
      - ./mongo/data/data3:/data/db
      - ./mongo/mongodb.key:/etc/mongodb.key

networks:
  mongoNet:
    name: mongoNet&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;command
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;--replSet rs : 리플리카셋 이름 지정, 필자는 rs로 했지만 마음대로 변경 가능하다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;완성된 디렉토리 구성은 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1706847839767&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker
  ㄴ mongo
     ㄴ data
        ㄴ data1
        ㄴ data2
        ㄴ data3
     ㄴ mongodb.key
     ㄴ mongo-init.js
  ㄴ docker-compose.yml&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;3개의 몽고디비 컨테이너를 구동한 뒤 Primary Node로 사용할 컨테이너에 접속한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 mongo1을  Primary Node로 두고 리플리카셋 설정을 진행했다.&lt;/p&gt;
&lt;pre id=&quot;code_1707109615704&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it mongo1 mongosh -u {username} -p {password}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1706847157534&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rs.initiate({
    _id: 'rs',
    members: [
        { _id: 0, host: 'mongo1:27017', priority: 2 },
        { _id: 1, host: 'mongo2:27017', priority: 0.5 },
        { _id: 2, host: 'mongo3:27017', priority: 0.5 }
    ]
});&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;_id: 'rs' : docker-compose에서 --replSet 뒤에 지정해준 리플리카셋 이름이다.&lt;/li&gt;
&lt;li&gt;priority : priority가 높은 순서대로 Primary Node가 된다. 이때 주의할 점은 0으로 설정할 경우 해당 멤버는 Arbiter Node가 되어, 투표권만 갖고 데이터 복제를 진행하지 않는다. 만약 Arbiter Node를 의도적으로 사용하는 것이 아니라면 priority 값은 0보다 큰 값으로 설정해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1707116408387&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rs.status()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;rs.status()로 리플리카셋 상태를 확인할 수 있다.&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;제대로 설정했다면 mongo1은 PRIMARY로 mongo2,3은 SECONDARY로 설정된 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;840&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuPnY2/btsEjEK7Tmw/qakR2KxngDpsd1uqDBzbBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuPnY2/btsEjEK7Tmw/qakR2KxngDpsd1uqDBzbBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuPnY2/btsEjEK7Tmw/qakR2KxngDpsd1uqDBzbBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuPnY2%2FbtsEjEK7Tmw%2FqakR2KxngDpsd1uqDBzbBK%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;1854&quot; height=&quot;840&quot; data-origin-width=&quot;1854&quot; data-origin-height=&quot;840&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;h2 data-ke-size=&quot;size26&quot;&gt;쉘 스크립트로 리플리카셋 구성까지 한번에 처리하기&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  docker/run-mongo.sh&lt;/blockquote&gt;
&lt;pre id=&quot;code_1714640942588&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

# mongodb.key 파일이 없는 경우에만 생성
if [ ! -f &quot;./mongo/mongodb.key&quot; ]; then
    echo &quot;create keyfile&quot;
    openssl rand -base64 756 &amp;gt; ./mongo/mongodb.key
    chmod 400 ./mongo/mongodb.key
fi

docker-compose up -d

sleep 10

echo &quot;init replicaset&quot;

docker exec mongo1 /scripts/rs-init.sh&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  docker/mongo/rs-init.sh&lt;/blockquote&gt;
&lt;pre id=&quot;code_1714641008747&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#!/bin/bash

mongosh -u &quot;root&quot; -p &quot;1234&quot;&amp;lt;&amp;lt;EOF

var config = {
      _id: 'rs',
      members: [
          { _id: 0, host: 'mongo1:27017', priority: 2 },
          { _id: 1, host: 'mongo2:27017', priority: 0.5 },
          { _id: 2, host: 'mongo3:27017', priority: 0.5 }
      ]
}
rs.initiate(config);
rs.status();

EOF&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;h2 data-ke-size=&quot;size26&quot;&gt;고된 삽질 ... ⛏️&lt;/h2&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;여러 문서들을 정말 많이 찾아보며 도커 컴포즈 파일을 작성했는데 mongo1, mongo2, mongo3 컨테이너가 도통 돌아가지가 않았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 안되는건줄도 모르겠고, 도커 컴포즈 파일을 잘못 작성했구나 싶어 그에 관련된 것만 계속해서 찾아보며 쩔쩔맸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러다 문득 도커 로그를 차근차근 살펴보게 되었는데..... 역시 로그에 실마리가 있었다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(계속 가장 마지막 에러 로그만 확인한 죄지...)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수많은 로그 에러 중 실마리를 찾은 로그는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1706861498368&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{&quot;t&quot;:{&quot;$date&quot;:&quot;2024-02-02T03:30:44.253+00:00&quot;},&quot;s&quot;:&quot;I&quot;, &quot;c&quot;:&quot;ACCESS&quot;, &quot;id&quot;:20254, &quot;ctx&quot;:&quot;main&quot;,&quot;msg&quot;:&quot;Read security file failed&quot;,&quot;attr&quot;:{&quot;error&quot;:{&quot;code&quot;:30,&quot;codeName&quot;:&quot;InvalidPath&quot;,&quot;errmsg&quot;:&quot;permissions on /etc/mongodb.key are too open&quot;}}}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리플리카셋 구성을 위해 이전에 키 파일을 만들어 준 것이 기억날거다.&lt;/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;나는 계속 이 키를 도커로 연결하는 volumns 경로가 잘못된 것 같다는 생각으로 docker-compose 파일만 계속 수정했었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, 에러 메세지를 보면 알 수 있 듯 키 파일의 권한 부여 문제임을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 에러를 눈치 챈 후, 아...설마..... 하며 gpt한테 물어봤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;1002&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/srUns/btsEqXXGZER/hLPm6r3a0sgW26gS0MLmVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/srUns/btsEqXXGZER/hLPm6r3a0sgW26gS0MLmVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/srUns/btsEqXXGZER/hLPm6r3a0sgW26gS0MLmVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsrUns%2FbtsEqXXGZER%2FhLPm6r3a0sgW26gS0MLmVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;495&quot; data-origin-width=&quot;1214&quot; data-origin-height=&quot;1002&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;에러 해결을 위해 mongodb.key 파일을 삭제하고 다시 만들고를 반복하다보니 그 과정에서 권한 설정을 빼먹어 일어난 문제였다.&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;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.baeldung.com/spring-data-mongodb-transactions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Baeldung] Spring Data MongoDB Transactions&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-data/mongodb/reference/mongodb/client-session-transactions.html#mongo.transactions&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[공식문서] Spring Data MongoDB Transactions&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://monny.tistory.com/249&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring MongoDB Transaction Support&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=g9oGml_wnKg&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[youtube] 몽고디비 리플리카 셋업부터 테스트까지&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://seoko.me/post/3&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MongoDB Replica Set 환경 구축하기 (Feat.Docker)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://devs0n.tistory.com/45&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;MongoDB Single node replica set 설정&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@juhwanheo/Spring-Boot-MongoDB-Transaction&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring Boot에서 MongoDB Transaction 사용하기&lt;/a&gt;&lt;/p&gt;</description>
      <category>  Computer Science/데이터베이스</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/340</guid>
      <comments>https://jollyn.tistory.com/340#entry340comment</comments>
      <pubDate>Wed, 31 Jan 2024 02:42:57 +0900</pubDate>
    </item>
    <item>
      <title>트리(Tree)</title>
      <link>https://jollyn.tistory.com/333</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트리&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트리(Tree)란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리는 &lt;b&gt;부모노드&lt;/b&gt;와 &lt;b&gt;자식노드&lt;/b&gt;로 이루어진 &lt;b&gt;계층적인 구조&lt;/b&gt;를가지며, &lt;b&gt;무방향 그래프&lt;/b&gt;의 일종이자 &lt;b&gt;사이클이 없는 자료구조&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리는 정점(Vertex)과 간선(Edge)으로 이루어진 그래프의 일종이다. (그래프 &amp;gt; 트리)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트리의 용어&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;488&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdp2XR/btsDfXRC2YD/dqiF2Xxuc5BMxuK7iZuhuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdp2XR/btsDfXRC2YD/dqiF2Xxuc5BMxuK7iZuhuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdp2XR/btsDfXRC2YD/dqiF2Xxuc5BMxuK7iZuhuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcdp2XR%2FbtsDfXRC2YD%2FdqiF2Xxuc5BMxuK7iZuhuK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;274&quot; data-origin-width=&quot;1068&quot; data-origin-height=&quot;488&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;노드(node)&lt;/b&gt; : 트리를 구성하는 정점. ex) a,b,c,d,e,f,g&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간선(edge,link)&lt;/b&gt; : 각 노드간 연결하는 선&lt;/li&gt;
&lt;li&gt;&lt;b&gt;루트 노드(root node)&lt;/b&gt; : 트리의 최상위 노드. 트리는 하나의 루트 노드만을 가진다. ex) a&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리프 노드(leaf node)&lt;/b&gt; : 트리의 최하위 노드. ex) d,e,f,g&lt;/li&gt;
&lt;li&gt;&lt;b&gt;내부 노드(internal node)&lt;/b&gt; : 최소 1개 이상의 하위 노드를 갖는 노드. ex) a,b,c&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부모 노드(parent node)&lt;/b&gt; : 하위 트리를 가지는 노드. ex) b,c의 부모 노드는 a, d,e의 부모 노드는 b, f,g의 부모 노드는 c이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;자식 노드(child node)&lt;/b&gt; : 상위 트리를 가진 노드. ex) a의 자식 노드는 b,c, b의 자식 노드는 d,fe, c의 자식 노드는 f,g이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;형제 노드(sibling node)&lt;/b&gt; : 같은 부모를 가지는 노드. ex) d-e, f-g, b-c는 형제노드이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;조상 노드(ancestor node)&lt;/b&gt; : 특정 노드의 모든 부모 노드. ex) f의 조상 노드는 c,a이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서브 트리(sub tree)&lt;/b&gt; : 트리 내의 하위 집합. 하나의 트리는 여러 개의 서브 트리로 구성될 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;높이(height)&lt;/b&gt; : 루트 노드로부터 리프 노드까지의 거리 중 가장 긴 거리. ex) 위 트리의 높이는 2이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;깊이(레벨)&lt;/b&gt; : 루트 노드에서 특정 노드까지 최단거리로 갔을 때의 거리. 각각의 노드마다 깊이가 다르다. ex) b노드의 깊이는 1, e노드의 깊이는 2이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;크기(size)&lt;/b&gt; : 트리의 모든 노드의 개수. ex) 위 트리의 크기는 7이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;차수(degree)&lt;/b&gt; : 노드의 하위 트리 개수. 즉, 연결된 자식 노드의 수를 말한다. ex) c의 차수는 2이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트리의 특징&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1) 부모, 자식 계층 구조를 가진다.&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;/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;2) V(Vertex) - 1 = E(Edge)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;노드가 n개인 트리는 항상 n-1개의 간선을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 그림을 보면 7개의 노드가 존재하며, 간선의 수는 7 - 1 = 6개인 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3) 임의 두 노드 사이의 경로는 유일무이하게 존재한다.&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;&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;&lt;b&gt;이진 트리&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이진 트리(Binary Tree)란?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 트리란 각 노드의 &lt;b&gt;자식 노드 수가 2개 이하&lt;/b&gt;로 구성되어 있는 트리를 의미한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;379&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qKPfP/btsC6S5p99w/kjyhktw6tsuIkdjj5o2Fm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qKPfP/btsC6S5p99w/kjyhktw6tsuIkdjj5o2Fm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qKPfP/btsC6S5p99w/kjyhktw6tsuIkdjj5o2Fm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqKPfP%2FbtsC6S5p99w%2Fkjyhktw6tsuIkdjj5o2Fm0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;251&quot; data-origin-width=&quot;1055&quot; data-origin-height=&quot;379&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이진 트리의 종류&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;278&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rJE47/btsDdFp6NiH/bL1l07LNLOnBGPEkwdJl60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rJE47/btsDdFp6NiH/bL1l07LNLOnBGPEkwdJl60/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rJE47/btsDdFp6NiH/bL1l07LNLOnBGPEkwdJl60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrJE47%2FbtsDdFp6NiH%2FbL1l07LNLOnBGPEkwdJl60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;278&quot; data-origin-width=&quot;1010&quot; data-origin-height=&quot;278&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정이진 트리(full binary tree)&lt;/b&gt; : 자식 노드가 0 또는 2개인 이진 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;완전이진 트리(complete binary tree)&lt;/b&gt; : 왼쪽에서부터 채워져 있는 이진 트리, 마지막 레벨을 제외하고 모든 레벨이 완전히 채워져 있으며 마지막 레벨의 경우 왼쪽부터 채워진다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변질이진 트리(degenerate binary tree)&lt;/b&gt; : 자식 노드가 하나밖에 없는 이진 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포화이진 트리(perfect binary tree)&lt;/b&gt; : 모든 노드가 꽉 차 있는 이진 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;⭐️ 균형이진 트리(balanced binary tree)&lt;/b&gt; : 모든 노드의 &lt;b&gt;왼쪽 하위 트리와 오른쪽 하위 트리의 깊이 차이가 1 이하인 트리&lt;/b&gt;, map과 set을 구성하는 레드블랙트리는 균형이진트리 중 하나이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;이진 탐색 트리(Binary Search Tree)란?&lt;/b&gt;&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;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dqJmWc/btsDbdgTrwQ/KsHEO58NVlNM6nKIAArmFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqJmWc/btsDbdgTrwQ/KsHEO58NVlNM6nKIAArmFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqJmWc/btsDbdgTrwQ/KsHEO58NVlNM6nKIAArmFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqJmWc%2FbtsDbdgTrwQ%2FKsHEO58NVlNM6nKIAArmFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;242&quot; data-origin-width=&quot;1162&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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;예를 들어 2 노드를 찾으려고 한다면, 굳이 전체 탐색을 하지 않고 10 노드의 왼쪽 노드들만 탐색하면 되기 때문이다.&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;이진탐색 트리의 시간복잡도는 O(logn)이다. 정확히 말하자면 트리의 높이에 따라 영향을 받아 O(h)이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이진탐색 트리는 삽입 순서에 따라 선형적인 자료구조가 될 수 있으며, 그럴 경우 worst case로 성능에 영향을 미치고 시간 복잡도가 O(n)이 된다.&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;이를 개선하기 위해 균형 잡히게 만든 AVL 트리와 레드블랙 트리가 등장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Map이라는 자료구조는 시간복잡도가 O(logN)임을 보장받는데 그 이유는 균형 잡힌 트리인 레드블랙 트리를 기반으로 구현되어 있기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레드 블랙 트리에 대해서는 추후 공부 후 포스팅할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Referecne&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yoongrammer.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://yoongrammer.tistory.com/71&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/자료구조</category>
      <category>이진탐색트리</category>
      <category>이진트리</category>
      <category>트리</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/333</guid>
      <comments>https://jollyn.tistory.com/333#entry333comment</comments>
      <pubDate>Mon, 8 Jan 2024 21:24:33 +0900</pubDate>
    </item>
    <item>
      <title>[디자인패턴] MVC 패턴</title>
      <link>https://jollyn.tistory.com/321</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;이번 글에서는 소프트웨어 디자인 패턴 중 하나인&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;MVC 패턴에 대해 기록해보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MVC 패턴이란&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MVC는 Model-View-Controller의 약자로, 애플리케이션을 3가지 역할로 구분하는 디자인 패턴이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 역할을 분리하는 이유는 무엇일까? 화면과 데이터 처리를 분리해 코드 간의 종속성을 줄이고 구성 요소 간의 역할을 명확하게 함으로써 코드 분리가 쉽고 유지보수가 용이하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이해하기 쉽도록 실생활로 예를 들어보자면, 하나의 회사에서 마케팅 업무를 하는 직원, 디자인 업무를 하는 직원, 개발 업무를 하는 직원, 기획 업무를 하는 직원이 모두 한 공간에서 작업을 진행한다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 특정 디자인에 수정이 필요할 때, 그 복잡한 환경에서 해당 디자인 업무를 담당하는 직원들을 찾아 전달하는 것은 어려울 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 유지보수가 좋지 않은 환경인 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 업무 별로 부서를 나눠 체계화하면 담당 업무를 하는 직원을 찾는 것이 용이해 질 것이고, 이것이 MVC 패턴이 탄생한 이유라고 볼 수 있다.&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;&lt;b&gt;MVC의 각 컴포넌트의 역할&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Model(모델)&amp;nbsp;&lt;/b&gt;&lt;/h3&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;DB와 연동하여 데이터를 추출하거나 저장, 삭제, 변경 등의 작업을 수행한다. 특히 여러 개의 데이터 변경 작업을 하나의 작업으로 묶은 트랜잭션을 다루는 일도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Model은 다른 컴포넌트들에 대해 알지 못한다. 자기 자신이 무엇을 수행하는지만 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;View(뷰)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자에게 보여질 사용자 인터페이스를 담당하는 레이어로, Controller로 부터 받은 Model의 값을 가지고 출력할 화면을 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황과 도메인에 따라 동적으로 달라지는 값을 가져와야 하는 경우에만 Model에서 받아온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;View는 다른 컴포넌트들에 대해 알지 못한다. 자기 자신이 무엇을 수행하는지만 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Controller(컨트롤러)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Model과 View를 연결해주는 레이어로, 사용자 요청을 처리할 수 있는 Model과 View를 결정한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller는 클라이언트 요청을 받으면 해당 요청을 수행할 수 있는 Model을 호출한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 클라이언트가 보낸 데이터가 있으면, Model에 전달하기 쉽도록 데이터를 가공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Model이 업무 수행을 완료하면 그 결과를 가지고 화면을 생성하도록 View에 전달한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Controller는 다른 컴포넌트들에 대해 알고 있다. 자기 자신 외의 Model과 View가 무엇을 수행하는지 알고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdleV3/btsCOEeMP0i/eavTeUxjkff2FSHMD9Cys0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdleV3/btsCOEeMP0i/eavTeUxjkff2FSHMD9Cys0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdleV3/btsCOEeMP0i/eavTeUxjkff2FSHMD9Cys0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdleV3%2FbtsCOEeMP0i%2FeavTeUxjkff2FSHMD9Cys0%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;592&quot; height=&quot;366&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 요청을 보내면, Controller는 해당 요청을 수행할 수 있는 Model을 호출해 데이터를 가져오고 그 정보를 바탕으로 시각적인 표현을 담당하는 View를 제어해서 사용자에게 전달한다.&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;&lt;b&gt;MVC 규칙을 지키면서 코딩하는 방법&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모델은 컨트롤러나 뷰에 의존하면 안된다.&lt;/li&gt;
&lt;li&gt;뷰는 모델에만 의존해야 하고, 컨트롤러에는 의존하면 안된다.&lt;/li&gt;
&lt;li&gt;뷰가 모델로부터 데이터를 받을 때는 사용자마다 다르게 보여주어야 하는 데이터에 한해서만 받아야 한다.&lt;/li&gt;
&lt;li&gt;컨트롤러는 모델과 뷰에 의존해도 된다.&lt;/li&gt;
&lt;li&gt;뷰가 모델로부터 데이터를 받을 때는 반드시 컨트롤러를 통해 받아야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MVC 패턴의 한계점&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MVC 패턴의 한계점으로 이야기 되는 것들은 다음과 같다.&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;Model과 View의 의존성을 완전히 분리시킬 수 없다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;View는 Controller와 연결되어 화면을 구성하기 때문에 Controller는 여러 개의 View를 가질수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Model은 Controller를 통해서 View와 연결된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, Controller에 의해 하나의 View에 연결되는 Model도 여러개가 될 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 복잡한 구조의 애플리케이션일수록 하나의 Controller에 다수의 View와 Model이 복잡하게 연결되어 서로 간의 의존성이 커지는 상황이 발생할 수 있다.&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;컨트롤러의 비중이 높아져 부담이 커진다면 Massive-View-Controller 현상이 발생한다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Massice-View-Controller(대규모 MVC 애플리케이션) 현상은 MVC 패턴에서 컨트롤러의 역할이 과도하게 커지고 복잡해지는 상황ㅇ르 의미한다. 주로 대규모 애플리케이션에서 발생할 수 있으며, 하나의 Controller에도 수많은 View와 Model이 연결되어 다양한 side-effect를 불러오는 문제를 야기할 수 있다.&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;이러한 MVC 패턴의 문제를 해결하기 위한 대안으로 MVVM, MVP 등 다양한 패턴들이 등장했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2021-04-26-mvc/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://tecoble.techcourse.co.kr/post/2021-04-26-mvc/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@langoustine/%EC%97%AC%EA%B8%B0%EB%8F%84-MVC-%EC%A0%80%EA%B8%B0%EB%8F%84-MVC-MVC-%ED%8C%A8%ED%84%B4%EC%9D%B4-%EB%AD%90%EC%95%BC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기도 MVC, 저기도 MVC! MVC 패턴이 뭐야?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://binco.tistory.com/entry/Java-MVC%ED%8C%A8%ED%84%B4-%EB%B0%94%EB%A1%9C%EC%95%8C%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Java MVC 패턴 바로 알기&lt;/a&gt;&lt;/p&gt;</description>
      <category> ️ Programming/개발상식</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/321</guid>
      <comments>https://jollyn.tistory.com/321#entry321comment</comments>
      <pubDate>Fri, 3 Nov 2023 16:37:03 +0900</pubDate>
    </item>
    <item>
      <title>[Intellij] 자동 코드 접기 기능 해제하기</title>
      <link>https://jollyn.tistory.com/319</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;인텔리제이에서 클래스를 열었을 때 다음과 같이 자동으로 메서드를 한줄로 접어주는 기능이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맥을 사용하는 나는 매번 command + shift + plus 단축키를 사용해 펼쳐서 확인했는데, 이게 갑자기 너무너무 번거롭게 느껴졌다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;288&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cZazuN/btsy0gIK9p1/w7m0IrKbh80T7HHrGaKTRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cZazuN/btsy0gIK9p1/w7m0IrKbh80T7HHrGaKTRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cZazuN/btsy0gIK9p1/w7m0IrKbh80T7HHrGaKTRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcZazuN%2Fbtsy0gIK9p1%2Fw7m0IrKbh80T7HHrGaKTRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;144&quot; data-origin-width=&quot;802&quot; data-origin-height=&quot;288&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나처럼 자동 접기 기능이 오히려 방해가 된다면 아래 설정을 만져주자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Settings &amp;gt; Editor &amp;gt; General &amp;gt; Code Folding&lt;/li&gt;
&lt;li&gt;imports, one-line methods 체크 박스 해제&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2104&quot; data-origin-height=&quot;1340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/y8uRe/btsyVbupMnE/LVZEs5lcVc1NKgkyTXo3Dk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/y8uRe/btsyVbupMnE/LVZEs5lcVc1NKgkyTXo3Dk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/y8uRe/btsyVbupMnE/LVZEs5lcVc1NKgkyTXo3Dk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fy8uRe%2FbtsyVbupMnE%2FLVZEs5lcVc1NKgkyTXo3Dk%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;2104&quot; height=&quot;1340&quot; data-origin-width=&quot;2104&quot; data-origin-height=&quot;1340&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;</description>
      <category> ️ Programming/개발환경</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/319</guid>
      <comments>https://jollyn.tistory.com/319#entry319comment</comments>
      <pubDate>Mon, 23 Oct 2023 18:09:23 +0900</pubDate>
    </item>
    <item>
      <title>[Git] 명령어 취소하기 : git reflog &amp;amp; reset</title>
      <link>https://jollyn.tistory.com/309</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;git 명령어를 잘못쳐서 작업 내용이 다 날아가 멘붕이 온 경험이 한번쯤 있을 것이다. git은 우리의 실수를 예견하고... 친절하게 지난 명령어의 history를 기록하고 다시 되돌아갈 수 있도록 기능을 제공한다.&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;b&gt;이전 명령어 확인하기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702914882689&quot; class=&quot;bash&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;git reflog&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지난 git history를 확인하는 명령어이다.&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;b&gt;명령어를 치기 전 상태로 되돌아가기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1702914975988&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git reset --hard HEAD@{1}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 가장 마지막으로 한 명령어가 잘못되었다면, 돌아가야할 위치는 HEAD@{1} 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 지난 로그를 확인하고 돌아가야할 위치를 확인해 reset을 해주면, 명령어를 치기 전 상태로 다시 되돌아갈 수 있다.&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;앞으로 명령어를 잘못 쳤다면, 당황하지 말고 reflog와 reset을 사용해 해결해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/Git &amp;amp; Github</category>
      <category>git reflog</category>
      <category>git 명령어 취소</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/309</guid>
      <comments>https://jollyn.tistory.com/309#entry309comment</comments>
      <pubDate>Fri, 14 Jul 2023 16:11:35 +0900</pubDate>
    </item>
    <item>
      <title>재귀함수 (Recursive Function)</title>
      <link>https://jollyn.tistory.com/306</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;재귀함수&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;재귀함수는 &lt;b&gt;스택 프레임&lt;/b&gt;을 사용해 작동한다. 스택 프레임에 저장되는 정보는 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;매개변수 정보&lt;/li&gt;
&lt;li&gt;지역변수 정보&lt;/li&gt;
&lt;li&gt;복귀 주소&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 재귀함수가 어떻게 작동하는지 코드를 통해 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 일반적으로 재귀함수를 표현하는 패턴이다.&lt;/p&gt;
&lt;pre id=&quot;code_1692343022913&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class DFS {
    public static void dfs(int n) {
        if (//재귀 탈출 조건) {
            return;
        } else {
            dfs(//탈출을 위한 반복 조건);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시 코드이다.&lt;/p&gt;
&lt;pre id=&quot;code_1688644442159&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class DFS {
    public static void dfs(int n) {
        if (n == 0) {
            return;
        } else {
            dfs(n-1);
            System.out.print(n + &quot; &quot;); 
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1688644486860&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1 2 3&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;b&gt;스택은 항상 상단에 있는게 작동한다&lt;/b&gt;는 것을 기억하자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2170&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A7cnK/btsmJP9HF0G/gwvigbDbgNQJLrOmdEdSUk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A7cnK/btsmJP9HF0G/gwvigbDbgNQJLrOmdEdSUk/img.png&quot; data-alt=&quot;진행 순서 (왼-&amp;amp;gt;오)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A7cnK/btsmJP9HF0G/gwvigbDbgNQJLrOmdEdSUk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA7cnK%2FbtsmJP9HF0G%2FgwvigbDbgNQJLrOmdEdSUk%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;2170&quot; height=&quot;540&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2170&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;진행 순서 (왼-&amp;gt;오)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 말했듯이 스택은 제일 상단에 있는 것이 실행되기 때문에 D(0)이 실행중인 상태이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D(0)은 if문 조건에 부합하기 때문에 바로 return되고, 바로 9라인으로 가서 종료된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D(0)은 할일을 끝냈기 때문에 스택에서 pop 된다.&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;이후 스택은 가장 상단에 있는 D(1)로 복귀하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D(1)은 6라인까지 실행했기 때문에 7라인부터 시작해 print문을 통해 1이 출력된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러면 D(1)도 종료되면서 스택에서 pop 된다.&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;이런식으로 계속하여 가장 상단에 있는 D(2)로 복귀하고 7라인부터 시작해 2를 출력하고 종료 및 pop,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;D(3)으로 복귀하고 7라인부터 시작해 3을 출력하고 종료 및 pop 되기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1 &amp;rarr; 2 &amp;rarr; 3 순서로 결과가 출력되는 것이다.&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;h2 data-ke-size=&quot;size26&quot;&gt;활용 문제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;팩토리얼&lt;/h3&gt;
&lt;pre id=&quot;code_1688658866967&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Factorial {
    public int factorial(int n) {
        if (n == 1) {
            return 1;
        } else {
            return n * factorial(n - 1);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;피보나치 수열&lt;/h3&gt;
&lt;pre id=&quot;code_1688659023593&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Fibonacci {
    public static int fibo(int n) {
        if (n == 1 || n == 2) {
            return 1;
        } else {
            return fibo(n - 2) + fibo(n - 1);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span&gt;피보나치 수열의 기저는 n이 1 또는 2일 때 이며, 이 경우 재귀가 종료(return 1)된다.&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot;&gt;&lt;span&gt;1과 2가 아닌 n은 재귀함수를 통해 점점 1과 2를 향해 내려간다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;위 코드를 실제로 실행하면 한가지 문제가 발생하게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 fibo(5)를 호출한다고 했을 때&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc; color: #555555; text-align: start;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(5) &amp;rarr; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(3) + &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(4) 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(3) &amp;rarr; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(1) + &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(2) 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;fibo(1) &amp;rarr; 1 반환&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;fibo(2) &amp;rarr; 1 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(4) &amp;rarr; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(2) + &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(3) 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;fibo(2) &amp;rarr; 1 반환&amp;nbsp;&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(3) &amp;rarr; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(1) +&amp;nbsp; &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(2) 호출
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;fibo(1) &amp;rarr; 1 반환&lt;/li&gt;
&lt;li style=&quot;list-style-type: disc; color: #666666;&quot; data-ke-style=&quot;style1&quot;&gt;fibo(2) &amp;rarr; 1 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;즉, &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(3)은 2번, &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(2)는 3번, &lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;fibo&lt;/span&gt;(1)는 2번 호출된다. 이전에 구한 값임에도 계속 뻗어나가며 또 값을 구하는 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #555555; text-align: start;&quot;&gt;이런 경우 fibo&lt;/span&gt;(100) 같은 경우 &lt;b&gt;시간이 굉장히 오래&lt;/b&gt; 걸리게 된다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;구한 값을 어딘가에 저장해놓고, 이전에 구해놓은 값이면 더이상 재귀를 뻗지 않고 값을 가져다 사용한다면 시간 복잡도를 줄일 수 있을 것이다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이렇게 동일한 계산을 반복해야 할 때, &lt;b&gt;이전에 계산한 값을 메모리에 저장&lt;/b&gt;함으로써 동일한 계산의 반복 수행을 제거해 실행 속도를 빠르게 하는 기술을 &quot;&lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;메모이제이션&lt;/b&gt;&lt;/span&gt;&quot;이라 한다.&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  메모이제이션 활용&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1688659637153&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Fibonacci {
    static int[] memo;

    public static int fibo(int n) {
        memo = new int[n + 1];

        if (memo[n] &amp;gt; 0) {
            return memo[n]; //이미 구한 값이 있을 경우
        }
        if (n == 1 || n == 2) {
            return memo[n] = 1;
        } else {
            return memo[n] = fibo(n - 2) + fibo(n - 1);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/알고리즘</category>
      <category>메모이제이션</category>
      <category>알고리즘</category>
      <category>재귀함수</category>
      <category>팩토리얼</category>
      <category>피보나치</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/306</guid>
      <comments>https://jollyn.tistory.com/306#entry306comment</comments>
      <pubDate>Thu, 6 Jul 2023 21:46:54 +0900</pubDate>
    </item>
    <item>
      <title>[Book] 객체지향의 사실과 오해</title>
      <link>https://jollyn.tistory.com/262</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1장. 협력하는 객체들의 공동체&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향이란 시스템을 상호작용하는 &lt;b&gt;자율적인 객체&lt;/b&gt;들의 공통체로 바라보고 객체를 이용해 시스템을 분할하는 방법이다.&lt;/li&gt;
&lt;li&gt;자율적인 객체란 &lt;b&gt;상태&lt;/b&gt;와 &lt;b&gt;행위&lt;/b&gt;를 함께 지니며, &lt;b&gt;스스로 자기 자신을 책임&lt;/b&gt;지는 객체를 의미한다.&lt;/li&gt;
&lt;li&gt;객체는 시스템의 행위를 구현하기 위해 다른 객체와 &lt;b&gt;협력&lt;/b&gt;한다. 각 객체는 협력 내에서 정해진 &lt;b&gt;역할&lt;/b&gt;을 수행하며, 역할은 관련된 &lt;b&gt;책임&lt;/b&gt;의 집합이다.&lt;/li&gt;
&lt;li&gt;객체는 다른 객체와 협력하기 위해 &lt;b&gt;메세지&lt;/b&gt;를 전송하고, 메시지를 수신한 객체는 그것을 처리하는 데 적합한 메서드를 자율적으로 선택한다.&lt;/li&gt;
&lt;li&gt;객체지향의 핵심은 적절한 책임을 수행하는 역할 간의 유연하고 견고한 협력 관계를 구축하는 것이다. 클래스는 협력에 참여하는 객체를 만드는 데 필요한 구현 메커니즘일 뿐 클래스가 객체 지향의 중심이 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;실생활 예시&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 54.4183%; height: 95px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 17.3997%;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;역할&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 58.6318%;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;책임&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 17.3997%;&quot;&gt;손님&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 58.6318%;&quot;&gt;커피를 주문할 책임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 38px; width: 17.3997%;&quot; rowspan=&quot;2&quot;&gt;캐셔&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 58.6318%;&quot;&gt;주문 내용을 바리스타에게 전달할 책임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 58.6318%;&quot;&gt;커피가 준비됐다는 사실을 손님에게 알릴 책임&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 17.3997%;&quot;&gt;바리스타&lt;/td&gt;
&lt;td style=&quot;text-align: center; height: 19px; width: 58.6318%;&quot;&gt;커피를 제조할 책임&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;(identity), 변경 가능한 &lt;b&gt;상태&lt;/b&gt;(state), 특징적인 &lt;b&gt;행동&lt;/b&gt;(behavior)을 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;상태&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 상태를 구성하는 모든 특징을 통틀어 객체의 &lt;b&gt;프로퍼티(property)&lt;/b&gt;라 한다.&lt;/li&gt;
&lt;li&gt;객체의 프로퍼티는 단순한 값인 속성과 다른 객체를 참조하는 링크로 구분할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;행동&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체가 취하는 행동은 객체 자신의 상태를 변경시킨다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;행동은 부수효과(side effect)를 초래한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체 자신의 상태 변경&lt;/li&gt;
&lt;li&gt;행동 내에서 협력하는 다른 객체에 대한 메시지 전송&amp;nbsp;&lt;/li&gt;
&lt;li&gt;ex) 앨리스가 음료를 마시는 행동은 1) 앨리스의 키 감소, 2) 음료의 양 감소의 부수 효과를 일으킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;객체의 행동은 객체의 상태를 변경시키지만, 행동의 결과는 객체의 상태에 의존적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  식별자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체가 식별 가능하다는 것은 객체를 서로 구별할 수 있는 특정한 프로퍼티가 객체 안에 존재함을 의미하며, 이 프로퍼티를 식별자라 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 101.047%; height: 36px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 10.1091%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;단순 값 &lt;/b&gt;&lt;br /&gt;(value)&lt;/td&gt;
&lt;td style=&quot;width: 9.59893%; text-align: center; height: 19px;&quot;&gt;식별자 &lt;br /&gt;O&lt;/td&gt;
&lt;td style=&quot;width: 13.3069%; text-align: center; height: 19px;&quot;&gt;불변 상태&lt;br /&gt;(immutable &lt;br /&gt;state)&lt;/td&gt;
&lt;td style=&quot;width: 68.0317%; height: 19px; text-align: left;&quot;&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; 숫자, 문자열, 날짜, 시간, 금액 등&lt;br /&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; 값의 상태는 변하지 않기 때문에 &lt;b&gt;상태&lt;/b&gt;를 기반으로 두 인스턴스가 같은지 판단 &lt;br /&gt;&amp;nbsp; &amp;nbsp;&amp;rarr; &quot;&lt;b&gt;동등성(quality)&lt;/b&gt;&quot;&lt;br /&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; ex) 종이에 숫자 1이 적혀 있다면, 두 개의 숫자를 동일한 것이라고 판단&lt;br /&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; 관련 용어 : &lt;b&gt;값 객체(value object)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 10.1091%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;객체 &lt;/b&gt;&lt;br /&gt;(object)&lt;/td&gt;
&lt;td style=&quot;width: 9.59893%; text-align: center; height: 17px;&quot;&gt;식별자 &lt;br /&gt;X&lt;/td&gt;
&lt;td style=&quot;width: 13.3069%; text-align: center; height: 17px;&quot;&gt;가변 상태&lt;br /&gt;(mutable&lt;br /&gt;state)&lt;/td&gt;
&lt;td style=&quot;width: 68.0317%; height: 17px; text-align: left;&quot;&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; 객체는 시간의 흐름에 따라 행동을 통해 상태가 변하기 때문에 상태가 아닌 &lt;b&gt;식별자&lt;/b&gt;를 &lt;br /&gt;&amp;nbsp; &amp;nbsp;기반으로 두 인스턴스가 같은지 판단 &amp;rarr; &quot;&lt;b&gt;동일성(identical)&lt;/b&gt;&quot;&lt;br /&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; ex) 이름이 앨리스고 키가 동일한 두 사람이 있더라도, 두 사람을 같은 사람이라고 &lt;br /&gt;&amp;nbsp; &amp;nbsp;판단하지 않음&lt;br /&gt;&lt;b&gt;&amp;bull;&lt;/b&gt; 관련 용어 : &lt;b&gt;참조 객체(reference object)&lt;/b&gt;, &lt;b&gt;엔티티(entity)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;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;h2 data-ke-size=&quot;size26&quot;&gt;3장. 타입과 추상화&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;추상화&lt;/b&gt;란 어떤 양상, 세부 사항, 구조를 좀 더 명확하게 이해하기 위해 특정 절차나 물체를 의도적으로 &lt;b&gt;생략하거나 감춤으로써 복잡도를 극복&lt;/b&gt;하는 방법이다.&lt;/li&gt;
&lt;li&gt;추상화의 목적은 복잡성을 이해하기 쉬운 수준으로 &lt;b&gt;단순화&lt;/b&gt;하는 것이다.&lt;/li&gt;
&lt;li&gt;객체란 특정한 개념을 적용할 수 있는 구체적인 사물을 의미한다. 개념이 객체에 적용됐을 때 객체를 개념의 인스턴스(instance)라고 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;공통점을 기반으로 객체들을 묶기위한 그릇을 개념(concept)이라 한다.&lt;/li&gt;
&lt;li&gt;개념을 이용하면 객체를 여러 그룹으로 분류할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;컴퓨터 공학자들은 개념을 타입(type)이라 표현한다.&lt;/li&gt;
&lt;li&gt;타입(type)은 공통점을 기반으로 객체들을 묶기 위한 틀이다.&lt;/li&gt;
&lt;li&gt;훌륭한 객체지향 설계는 외부에 행동만을 제공하고 데이터는 행동 뒤로 감춰야한다. 이 원칙을 흔히 &lt;b&gt;캡슐화&lt;/b&gt;라고 한다.&lt;/li&gt;
&lt;li&gt;클래스는 타입을 구현하기 위해 프로그래밍 언어에서 제공한는 구현 메커니즘이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;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;4장. 역할, 책임, 협력&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 객체가 어떤 요청에 대해 대답해 줄 수 있거나, 적절한 행동을 할 의무가 있는 경우 해당 객체가 &lt;b&gt;책임&lt;/b&gt;을 가진다고 말한다.&lt;/li&gt;
&lt;li&gt;객체의 책임은 '&lt;b&gt;객체가 무엇을 알고 있는가&lt;/b&gt;'와 '&lt;b&gt;무엇을 할 수 있는가&lt;/b&gt;'로 구성된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아는 것(knowing)&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개인적인 정보에 관해 아는 것&amp;nbsp;&lt;/li&gt;
&lt;li&gt;관련된 객체에 관해 아는 것&lt;/li&gt;
&lt;li&gt;자신이 유도하거나 계산할 수 있는 것에 관해 아는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;하는 것(doing)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체를 생성하거나 계산을 하는 등의 스스로 하는 것&lt;/li&gt;
&lt;li&gt;다른 객체의 행동을 시키는 것&lt;/li&gt;
&lt;li&gt;다른 객체의 활동을 제어하고 조절하는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동일한 역할&lt;/b&gt;을 수행하는 객체들이 &lt;b&gt;동일한 메세지&lt;/b&gt;를 수신할 수 있기 때문에 &lt;b&gt;동일한 책임&lt;/b&gt;을 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;역할은 객체지향 설계의 단순성(simplicity), 유연성(flexbility), 재사용성(reusability)을 뒷받침하는 핵심 개념이다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 판사 역할(하트왕,하트여왕), 증인 역할(모자 장수, 앨리스, 요리사)와 같이 역할을 이용해 협력을 추상화했기 때문에 '판사'나 '증인'의 역할을 수행할 수 있는 어떤 객체라도 협력에 참여할 수 있다.&lt;br /&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tUJIJ/btsm8OCtWRX/qPk6pKxEFEMJMbiTJtH1z0/img.png&quot; width=&quot;369&quot; height=&quot;305&quot; data-origin-width=&quot;1621&quot; data-origin-height=&quot;1343&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;협력이라는 문맥에서 객체가 수행하게 될 적절한 책임, 즉 행동을 결정한 후에 그 행동을 수행하는 데 필요한 데이터를 고민해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;객체 지향 설계 기법&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;책임-주도 설계(Responsibility-Driven Design)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;협력에 필요한 책임들을 식별하고 적합한 객체에게 책임을 할당하는 방식으로 애플리케이션을 설계한다.&lt;/li&gt;
&lt;li&gt;시스템의 책임을 객체의 책임으로 변환하고, 각 객체가 책임을 수행하는 중에 필요한 정보나 서비스를 제공해줄 협력자를 찾아 해당 협력자에게 책임을 할당하는 순차적인 방식으로 객체들의 협력 공동체를 구축한다.&lt;/li&gt;
&lt;li&gt;객체지향 시스템을 설계하는 절차
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;시스템이 사용자에게 제공해야 하는 기능인 시스템 책임을 파악한다.&lt;/li&gt;
&lt;li&gt;시스템 책임을 더 작은 책임으로 분할한다.&lt;/li&gt;
&lt;li&gt;분할된 책임을 수행할 수 있는 적절한 객체 또는 역학을 찾아 책임을 할당한다.&lt;/li&gt;
&lt;li&gt;객체가 책임을 수행하는 중에 다른 객체의 도움이 필요한 경우 이를 책임질 적절한 객체 또는 역할을 찾는다.&lt;/li&gt;
&lt;li&gt;해당 객체 또는 역할에게 책임을 할당함으로써 두 객체가 협력하게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;디자인 패턴(Design Pattern)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 역할, 책임, 협력을 고안하기 위한 방법과 절차를 정의해 놓은 설계 템플릿의 모음이다.&lt;/li&gt;
&lt;li&gt;특정한 상황에 적용 가능한 디자인 패턴을 잘 알고 있다면 책임-주고 설계의 절차를 순차적으로 따르지 않고도 시스템 안에 구현할 객체들의 역할과 책임, 협력 관계를 빠르고 손쉽게 포착할 수 있을 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테스트-주도 개발(Test-Driven Development)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테스트를 먼저 작성하고 테스트를 통과하는 구체적인 코드를 추가하면서 애플리케이션을 완성해가는 방식을 따른다.&lt;/li&gt;
&lt;li&gt;기본 흐름은 실패하는 테스트를 작성하고, 테스트를 통과하는 가장 간단한 코드를 작성한 후 리팩터링을 통해 중복을 제거하는 것이다.&lt;/li&gt;
&lt;li&gt;테스트-주도 개발은 책임-주도 설계를 통해 도달해야 하는 목적지를 테스트라는 안전장치를 통해 좀 더 빠르고 견고한 방법으로 도달할 수 있도록 해주는 최상의 설계 프랙티스다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5장. 책임과 메시지&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;훌륭한 객체지향의 세계는 명확하게 정의된 역할과 책임을 지닌 객체들이 상호 협력하는 세계다.&lt;/li&gt;
&lt;li&gt;객체지향 공동체를 구성하는 기본 단위는 &lt;b&gt;자율적&lt;/b&gt;인 객체로, 자율적인 객체란 스스로 정한 원칙에 따라 판단하고 스스로의 의지를 기반으로 행동하는 객체다.&lt;/li&gt;
&lt;li&gt;책임은 협력에 참여하는 의도를 명확하게 설명할 수 있는 수준 안에서 추상적이어야 한다.&lt;/li&gt;
&lt;li&gt;자율적인 책임의 특징은 객체가 '어떻게(how)' 해야하는 가가 아니라 '&lt;b&gt;무엇을&lt;/b&gt;(what)'을 해야 하는가를 설명한다는 것이다.&lt;/li&gt;
&lt;li&gt;객체가 다른 객체에 접근할 수 있는 유일한 방법은 &lt;b&gt;메시지&lt;/b&gt;를 전송하는 것이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메세지는 수신자, 메시지 이름, 인자의 조합으로 구성된다.&lt;/li&gt;
&lt;li&gt;ex) 왕이 어제, 왕국에서 목격한 것을 증언할 것을 요청하고 싶을 때 모자 장수에게 보내는 메시지 &lt;br /&gt;&amp;rarr; &quot;모자장수.증언하라(어제, 왕국)&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;객체가 &lt;b&gt;메시지&lt;/b&gt;를 수신할 수 있다는 것은 객체가 메시지에 해당하는 &lt;b&gt;책임&lt;/b&gt;을 수행할 수 있음을 의미한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다형성&lt;/b&gt;이란 서로 다른 유형의 객체가 &lt;b&gt;동일한 메시지&lt;/b&gt;에 대해 서로 &lt;b&gt;다르게 반응&lt;/b&gt;하는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;서로 다른 객체들이 다형성을 만족시킨다는 것은 객체들이 동일한 책임을 공유한다는 것으로, 객체들 사이의 &lt;b&gt;대체 가능성&lt;/b&gt;을 의미한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 왕의 관점에서 모자 장수, 요리사, 앨리스는 동일한 메시지(증언하라)를 처리할 수 있기 때문에 모두 대체 가능한 존재다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다형성은 객체들의 대체 가능성을 이용해 설계를 유연하고 재사용 가능하게 만들며, &lt;b&gt;수신자의 종류를 캡슐화&lt;/b&gt;한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 왕은 '증언하라'라는 메시지를 전송하지만 메시지를 수신하는 대상이 모자 장수인지, 요리사인지, 앨리스인지 알 필요가 없다.&lt;/li&gt;
&lt;li&gt;따라서 왕에게 영향을 주지 않고도 메시지를 수신할 객체의 타입을 자유롭게 추가할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;송신자가 수신자에 대해 매우 적은 정보만 알고 있더라도 상호 협력이 가능하다는 사실은 설계 품질에 큰 영향을 미친다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;협력이 유연해짐 : 송신자는 수신자가 메시지를 이해한다면 누구라도 상관하지 않는다.&lt;/li&gt;
&lt;li&gt;협력이 수행되는 방식을 확장할 수 있음 : 송신자에게 아무런 영향을 주지 않고 수신자를 교체할 수 있다.&lt;/li&gt;
&lt;li&gt;협력이 수행되는 방식을 재사용할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;독립된 객체의 상태와 행위에 대해 고민하지 말고 시스템의 기능을 구현하기 위해 객체가 다른 객체에게 제공해야 하는 메시지에 대해 고민하라.&lt;/li&gt;
&lt;li&gt;자율적인 책임의 중요성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;협력을 단순하게 만든다. &amp;rarr; 책임이 적절하게 추상화된다.&lt;/li&gt;
&lt;li&gt;객체의 외부와 내부를 명확하게 분리한다. &amp;rarr; 객체가 몰라도 되는 사적인 부분이 객체 내부로 캡슐화되기 때문에 인터페이스와 구현이 분리된다.&lt;/li&gt;
&lt;li&gt;책임을 수행하는 내부적인 방법을 변경하더라도 외부에 영향을 미치지 않는다. &amp;rarr; 변경의 파급효과가 객체 내부로 캡슐화되기 때문에 두 객체 간의 결합도가 낮아진다.&lt;/li&gt;
&lt;li&gt;협력의 대상을 다양하게 선택할 수 있는 유연성을 제공한다. &amp;rarr; 설계가 유연해지고 재사용성이 높아진다.&lt;/li&gt;
&lt;li&gt;객체의 역할을 이해하기 쉬워진다. &amp;rarr; 객체의 응집도를 높은 상태로 유지하기가 쉬워진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;책임-주도 설계&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체지향 설계는 적절한 책임을 적절한 객체에게 할당하면서 메시지를 기반으로 협력하는 객체들의 관계를 발견하는 과정이다.&lt;/li&gt;
&lt;li&gt;책임을 완수하기 위해 협력하는 객체들을 이용해 시스템을 설계하는 방법을 &lt;b&gt;책임-주도 설계&lt;/b&gt;라고 한다.&lt;/li&gt;
&lt;li&gt;책임-주도 설계의 핵심은 어떤 행위가 필요한지를 먼저 결정한 후에 이 행위를 수행할 객체를 결정하는 것이다. 이 과정을 흔히 What/Who 사이클이라고 한다.&lt;/li&gt;
&lt;li&gt;메시지를 먼저 결정하고 객체가 메시지를 따르게 하는 설계 방식은 객체가 외부에 제공하는 인터페이스가 독특한 스타일을 따르게 한다. 이 스타일을 '묻지 말고 시켜라' 스타일 또는 '데메테르 법칙'이라고 한다.&lt;/li&gt;
&lt;li&gt;메시지 중심의 설계는 메시지 수신자의 &lt;b&gt;캡슐화&lt;/b&gt;를 증진시키고, 송신자가 수신자의 내부 상태를 미리 알 수 없기 때문에 송신자와 수신자가 &lt;b&gt;느슨하게 결합&lt;/b&gt;된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;인터페이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터페이스란 어떤 두 사물이 마주치는 경계 지점에서 서로 상호작용할 수 있게 이어주는 방법이나 장치를 의미한다.&lt;/li&gt;
&lt;li&gt;객체가 어떤 메시지를 수신할 수 있는지가 객체가 제공하는 인터페이스의 모양을 만든다.&lt;/li&gt;
&lt;li&gt;인터페이스는 외부에서 접근 가능한 &lt;b&gt;공용 인터페이스&lt;/b&gt;와 내부에서만 접근할 수 있는 감춰진 인터페이스로 구분된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;인터페이스의 특징&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터페이스의 사용법을 익히기만 하면 내부 구조나 동작 방식을 몰라도 쉽게 대상을 조작하거나 의사를 전달할 수 있다.&lt;/li&gt;
&lt;li&gt;인터페이스 자체는 변경하지 않고 단순히 내부 구성이나 작동방식을 변경하는 것은 사용자에게 어떠한 영향도 미치지 않는다.&lt;/li&gt;
&lt;li&gt;대상이 변경되더라도 동일한 인터페이스를 제공하기만 하면 아무런 문제 없이 상호작용할 수 있다.&lt;/li&gt;
&lt;li&gt;ex) 자동차의 인터페이스&lt;br /&gt;- 운전자와 자동차 사이에는 핸들, 변속기, 엑셀, 브레이크, 계기판으로 구성된 인터페이스가 존재한다.&lt;br /&gt;- 운전자는 자동차가 어떤 원리로 움직이는지 몰라도 운전하는 데 아무런 문제가 없다.&lt;br /&gt;- 자동차의 엔진을 교체한다고 해서 자동차를 운전하는 방법이 변하지 않는다.&lt;br /&gt;- 하나의 자동차를 운전하기 위한 인터페이스에 능숙하다면 어떤 자동차라도 운전할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;인터페이스의 원칙&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;좀 더 추상적인 인터페이스 : 객체의 자율성을 위해 너무 구체적인 인터페이스보다는 추상적인 인터페이스를 설계하자&lt;/li&gt;
&lt;li&gt;최소 인터페이스 : 외부에 사용할 필요가 없는 인터페이스는 최대한 노출을 하지 말자&lt;/li&gt;
&lt;li&gt;인터페이스와 구현 간에 차이가 있다는 점을 인식&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;구현&lt;/b&gt;(implementation)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구현은 객체의 내부 구조와 작동 방식을 가리킨다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;객체는 상태를 가진다. 상태는 객체에 포함되지만 객체 외부에 노출되는 공용 인터페이스의 일부는 아니다. 따라서 상태를 어떠헥 표현할 것인가는 객체의 구현에 해당한다.&lt;/li&gt;
&lt;li&gt;객체의 외부와 내부를 분리하라는 것은 객체의 공용 인터페이스와 구현을 명확하게 분리하라는 말과 동일하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;객체를 설계할 때 객체 외부에 노출되는 인터페이스와 객체의 내부에 숨겨지는 구현을 명확하게 분리해서 고려해야 한다. 이를 '&lt;b&gt;인터페이스와 구현의 분리 원칙&lt;/b&gt;'이라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  캡슐화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체의 자율성을 보존하기 위해 &lt;b&gt;구현을 외부로부터 감추는 것&lt;/b&gt;을 캡슐화라고 한다.&lt;/li&gt;
&lt;li&gt;캡슐화는 두가지 관점에서 사용된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태와 행위의 캡슐화(데이터 캡슐화)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체는 스스로 자신의 상태를 관리하며 상태를 변경하고 외부에 응답할 수 있는 행동을 내부에 함께 보관한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;사적인 비밀의 캡슐화
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;객체는 외부의 객체가 자신의 내부 상태를 직접 관찰하거나 제어할 수 없도록 막기 위해 의사소통 가능한 특별한 경로만 외부에 노출한다.&lt;/li&gt;
&lt;li&gt;외부에서 객체와 의사소통할 수 있는 고정된 경로를 공용 인터페이스라 한다.&lt;/li&gt;
&lt;li&gt;외부에 제공해야 할 필요가 있는 메시지만을 객체의 공용 인터페이스에 포함시키고 개인적인 비밀은 공용 인터페이스 뒤에 감춤으로써 외부에 불필요한 공격과 간섭으로부터 내부 상태를 격리할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6장. 객체 지도&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자주 변경되는 기능이 아니라 안정적인 구조를 따라 역할 , 책임, 협력을 구성하라.&lt;/li&gt;
&lt;li&gt;객체지향 세계를 구축하기 위해서는 사용자에게 제공할 &lt;b&gt;기능&lt;/b&gt;과 기능을 담을 안정적인 &lt;b&gt;구조&lt;/b&gt;라는 재료가 준비되어 있어야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기능 : 사용자가 자신의 목표를 달성하기 위해 책임을 수행하는 시스템의 행위, 서비스로 표현&lt;/li&gt;
&lt;li&gt;구조 : 시스템의 기능을 구현하기 위한 기반, 기능 변경을 수용할 수 있도록 안정적이어야 함, 사용자가 도메인에 관해 생각하는 개념과 개념들 간의 관계로 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;기능을 수집하고 표현하기 위한 기법을 &lt;b&gt;유스케이스 모델링&lt;/b&gt;, 구조를 수집하고 표현하기 위한 기법을 &lt;b&gt;도메인 모델링&lt;/b&gt;이라 한다.&lt;/li&gt;
&lt;li&gt;안정적인 도메인 모델을 기반으로 시스템의 기능을 구현하라. 도메인 모델과 코드를 밀접하게 연관시키기 위해 노력하라. 그것이 유지보수하기 쉽고 유연한 객체지향 시스템을 만드는 첫걸음이 될 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구조 : 도메인 모델&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;도메인 모델&lt;/b&gt;이란 사용자가 프로그램을 사용하는 대상 영역에 관한 지식을 선택적으로 단순화한 형태다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인 : 사용자가 프로그램을 사용하는 대상 분야&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;모델 : 대상을 단순화하고 의식적으로 구조화해서 표현한 것&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;소프트웨어의 도메인이 무엇이건 상관없이 항상 도메인과 관련된 사람들이 도메인을 바라보는 모델이 존재한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) 은행원은 은행 도메인을 고객과 계좌 사이의 돈의 흐름으로 이해, 게임 플레이어들은 게임 도메인을 캐릭터와 몬스터, 몬스터가 떨구는 아이템 간의 관계로 파악&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;멘탈 모델을 사용자 모델, 디자인 모델, 시스템 이미지 세가지로 구분한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자 모델 : 사용자가 제품에 대해 가지고 있는 생각&lt;/li&gt;
&lt;li&gt;디자인 모델 : 설계자가 마음 속에 갖고 있는 시스템에 대한 생각&lt;/li&gt;
&lt;li&gt;시스템 이미지 : 최종 제품의 모습&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;설계자는 디자인 모델을 기반으로 만든 시스템 이미지가 사용자 모델을 정확하게 반영하도록 노력해야 한다.&lt;/li&gt;
&lt;li&gt;안정적인 구조를 제공하는 도메인 모델을 기반으로 소프트웨어 구조를 설계하면 변경에 유연하게 대응할 수 있는 탄력적인 소프트웨어를 만들 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1197&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pejaE/btsno7hNPky/FmwQoXRfIabMmZabCVViMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pejaE/btsno7hNPky/FmwQoXRfIabMmZabCVViMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pejaE/btsno7hNPky/FmwQoXRfIabMmZabCVViMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpejaE%2Fbtsno7hNPky%2FFmwQoXRfIabMmZabCVViMk%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;450&quot; height=&quot;199&quot; data-origin-width=&quot;1197&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기능 : 유스케이스&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용자의 목표를 달성하기 위해 사용자와 시스템 간에 이뤄지는 상호작용의 흐름을 텍스트로 정리한 것을 유스케이스라 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m59IA/btsni8CTNwO/gp5UxSbkxkbKvVWMs6XLI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m59IA/btsni8CTNwO/gp5UxSbkxkbKvVWMs6XLI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m59IA/btsni8CTNwO/gp5UxSbkxkbKvVWMs6XLI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm59IA%2Fbtsni8CTNwO%2Fgp5UxSbkxkbKvVWMs6XLI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;219&quot; data-origin-width=&quot;1119&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;유스케이스는 하나의 시나리오가 아니라 여러 시나리오들의 집합이다. 시나리오는 유스케이스를 통해 시스템을 사용하는 하나의 특정한 이야기이며 &quot;유스케이스 인스턴스&quot;라고도 한다.&lt;/li&gt;
&lt;li&gt;유스케이스는 사용자 인터페이스와 관련된 세부 정보 및 내부 설계와 관련된 정보를 포함하지 않아야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;유스케이스에 대해 더 알고 싶다면 &lt;a href=&quot;http://www.cs.otago.ac.nz/coursework/cosc461/usecases.htm&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;여기&lt;/a&gt;를 참고하자.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7장. 함께 모으기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체지향 설계의 세가지 상호 연관된 관점을 마틴 파울러는 다음과 같이 설명한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개념 관점&lt;/b&gt; : 설계는 도메인 안에 존재하는 개념과 개념들 사이의 관계를 표현한다. &lt;b&gt;도메인&lt;/b&gt;이란 사용자들이 관심을 가지고 있는 특정 분야나 주제를 말하며, 소프트웨어는 도메인에 존재하는 문제를 해결하기 위해 개발된다. 이 관점은 사용자가 도메인을 바라보는 관점을 반영해 실제 도메인 규칙과 제약을 최대한 유사하게 반영하는 것이 핵심이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;명세 관점&lt;/b&gt; : 이 관점은 사용자 영역인 도메인의 개념이 아니라 개발자의 영역인 실제 소프트웨어 안에서 살아 숨쉬는 객체들의 책임에 초점을 맞춘다. 즉, 객체의 인터페이스를 바라보게 된다. 명세 관점에서 프로그래머는 객체가 협력을 위해 &lt;b&gt;무엇&lt;/b&gt;을 할 수 있는가에 초점을 맞춘다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;구현 관점&lt;/b&gt; : 이 관점은 객체들이 책임을 수행하는 데 필요한 동작하는 코드를 작성하는 것이다. 구현 관점에서 프로그래머는 객체의 책임을 &lt;b&gt;어떻게&lt;/b&gt; 수행할 것인가에 초점을 맞추며 인터페이스를 구현하는데 필요한 속성과 메서드를 클래스에 추가한다.&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  커피 전문점 예제&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;도메인&lt;/b&gt; : 커피 전문점&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;메뉴판, 메뉴(아메리카노, 카푸치노, 카라멜 마키아또, 에스프레소), 손님, 바리스타, 커피&lt;img style=&quot;caret-color: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/6F8U1/btsobbKiLNH/lANdJJPhKlAMi1LidTVM5K/img.png&quot; width=&quot;326&quot; height=&quot;279&quot; data-origin-width=&quot;1578&quot; data-origin-height=&quot;1353&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체들 간의 관계&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;손님은 메뉴판에서 주문할 커피를 선택할 수 있다. &amp;rarr; 손님-메뉴판 관계&lt;/li&gt;
&lt;li&gt;손님은 바리스타에게 주문을 할 수 있다. &amp;rarr; 손님-바리스타 관계&lt;/li&gt;
&lt;li&gt;바리스타는 커피를 만든다. &amp;rarr; 바리스타-커피 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;도메인 모델&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커피 전문점 도메인을 구성한느 타입들의 종류와 관계를 표현한 것으로, 이처럼 소프트웨어가 대상으로 하는 영역인 도메인을 단순화해서 표현한 모델을 도메인 모델이라 한다.&lt;br /&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TANDQ/btsn7tk8uSv/dKLMJxnkzEjnabodGkvoHk/img.png&quot; width=&quot;250&quot; height=&quot;185&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;576&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/개발서적</category>
      <category>객체지향의 사실과 오해</category>
      <category>북리뷰</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/262</guid>
      <comments>https://jollyn.tistory.com/262#entry262comment</comments>
      <pubDate>Wed, 5 Jul 2023 15:46:28 +0900</pubDate>
    </item>
    <item>
      <title>[Tistory] 목차(TOC) 적용하기</title>
      <link>https://jollyn.tistory.com/304</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목차 스타일1&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;552&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pI39Z/btsCoe0ZZWV/jcdwGtVQz0M7LN80EuOmyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pI39Z/btsCoe0ZZWV/jcdwGtVQz0M7LN80EuOmyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pI39Z/btsCoe0ZZWV/jcdwGtVQz0M7LN80EuOmyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpI39Z%2FbtsCoe0ZZWV%2FjcdwGtVQz0M7LN80EuOmyk%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;280&quot; height=&quot;272&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;552&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;HTML 변경하기&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;/head&amp;gt; 바로 전 부분에 코드를 추가해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688540518679&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- TOC Start --&amp;gt;
&amp;lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://cdnjs.cloudflare.com/ajax/libs/tocbot/4.11.1/tocbot.css&quot;&amp;gt;
&amp;lt;!-- TOC End --&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신의 스킨에서 본문 내용이 시작되는 부분을 찾아 추가해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688540700761&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- TOC Start --&amp;gt;
&amp;lt;div class='toc'&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;!-- TOC End --&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;/body&amp;gt; 바로 전 부분에 추가해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688540560395&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- TOC Script Start--&amp;gt; 
&amp;lt;script&amp;gt;
  var content = document.querySelector('.entry-content')
  var headings = content.querySelectorAll('h1, h2, h3, h4, h5, h6, h7')
  var headingMap = {}

  Array.prototype.forEach.call(headings, function (heading) {
      var id = heading.id ? heading.id : heading.textContent.trim().toLowerCase()
                 .split(' ').join('-').replace(/[\!\@\#\$\%\^\&amp;amp;\*\(\):]/ig, '')
      headingMap[id] = !isNaN(headingMap[id]) ? ++headingMap[id] : 0
      if (headingMap[id]) {
        heading.id = id + '-' + headingMap[id]
      } else {
        heading.id = id
      }
    })

  tocbot.init({
    tocSelector: '.toc',
    contentSelector: '.entry-content',
    headingSelector:'h1, h2, h3',
    hasInnerContainers: false
  });

  $(document).ready(function(){
    $('.toc').addClass('toc-absolute');

    var toc_top = $('.toc').offset().top - 165;
    $(window).scroll(function() {
      if ($(this).scrollTop() &amp;gt;= toc_top) {
        $('.toc').addClass('toc-fixed');
        $('.toc').removeClass('toc-absolute');
      } else {
        $('.toc').addClass('toc-absolute');
        $('.toc').removeClass('toc-fixed');
      }
    });
  });
&amp;lt;/script&amp;gt;
&amp;lt;!-- TOC Script End--&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;CSS 변경하기&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신의 스킨에 맞게 변경이 필요할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688541041317&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* TOC CSS Start */
.toc-absolute {
  position: absolute;
}
.toc-fixed {
  position: fixed;
  top: 130px;
}
.toc {
  right: calc((100% - 840px) / 2 - 300px);
  width: 180px;
  padding: 0 10px 0 10px;
  box-sizing: border-box;
}

.toc-list {
  margin-top: 10px !important;
  font-size: 12px;
}
.toc &amp;gt; .toc-list li {
  margin-bottom: 10px;
}
.toc &amp;gt; .toc-list li:last-child {
  margin-bottom: 0;
}
.toc &amp;gt; .toc-list li a {
  text-decoration: none;
}

@media screen and (max-width: 950px) {
    .toc {
        display: none;
    }
}
/* TOC CSS End */&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;적용 모습&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필자는 티스토리 BookClub 테마 사용했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2723&quot; data-origin-height=&quot;1188&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/teInM/btsCgqoRjB7/Bug8lmp1keD7eR1sbBHLWk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/teInM/btsCgqoRjB7/Bug8lmp1keD7eR1sbBHLWk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/teInM/btsCgqoRjB7/Bug8lmp1keD7eR1sbBHLWk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FteInM%2FbtsCgqoRjB7%2FBug8lmp1keD7eR1sbBHLWk%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;2723&quot; height=&quot;1188&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2723&quot; data-origin-height=&quot;1188&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;목차 스타일2&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;554&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lQsFU/btsCg6jkvZQ/LanYy3ltOOc4fBbmpF8b90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lQsFU/btsCg6jkvZQ/LanYy3ltOOc4fBbmpF8b90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lQsFU/btsCg6jkvZQ/LanYy3ltOOc4fBbmpF8b90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlQsFU%2FbtsCg6jkvZQ%2FLanYy3ltOOc4fBbmpF8b90%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;280&quot; height=&quot;276&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;562&quot; data-origin-height=&quot;554&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;파일 업로드&lt;/b&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/7nb4O/btsmziSsNAG/OlKdJAaVm4Z1mwm6awy2Bk/toc.js?attach=1&amp;amp;knm=tfile.js&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;toc.js&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.01MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;figure class=&quot;fileblock&quot; data-ke-align=&quot;alignLeft&quot;&gt;&lt;a href=&quot;https://blog.kakaocdn.net/dn/Gsk6S/btsmzIDgXgU/eWAREtuGUYFUhtNaF1g4o1/toc.css?attach=1&amp;amp;knm=tfile.css&quot; class=&quot;&quot;&gt;
    &lt;div class=&quot;image&quot;&gt;&lt;/div&gt;
    &lt;div class=&quot;desc&quot;&gt;&lt;div class=&quot;filename&quot;&gt;&lt;span class=&quot;name&quot;&gt;toc.css&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;size&quot;&gt;0.00MB&lt;/div&gt;
&lt;/div&gt;
  &lt;/a&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;HTML 변경&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;/head&amp;gt; 앞 부분에 추가해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688541466563&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!--============= TOC =============--&amp;gt;
&amp;lt;script src=&quot;./images/toc.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;link rel=&quot;stylesheet&quot; href=&quot;./images/toc.css&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신의 스킨에서 본문 내용이 시작되는 부분을 찾아 추가해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688541355094&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- TOC Start --&amp;gt;
&amp;lt;div class='toc hidden-xs hidden-sm'&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;!-- TOC End --&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;/body&amp;gt; 앞 부분에 추가해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688541451080&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- TOC Script Start--&amp;gt; 
&amp;lt;script&amp;gt;
  var content = document.querySelector('.tt_article_useless_p_margin')
  var headings = content.querySelectorAll('h1, h2, h3, h4, h5, h6, h7')
  var headingMap = {}
 
  Array.prototype.forEach.call(headings, function (heading) {
      var id = heading.id ? heading.id : heading.textContent.trim().toLowerCase()
                 .split(' ').join('-').replace(/[\!\@\#\$\%\^\&amp;amp;\*\(\):]/ig, '')
      headingMap[id] = !isNaN(headingMap[id]) ? ++headingMap[id] : 0
      if (headingMap[id]) {
        heading.id = id + '-' + headingMap[id]
      } else {
        heading.id = id
      }
    })
 
  tocbot.init({
    tocSelector: '.toc',
    contentSelector: '.tt_article_useless_p_margin',
    headingSelector:'h1, h2, h3',
    hasInnerContainers: false
  });
 
  $(document).ready(function(){
    $('.toc').addClass('toc-absolute');
 
    var toc_top = $('.toc').offset().top - 10;
    $(window).scroll(function() {
      if ($(this).scrollTop() &amp;gt;= toc_top) {
        $('.toc').addClass('toc-fixed');
        $('.toc').removeClass('toc-absolute');
      } else {
        $('.toc').addClass('toc-absolute');
        $('.toc').removeClass('toc-fixed');
      }
    });
  });
&amp;lt;/script&amp;gt;
&amp;lt;!-- TOC Script End--&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;b&gt;CSS 변경&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자신의 스킨에 맞게 변경이 필요할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1688541543195&quot; class=&quot;css&quot; data-ke-language=&quot;css&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* TOC CSS Start */
.toc {
  position: fixed;
  top: 12%;
  right: 1.0%;
  width: 250px;
  padding: 10px 0px 15px 5px;
  border-radius: var(--default-radius);
  box-sizing: border-box;
  box-shadow: 0px 3px 10px rgb(0 0 0 / 30%);
  background: #59595981;
  }
.toc-list {
  margin-top: 10px !important;
  font-size: 13px;
  padding-right: 8px;
  color:#fff;
  text-overflow:ellipsis;
}
.toc &amp;gt; .toc-list li {
  margin-bottom: 10px;
}
.toc &amp;gt; .toc-list li:last-child {
  margin-bottom: 0;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.toc &amp;gt; .toc-list li a {
  text-decoration: none;
}
/* TOC CSS End */&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;기본 목차 스타일&quot; href=&quot;https://jh-make.tistory.com/entry/%EC%9E%90%EB%8F%99-%EB%AA%A9%EC%B0%A8-%EB%84%A3%EA%B8%B0-%EB%B6%81%ED%81%B4%EB%9F%BD-%EC%8A%A4%ED%82%A8&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[티스토리 블로그] 자동 목차 넣기 (TOC)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;왼쪽 선 심플 스타일&quot; href=&quot;https://jstar0525.tistory.com/256#ref.&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Blog] Tistory 자동 목차(TOC) 적용하기 (odyssey 오디세이 스킨)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;float 스타일&quot; href=&quot;https://seons-dev.tistory.com/entry/%ED%8B%B0%EC%8A%A4%ED%86%A0%EB%A6%AC-%EB%B3%B8%EB%AC%B8%EC%97%90-TOC-%EB%AA%A9%EC%B0%A8-%EB%84%A3%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;(티스토리) 본문에 TOC 목차 넣기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Etc</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/304</guid>
      <comments>https://jollyn.tistory.com/304#entry304comment</comments>
      <pubDate>Wed, 5 Jul 2023 03:20:17 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] #17 JPQL : 중급 문법</title>
      <link>https://jollyn.tistory.com/300</link>
      <description>&lt;blockquote style=&quot;background-color: #fcfcfc; color: #666666; text-align: left;&quot; data-ke-style=&quot;style3&quot;&gt;본 포스팅은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.inflearn.com/course/ORM-JPA-Basic/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;인프런 - 자바 ORM 표준 JPA 프로그래밍 (기본편)&amp;nbsp;&lt;/a&gt;을 강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;경로 표현식&lt;/b&gt;&lt;/h2&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;경로 표현식은 .(점)을 찍어 객체 그래프를 탐색하는 것이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상태 필드&lt;/b&gt;(static field) : 단순히 값을 저장하기 위한 필드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;연관 필드&lt;/b&gt;(association field) : 연관관계를 위한 필드
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 값 연관 필드 : @ManyToOne, @OneToOne, 대상이 엔티티&lt;/li&gt;
&lt;li&gt;컬렉션 값 연관 필드 : @OneToMany, @ManyToMany, 대상이 컬렉션&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;특징&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상태 필드 : 경로 탐색의 끝이며, 더이상 탐색이 불가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1688400756435&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String query = &quot;select m.username, m.age from Member m&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단일 값 연관 필드 : &lt;b&gt;묵시적 내부 조인이 발생&lt;/b&gt;하며, 탐색을 더 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1688400040088&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String query = &quot;select m.team from Member m&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 m.team.name으로 탐색이 더 가능하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컬렉션 값 연관 필드 : 묵시적 내부 조인이 발생하며, 더이상 &lt;b&gt;탐색이 불가능&lt;/b&gt;하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1688400337394&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String query = &quot;select t.members from Team t&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 t.members.username으로 탐색이 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해서 탐색이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1688400552786&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String query = &quot;select m.username from Team t join t.members m&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;실무에서는 묵시적 조인은 사용하지 않는 것을 권장한다.&lt;br /&gt;명시적 조인을 사용해야 쿼리 튜닝하기 쉽고, 묵시적 조인을 사용할 경우 에러사항이 많이 발생할 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;명시적 조인, 묵시적 조인&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;명시적 조인&lt;/b&gt; : join 키워드를 직접 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;묵시적 조인&lt;/b&gt; : 경로 표현식에 의해 묵시적으로 SQL 조인이 발생 (내부 조인만 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1688400939500&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* 명시적 조인 */
select m from Member m join m.team t
/* 묵시적 조인 */
select m.team from Member m&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;경로 탐색을 사용한 묵시적 조인 시 주의사항&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;항상 내부 조인을 사용한다.&lt;/li&gt;
&lt;li&gt;컬렉션은 경로 탐색의 끝으로, 컬렉션을 더 탐색하려면 명시적 조인을 통해 별칭을 얻어야 한다.&lt;/li&gt;
&lt;li&gt;경로 탐색은 주로 SELECT, WHERE 절에서 사용하지만 묵시적 조인으로 인해 SQL의 FROM (JOIN) 절에 영향을 준다.&lt;/li&gt;
&lt;li&gt;조인은 SQL 튜닝에 중요한 포인트인데, 묵시적 조인은 조인이 일어나는 상황을 한눈에 파악하기 어렵기 때문에 튜닝이 어렵다.&lt;/li&gt;
&lt;li&gt;따라서 실무에서는 묵시적 조인은 사용하지 말고, 명시적 조인만 사용하는 것을 권장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;페치 조인(fetch join)&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPQL에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;성능 최적화&lt;/b&gt;를 위해 제공하는 기능이다.&lt;/li&gt;
&lt;li&gt;SQL 조인 종류 X&lt;/li&gt;
&lt;li&gt;연관된 엔티티나 컬렉션을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SQL 한번에&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함께 조회할 수 있도록 한다. (한방 쿼리)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;join fetch&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제를 통해 알아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1749794566310&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String qeury = &quot;select m from Member&quot;;
List&amp;lt;Member&amp;gt; result = em.createQuery(query, Member.class)
                        .getResultList();

for (Member member : result) {
    System.out.prinln(&quot;member = &quot; + member.getUsername() + &quot;, &quot; + member.getTeam().getName());
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Member의 Team 정보는 지연로딩으로 인해 프록시로 들어온다.&lt;br /&gt;따라서 member.getTeam().getName()으로 호출하는 시점마다 데이터베이스에 쿼리를 날린다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 쿼리를 보면 처음에 Member 조회 쿼리가 나가고, 반복문을 돌며 Team 조회 쿼리가 나가는 것을 확인할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;회원1, 팀A (SQL)&lt;/li&gt;
&lt;li&gt;회원2, 팀A (1차캐시)&lt;/li&gt;
&lt;li&gt;회원3, 팀B (SQL)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제에서는 쿼리가 3번 나갔지만, 만약 회원의 팀이 모두 다르고 팀이 100개라면 101개의 쿼리가 나갈 수 있는 것이다. (N+1문제)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 페치 조인을 사용해 N+1 문제를 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;엔티티 페치 조인 (ManyToOne)&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1749794566311&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String query = &quot;select m from Member m join fetch m.team&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;join fetch 명령어를 사용해 Member를 조회하는 시점에 Team도 함께 끌어오도록 JPQL을 변경했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리 1번으로, from 절에서 inner join을 사용해 member.* team.* 정보를 모두 가져오는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 Team은 프록시가 아니라 실제 객체로 영속성 컨텍스트에 올라가 있기 때문에 member.getTeam().getName() 시점에 1차캐시를 사용해 추가적인 쿼리가 발생하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;컬렉션 페치 조인 (OneToMany)&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1749794566311&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String query = &quot;select t from Team t join fetch t.members where t.name='팀A'&quot;;
List&amp;lt;Team&amp;gt; teams = em.createQuery(query, Team.class)
                     .getResultList();
                     
for(Team team : teams) {
    System.out.println(&quot;teamname = &quot; + team.getName() + &quot;, team = &quot; + team );
    for (Member member : team.getMembers()) {
        // 페치 조인으로 팀과 회원을 함께 조회해서 지연 로딩 발생 안함
        System.out.println(&quot;-&amp;gt; username = &quot; + member.getUsername() + &quot;, member = &quot; + member);
    }
}&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;팀A는 1개지만, 조인 시 row가 2개가 되는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;페치 조인과 DISTINCT&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL의 DISTINCT는 중복된 결과를 제거하고 싶을 때 사용한다.&lt;/li&gt;
&lt;li&gt;JPQL의 DISTINC는 2가지 기능을 제공한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL에 DISTINCT를 추가&lt;/li&gt;
&lt;li&gt;애플리케이션에서 엔티티 중복을 제거 (식별자로 확인 )&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 본 예제에서 distinct 명령어를 추가해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1749794566312&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String query = &quot;select distinct t from Team t join fetch t.members where t.name='팀A'&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SQL에 DISTICNT를 추가하지만 데이터가 다르므로(ID, NAME)&amp;nbsp; SQL 결과에서 중복제거가 이뤄지지 않는다.&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;이때 JPA가 DISTINCT 추가로 애플리케이션에서 중복 제거를 시도한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 식별자를 가진 Team 엔티티 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;페치 조인과 일반 조인의 차이&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt; &lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;일반 조인&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연관된 엔티티를 함께 조회하지 않음&lt;/li&gt;
&lt;li&gt;ex) select t from Team t&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;join&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;t.members m where t.name='팀A'&lt;/li&gt;
&lt;li&gt;지연 로딩 발생으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;N+1&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;주의&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  페치 조인&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;연관된 엔티티를 함께 조회해옴&lt;/li&gt;
&lt;li&gt;ex) select t from Team t&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;join fetch&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;t.members m where t.name='팀A'&lt;/li&gt;
&lt;li&gt;지연 로딩 발생 X&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;페치 조인의 특징과 한계&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페치 조인 대상에는 별칭을 줄 수 없다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) select t from Team t join fetch t.members&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;(as) m&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr; 불가능&lt;/li&gt;
&lt;li&gt;하이버네이트는 가능하지만, 가급적 사용하지 않는 것을 권장한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;둘 이상의 컬렉션은 페치 조인할 수 없다.&lt;/li&gt;
&lt;li&gt;컬렉션을 페치 조인하면 페이징 API를 사용할 수 없다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일대일, 다대일 같은 단일 값 연관관계 필드드들은 페치 조인해도 페이징 가능 (데이터가 뻥튀기 되지 않으므로)&lt;/li&gt;
&lt;li&gt;일대다 컬렉션 페치 조인은 데이터가 뻥튀기되기 때문에 페이징할 경우 이상한 결과가 나올 수 있기 때문에 사용 불가능&lt;/li&gt;
&lt;li&gt;컬렉션 페치 조인 시 하이버네이트는 경고 로그를 남기고 메모리에서 페이징 (매우 위험)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;연관된 엔티티들을 SQL 한번으로 조회할 수 있다. &amp;rarr; 성능 최적화&lt;/li&gt;
&lt;li&gt;엔티티에 직접 적용하는 글로벌 로딩 전략보다 페치 조인이 우선시 적용된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@OneToMany(fetch=FetchType.LAZY) // 글로벌 로딩 전략&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;페치 조인 페이징 해결방법 (BatchSize)&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1749794566313&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;lt;name=&quot;hibernate.default_batch_fetch_size&quot; value=&quot;100&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;실무에서는 글로벌 로딩 전략은 모두 지연 로딩으로, 최적화가 필요한 곳에만  페치 조인을 적용하면 대부분의 성능 문제가 해결된다.&lt;/li&gt;
&lt;li&gt;하지만, 모든 것을 페치 조인으로 해결 할 수는 없다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;페치 조인은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;객체 그래프를 유지할 때&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용하면 효과적이다.&lt;/li&gt;
&lt;li&gt;여러 테이블을 조인해서 엔티티가 가진 모양이 아닌 전혀 다른 결과를 내야 하면, 페치 조인보다는 일반 조인을 사용하고 필요한 데이터들만 조회해서 DTO로 반환하는 것이 효과적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;br /&gt;Named 쿼리&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;미리 정의해서 이름을 부여해두고 사용하는 JPQL이다.&lt;/li&gt;
&lt;li&gt;정적 쿼리만 가능, 동적 쿼리 불가능&lt;/li&gt;
&lt;li&gt;애플리케이션 로딩 시점에 초기화 후에 재사용한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;애플리케이션 로딩 시점에 쿼리를 검증&lt;/b&gt;한다는 장점이 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA가 로딩되면서 어노테이션으로 등록되어 있는 Named 쿼리를 SQL로 파싱해서 들고 있으려고 하기 때문에, 쿼리 문법이 안맞거나 문제가 있을 때 컴파일 에러를 발생시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사용 방법&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Named 쿼리를 정의하는 방법에는 2가지가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어노테이션에 정의&lt;/li&gt;
&lt;li&gt;XML 정의 (XML이 항상 우선권을 가짐)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  어노테이션에 정의&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1749794677299&quot; class=&quot;less&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@Entity
@NamedQuery(
    name = &quot;Member.findByUsername&quot;,
    query = &quot;select m from Member m where m.username = :username&quot;
)
public class Member {
    ...
}

List&amp;lt;Member&amp;gt; result = em.createNamedQuery(&quot;Member.findByUsername&quot;, Member.class)
                        .setParameter(&quot;username&quot;, &quot;이름1&quot;)
                        .getResultList();&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;  XML에 정의&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  META-INF/persistence.xml&lt;/p&gt;
&lt;pre id=&quot;code_1749794677300&quot; class=&quot;pgsql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;vbnet&quot;&gt;&lt;code&gt;&amp;lt;persistence-unit name=&quot;jpabook&quot; &amp;gt;
	&amp;lt;mapping-file&amp;gt;META-INF/ormMember.xml&amp;lt;/mapping-file&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  META-INF/ormMember.xml&lt;/p&gt;
&lt;pre id=&quot;code_1749794677300&quot; class=&quot;xml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;vbnet&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;entity-mappings xmlns=&quot;http://xmlns.jcp.org/xml/ns/persistence/orm&quot; version=&quot;2.1&amp;gt;
    &amp;lt;named-query name=&quot;Member.findByUsername&amp;gt;
        &amp;lt;query&amp;gt;&amp;lt;![CDTA[
            select m
            form Member m
            where m.username = :username
        ]]&amp;gt;&amp;lt;/query&amp;gt;
    &amp;lt;/named-query&amp;gt;

    &amp;lt;named-query name=Member.count&amp;gt;
        &amp;lt;query&amp;gt;select count(m) from Member m&amp;lt;/query&amp;gt;
    &amp;lt;/named-query&amp;gt;
&amp;lt;/entity-mappins&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/Jpa</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/300</guid>
      <comments>https://jollyn.tistory.com/300#entry300comment</comments>
      <pubDate>Tue, 4 Jul 2023 01:21:08 +0900</pubDate>
    </item>
    <item>
      <title>[Github] PR, ISSUE 템플릿 사용하기</title>
      <link>https://jollyn.tistory.com/296</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;PR 템플릿 사용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 최상단에 .github 폴더를 만든다.&lt;/p&gt;
&lt;pre id=&quot;code_1707975334232&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mkdir .github&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;.github 폴더 내에 PULL_REQUEST_TEMPATE 이름으로 md 파일을 만든다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  PULL_REQUEST_TEMPLATE.md&lt;/blockquote&gt;
&lt;pre id=&quot;code_1707975428060&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;##   관련 이슈

close #이슈번호

## ✨ 작업 내용

&amp;lt;!-- 이번 PR에서 작업한 내용을 리스트 형식으로 작성해주세요. (이미지 첨부 가능) --&amp;gt;

-

##   리뷰 요구 사항

&amp;lt;!-- 리뷰어가 특별히 봐주었으면 하는 부분을 알려주세요. --&amp;gt;

-

##   논의하고 싶은 내용

&amp;lt;!-- (선택) 논의하고 싶은 내용 작성해주세요. 
ex) 메서드 xxx의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요? --&amp;gt;

-

##   기타 사항

&amp;lt;!-- (선택) 다른 개발자분들이 인지해놓는다면 좋은 내용들이나 특이사항이 있다면 남겨주세요. --&amp;gt;

- [링크]()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;ISSUE 템플릿 사용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.github 폴더 내에 ISSUE_TEMPLATE 폴더를 만든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ISSUE_TEMPLATE 내에 이슈 타입에 맞는 md 파일을 만든다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  ISSUE_TEMPLATE/feat.md&lt;/blockquote&gt;
&lt;pre id=&quot;code_1707975564248&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
name: ✨ Feature
about: feature 관련 이슈입니다.
title: ''
labels: ' &amp;zwj; BE, ✨feature'
assignees: ''
---

## ✨ 구현 기능

&amp;lt;!-- 구현 할 기능을 요약하여 설명해주세요. --&amp;gt;

## ✅ TODO

&amp;lt;!-- 작업 해야할 목록을 작성해주세요. --&amp;gt;

- [ ] sample&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  ISSUE_TEMPLATE/bug.md&lt;/blockquote&gt;
&lt;pre id=&quot;code_1707975596388&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;---
name:   Bug
about: bug 관련 이슈입니다.
title: ''
labels: ' &amp;zwj; BE,  bug'
assignees: ''
---

##   버그 내용

&amp;lt;!-- 어떤 버그인지 설명해주세요. --&amp;gt;

##   버그 발생 과정

&amp;lt;!-- 어떤 과정을 통해 버그가 발생했는지 자세하게 알려주세요. --&amp;gt;

-

##   스크린샷

&amp;lt;!-- (선택) 버그 발생 화면을 스크린샷으로 남겨주세요. --&amp;gt;

##   참고 사항

&amp;lt;!-- (선택) 버그 발생 환경 등 추가로 전달할 내용이 있다면 작성해주세요. --&amp;gt;&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;style2&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://medium.com/prnd/%ED%97%A4%EC%9D%B4%EB%94%9C%EB%9F%AC-%EA%B0%9C%EB%B0%9C%ED%8C%80-%EB%AA%A8%EB%91%90%EA%B0%80-%ED%96%89%EB%B3%B5%ED%95%9C-%EA%B0%9C%EB%B0%9C-pr%EA%B4%80%EB%A6%AC-%EB%B0%A9%EB%B2%95-7%EA%B0%80%EC%A7%80-1d4cd5d091f0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;효율적인 PR 관리 방법 (헤이딜러 개발팀)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://brunch.co.kr/@mojuns/36&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;백로그와 우선순위 선정&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://yeshyun.tistory.com/17&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://yeshyun.tistory.com/17&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/Git &amp;amp; Github</category>
      <category>git</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/296</guid>
      <comments>https://jollyn.tistory.com/296#entry296comment</comments>
      <pubDate>Fri, 16 Jun 2023 17:57:55 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 데이터 삭제시 Cannot delete or update a parent row: a foreign key constraint fails 에러 해결</title>
      <link>https://jollyn.tistory.com/294</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;에러 원인&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL에서 row를 삭제하려고 하는데 다음과 같은 에러가 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1686826508739&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error Code: 1451. Cannot delete or update a parent row: a foreign key constraint fails&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 삭제하려고 하는 row를 다른 테이블에서 참조하고 있기 때문에 삭제하거나 변경할 수 없다는 것이다.&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;&lt;b&gt;에러 해결&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법1) 참조하는 데이터를 먼저 삭제하고 삭제하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FK로 참조하는 row를 삭제한 뒤 에러가 발생했던 row를 다시 삭제해주면된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이 방법이 가장 안전한 방법으로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;기존 DB 설계자가 의도한 대로 데이터의 관계를 유지할 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법2) 외래키 체크 설정을 해제하기&lt;/h3&gt;
&lt;pre id=&quot;code_1687225697173&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 외래키 체크 해제(0)/설정(1)
set foreign_key_checks=0;
set foreign_key_checks=1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외래키 체크 설정을 해제하고 해당 row를 삭제할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 테이블 간의 관계를 일시적으로 해제하고 데이터를 삭제하는 것이기 때문에 기존 테이블 간의 관계를 보장할 수 없게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 Member의 member_id를 참조하는  Post가 있을때,&lt;br /&gt;member 데이터를 삭제했을 때&amp;nbsp; 해당 member를 참조하는 post 데이터도 사라지도록 foreign key 설정이 되어 있다고 생각해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 이러한 상황에서 외래키 체크 설정을 해제하고 member 데이터를 지운뒤 다시 설정을 활성화 하면 post에는 여전히 member_id 정보가 남게되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 로컬이나 테스트 서버일 때 강제로 데이터를 지워야하는 상황에만 주의하여 사용해야 한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;추가&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외래키 체크를 해제 설정했지만, 또 다른 에러가 발생했다.&lt;/p&gt;
&lt;pre id=&quot;code_1686827763289&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column.  To disable safe mode, toggle the option in Preferences&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찾아보니 이 에러는 update 또는 delete 할 때 where 절이 없을 경우, 즉 한번에 여러 row를 변경할 때 막아주는 Safe Mode가 설정되어 있기 때문에 발생하는 에러였다.&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;Safe Mode를 해제하고 다시 삭제를 진행하니 간단하게 해결되었다!&lt;/p&gt;
&lt;pre id=&quot;code_1686827913355&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- Safe Mode 설정 해제(0)/설정(1)
set sql_safe_updates=0;
set foreign_key_checks=0;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/삽질기록</category>
      <category>mysql</category>
      <category>row 삭제 에러</category>
      <category>에러</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/294</guid>
      <comments>https://jollyn.tistory.com/294#entry294comment</comments>
      <pubDate>Thu, 15 Jun 2023 20:21:40 +0900</pubDate>
    </item>
    <item>
      <title>정적 팩토리 메서드(static factory method)</title>
      <link>https://jollyn.tistory.com/291</link>
      <description>&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;그런데 문득 정적 팩토리 메서드를 왜 사용하는 것인지 정확히 알지 못한채 사용한다는 생각이 들어 정적 팩토리 메서드를 왜 사용해야하는지 한번 정리해보려고 한다.&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;정적 팩토리 메서드란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 팩토리(factory)라는 용어는 GoF 디자인 패턴 중 팩토리 패턴에서 유래한 단어로, 객체를 생성하는 역할을 분리한다는 의미가 담겨 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 정적 팩토리 매서드란 &lt;b&gt;객체 생성의 역할을 하는 클래스 메서드&lt;/b&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접적으로 생성자를 통해 객체 생성을 하는 것이 아니라 객체 생성 역할을 대신해주는 정적 팩토리 메서드를 사용해 객체 생성을 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;왜 생성자 대신에 정적 팩토리 메서드를 통해 객체를 생성하는 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생상자와 정적 팩토리 메서드는 객체를 생성한다는 같은 역할을 하고 있지만, 그 활용도에서 엄청난 차이가 난다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 팩토리 메서드의 장점을 하나하나 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 이름을 가질 수 있다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체는 생성 목적과 과정에 따라 생성자를 구별해서 사용할 필요가 있다.&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;이때 정적 팩토리 메서드를 사용하면 메서드 &lt;b&gt;이름에 객체의 생성 목적을 담을 수 있다&lt;/b&gt;는 장점이 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1686533664013&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LottoFactory() {
    private static final int LOTTO_SIZE = 6;

    private static List&amp;lt;LottoNumber&amp;gt; allLottoNumbers = ...; // 1~45까지의 로또 번호

    public static Lotto createAutoLotto() {
        Collections.shuffle(allLottoNumbers);
        return new Lotto(allLottoNumbers.stream()
                .limit(LOTTO_SIZE)
                .collect(Collectors.toList());

    }

    public static Lotto createManualLotto(List&amp;lt;LottoNumber&amp;gt; lottoNumber) {
        return new Lotto(lottoNumbers);
    }

    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;createAuttoLotto와 createMenualLotto 모두 로또 객체를 생성하고 반환하는 정적 팩토리 메서드이다. 이때 메서드의 이름만으로도 로또 객체를 자동으로 생성하는지, 수동으로 생성하는지 단번에 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 정적 팩토리 메서드를 사용하면 해당 생성의 목적을 이름에 표현할 수 있어 가독성이 좋아지는 효과가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 호출할 때마다 새로운 객체를 생성할 필요가 없다.&lt;/h4&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 id=&quot;code_1686533891160&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class LottoNumber() {
    private static final int MIN_LOTTO_NUMBER = 1;
    private static final int MAX_LOTTO_NUMBER = 45;

    private static Map&amp;lt;Integer, LottoNumber&amp;gt; lottoNumberCache = new HashMap&amp;lt;&amp;gt;();

    static {
        IntStream.range(MIN_LOTTO_NUMBER, MAX_LOTTO_NUMBER)
                 .forEach(i -&amp;gt; lottoNumberCache.put(i, new LottoNumber(i)));
    }

    private int number;

    private LottoNumber(int number) {
        this.number = number;
    }

    public LottoNumber of(int number) { // LottoNumber를 반환하는 정적 팩토리 메서드
        return lottoNumberCache.get(number);
    }

    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제에서는 1~45까지의 로또 번호는 enum으로도 만들 수 있지만 반복문을 통해 쉽게 45개의 인스턴스를 만들 수 있으므로 반복문을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 미리 생성된 로또 번호 객체의 캐싱을 통해 새로운 객체 생성의 부담을 덜 수 있다는 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 생성자의 접근 제한자를 private으로 설정해 &lt;b&gt;객체 생성을 정적 팩토리 메서드로만 가능하도록 제한&lt;/b&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;3. 객체 생성을 캡슐화할 수 있다.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 팩토리 메서드는 객체 생성을 캡슐화하는 방법이기도 하다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;캡슐화(Encapsulization)&lt;/b&gt;&lt;br /&gt;&amp;bull; 데이터 은닉&lt;br /&gt;&amp;bull; 여기서는 생성자를 클래스의 메서드 안으로 숨기면서 내부 상태를 외부에 드러낼 필요없이 객체 생성 인터페이스를 단순화 시킬 수 있다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 애플리케이션을 개발하다보면 계층 간 데이터를 전송하기 위한 객체로 DTO(Data Transfer Object)를 정의해서 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DTO와 Entity간에는 자유롭게 형 변환이 가능해야 하는데, 이때 정적 팩토리 메서드를 사용하면 내부 구현을 모르더라도 쉽게 변환할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1686534579408&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public calss CarDTO {
    private String name;
    private int position;

    public static CarDto from(Car car) {
        return new CarDto(car.getName(), car.getPosition());
    }
}

// Car &amp;rarr; CarDto 변환
CarDto carDto = CarDto.from(car); // 정적 팩토리 메서드를 사용한 경우
CarDto carDto = new CarDto(car.getName(), car.getPosition()); // 생성자를 사용한 경우&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 팩토리를 쓰지 않고 DTO로 변환한다면 외부에서 생성자의 내부 구현을 모두 드러내야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 정적 팩토리 메서드는 단순히 생성자의 역할을 대신하는 것 뿐만 아니라, 좀 더 가독성 좋은 코드를 작성하고 객체지향적으로 프로그래밍 할 수 있도록 도와 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;도메인에서 &quot;객체 생성&quot;의 역할 자체가 중요한 경우라면 정적 팩토리 클래스를 따로 분리하는 것도 좋은 방법이 될 수 있다. 다만 팩토리 메서드만 존재하는 클래스를 생성할 경우 상속이 불가하다는 단점이 있으니 참고하여 사용해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확실한 것은 정적 팩토 메서드를 적절히 사용했을 때 얻을 수 있는 장점이 더욱 많다는 것이다. 객체간 형 변환이 필요하거나, 여러 번의 객체 생성이 필요한 경우라면 생성자보다는 정적 팩토리 메서드를 사용해보도록 하자!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;정적 팩토리 메서드 네이밍 컨벤션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정적 팩토리 메서드를 만드는데 있어 일반적으로 많이 사용되는 네이킹 컨벤션이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 77.6738%; height: 107px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 24.3023%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;메서드&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 53.3721%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;설명&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 24.3023%; height: 18px; text-align: center;&quot;&gt;from&lt;/td&gt;
&lt;td style=&quot;width: 53.3721%; height: 18px; text-align: center;&quot;&gt;하나의 매개변수를 받아 객체를 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 24.3023%; height: 18px; text-align: center;&quot;&gt;of&lt;/td&gt;
&lt;td style=&quot;width: 53.3721%; height: 18px; text-align: center;&quot;&gt;여러개의 매개변수를 받아 객체를 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 24.3023%; height: 18px; text-align: center;&quot;&gt;newInstance | Create&lt;/td&gt;
&lt;td style=&quot;width: 53.3721%; height: 18px; text-align: center;&quot;&gt;새로운 인스턴스를 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 24.3023%; height: 18px; text-align: center;&quot;&gt;get[other type]&lt;/td&gt;
&lt;td style=&quot;width: 53.3721%; height: 18px; text-align: center;&quot;&gt;다른 타입의 인스턴스를 생성, 이전에 반환했던 것과 같을 수 있음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 24.3023%; height: 18px; text-align: center;&quot;&gt;new[other type]&lt;/td&gt;
&lt;td style=&quot;width: 53.3721%; height: 18px; text-align: center;&quot;&gt;다른 타입의 새로운 인스턴스를 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Reference&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tecoble.techcourse.co.kr/post/2020-05-26-static-factory-method/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;정적 팩토리 메서드는 왜 사용할까?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@saint6839/%EC%A0%95%EC%A0%81-%ED%8C%A9%ED%86%A0%EB%A6%AC-%EB%A9%94%EC%84%9C%EB%93%9C-%EB%84%A4%EC%9D%B4%EB%B0%8D-%EB%B0%A9%EC%8B%9D&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;정적 팩토리 메서드 네이밍 방식&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>☕ Java/이론</category>
      <category>static factory method</category>
      <category>정적 팩토리 메서드</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/291</guid>
      <comments>https://jollyn.tistory.com/291#entry291comment</comments>
      <pubDate>Mon, 12 Jun 2023 10:54:43 +0900</pubDate>
    </item>
    <item>
      <title>트랜잭션 전파</title>
      <link>https://jollyn.tistory.com/290</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은 &lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[인프런] 스프링 DB 1편 - 데이터 접근 핵심 원리&lt;/a&gt;&amp;nbsp;강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션 커밋, 롤백&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 전파에 대해 알아보기 이전에 간단한 트랜잭션 코드를 통해 트랜잭션이 어떻게 동작하는지 확인해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1686117974240&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@SpringBootTest
class BasicTxTest {
    @Autowired PlatformTransactionManager txManager;

    @TestConfiguration
    static class Config {
        @Bean
        public PlatformTransactionManager transactionManager(DataSource dataSource) {
            return new DataSourceTransactionManager(dataSource);
        }
    }

    @Test
    void commit() {
        log.info(&quot;트랜잭션 시작&quot;);
        TransactionStatus status = txManager.getTransaction(new DefaultTransactionAttribute());

        log.info(&quot;트랜잭션 커밋 시작&quot;);
        txManager.commit(status);
        log.info(&quot;트랜잭션 커밋 완료&quot;);
    }

    @Test
    void rollback() {
        log.info(&quot;트랜잭션 시작&quot;);
        TransactionStatus status = txManager.getTransaction(new DefaultTransactionAttribute());

        log.info(&quot;트랜잭션 롤백 시작&quot;);
        txManager.rollback(status);
        log.info(&quot;트랜잭션 롤백 완료&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;txManager.getTransaction(new DefaultTransactionAttribute() : 트랜잭션 매니저를 통해 트랜잭션을 시작(획득)한다.&lt;/li&gt;
&lt;li&gt;txManager.commit(status) : 트랜잭션을 커밋한다.&lt;/li&gt;
&lt;li&gt;txManager.rollback(status) : 트랜잭션을 롤백한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 트랜잭션이 둘 이상 있다면 어떻게 동작할까?&lt;/p&gt;
&lt;pre id=&quot;code_1686101498174&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
void double_commit() {
    log.info(&quot;트랜잭션1 시작&quot;);
    TransactionStatus tx1 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info(&quot;트랜잭션1 커밋&quot;);
    txManager.commit(tx1);

    log.info(&quot;트랜잭션2 시작&quot;);
    TransactionStatus tx2 = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info(&quot;트랜잭션1 커밋&quot;);
    txManager.commit(tx2);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2494&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzHlar/btsiOetIWux/SypkVH0tL47dsQlG8BPITK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzHlar/btsiOetIWux/SypkVH0tL47dsQlG8BPITK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzHlar/btsiOetIWux/SypkVH0tL47dsQlG8BPITK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzHlar%2FbtsiOetIWux%2FSypkVH0tL47dsQlG8BPITK%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;2494&quot; height=&quot;714&quot; data-origin-width=&quot;2494&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력된 로그를 보면, 트랜잭션1이 완전히 끝나고나서 트랜잭션2가 수행되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Acquired Connection [Hikari... wrapping conn0] for JDBC transaction : 트랜잭션을 시작하고, 커넥션 풀에서 conn0 커넥션 획득&lt;/li&gt;
&lt;li&gt;Releasing JDBC Connenction [Hikari... wrapping conn0] after transaction : 트랜잭션을 커밋하고, 커넥션 풀에 conn0 커넥션을 반납&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘 이상의 트랜잭션이 동작하는 과정을 정리하자면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;744&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L3XzY/btsiPOHQ5ea/d1hy0PdhH4pWNEwCLgd0F0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L3XzY/btsiPOHQ5ea/d1hy0PdhH4pWNEwCLgd0F0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L3XzY/btsiPOHQ5ea/d1hy0PdhH4pWNEwCLgd0F0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL3XzY%2FbtsiPOHQ5ea%2Fd1hy0PdhH4pWNEwCLgd0F0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;344&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;744&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 각각 수행되면서 사용되는 DB 커넥션도 서로 다르다.&lt;/li&gt;
&lt;li&gt;이 경우 트랜잭션을 각자 관리하기 때문에 &lt;b&gt;전체 트랜잭션을 묶을 수 없다. &lt;/b&gt;&lt;/li&gt;
&lt;li&gt;예를 들어 트랜잭션1이 커밋하고, 트랜잭션2가 롤백하는 경우 트랜잭션1에서 저장한 데이터는 커밋되고, 트랜잭션2에서 저장한 데이터는 롤백된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션 전파&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 트랜잭션을 각각 사용하는 게 아니라 이미 진행중인 트랜잭션에 추가로 트랜잭션을 수행하면 어떻게 될까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 어떻게 동작할지 결정하는 것을 &lt;b&gt;트랜잭션 전파&lt;/b&gt;(propagation)라고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 다양한 트랜잭션 전파 옵션을 제공하는데, 우선 기본 옵션인 REQUIRED를 기준으로 알아보도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;248&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkBKh4/btsiOffa7l0/TDGdkYO1Cmiw1McgXm0jpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkBKh4/btsiOffa7l0/TDGdkYO1Cmiw1McgXm0jpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkBKh4/btsiOffa7l0/TDGdkYO1Cmiw1McgXm0jpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkBKh4%2FbtsiOffa7l0%2FTDGdkYO1Cmiw1McgXm0jpk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;115&quot; data-origin-width=&quot;1074&quot; data-origin-height=&quot;248&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CaPJr/btsiOI2e1Yc/HxNXhg2RFfTaNHeKqvNANk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CaPJr/btsiOI2e1Yc/HxNXhg2RFfTaNHeKqvNANk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CaPJr/btsiOI2e1Yc/HxNXhg2RFfTaNHeKqvNANk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCaPJr%2FbtsiOI2e1Yc%2FHxNXhg2RFfTaNHeKqvNANk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;190&quot; data-origin-width=&quot;1076&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&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;외부 트랜잭션과 내부 트랜잭션을 묶어서 하나의 트랜잭션을 만들어주며&lt;/b&gt;, 내부 트랜잭션이 외부 트랜잭션에 참여해 동작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n8zUe/btsiU5IOH4X/zd7PElBxXfKerjbmwQ40c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n8zUe/btsiU5IOH4X/zd7PElBxXfKerjbmwQ40c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n8zUe/btsiU5IOH4X/zd7PElBxXfKerjbmwQ40c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn8zUe%2FbtsiU5IOH4X%2Fzd7PElBxXfKerjbmwQ40c0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;410&quot; data-origin-width=&quot;1078&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 스프링은 이해를 돕기 위해 &lt;b&gt;논리 트랜잭션&lt;/b&gt;과 &lt;b&gt;물리 트랜잭션&lt;/b&gt;이라는 개념을 나눈다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;논리 트랜잭션 vs 물리 트랜잭션&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;논리 트랜잭션&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 트랜잭션 매니저를 통해 트랜잭션을 사용하는 단위, 논리 트랜잭션은 트랜잭션이 진행되는 중에 내부에 추가로 트랜잭션을 사용하는 경우에 나타남 (단순히 트랜잭션이 하나인 경우에는 둘을 구분하지 않음)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;물리 트랜잭션&lt;/b&gt; : 실제 데이터베이스에 적용되는 트랜잭션, 실제 커넥션을 통해 트랜잭션을 시작(setAutoCommit(false))하고 커밋 또는 롤백하는 단위&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논리 트랜잭션은 하나의 물리 트랜잭션으로 묶이며, 원칙은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;모든 논리 트랜잭션이 커밋&lt;/b&gt;되어야 &lt;b&gt;물리 트랜잭션이 커밋&lt;/b&gt;된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;하나의 논리 트랜잭션이라도 롤백&lt;/b&gt;되면 &lt;b&gt;물리 트랜잭션은 롤백&lt;/b&gt;된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제를 통해 여러가지 상황에서 어떻게 동작하는지 확인해보자.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;내부 커밋&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1686106157566&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
void inner_commit() {
    log.info(&quot;외부 트랜잭션 시작&quot;);
    TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info(&quot;outer.isNewTransaction()={}&quot;, outer.isNewTransaction()); // true

    log.info(&quot;내부 트랜잭션 시작&quot;);
    TransactionStatus inner = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info(&quot;inner.isNewTransaction()={}&quot;, inner.isNewTransaction()); // false
    log.info(&quot;내부 트랜잭션 커밋&quot;);
    txManager.commit(inner);

    log.info(&quot;외부 트랜잭션 커밋&quot;);
    txManager.commit(outer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dLPYZl/btsiU4SaLzE/lICsSBgSIKTi6KgVNkH9YK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dLPYZl/btsiU4SaLzE/lICsSBgSIKTi6KgVNkH9YK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dLPYZl/btsiU4SaLzE/lICsSBgSIKTi6KgVNkH9YK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdLPYZl%2FbtsiU4SaLzE%2FlICsSBgSIKTi6KgVNkH9YK%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;2464&quot; height=&quot;574&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2464&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션은 처음 수행된 트랜잭션으로 신규 트랜잭션이 된다.(isNewTansaction=true)&lt;/li&gt;
&lt;li&gt;내부 트랜잭션을 시작하는 시점에 이미 외부 트랜잭션이 진행중인 상태이므로 내부 트랜잭션은 외부 트랜잭션에 참여하며, 이 경우 신규 트랜잭션이 아니다. (isNewTransaction=false)&lt;/li&gt;
&lt;li&gt;외부 트랜잭션을 시작하거나 커밋할 때는 DB 커넥션을 통한 물리 트랜잭션을 시작, 커밋하는 로그를 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;내부 트랜잭션을 시작하거나 커밋할 때는 DB 커넥션을 통해 커밋하는 로그를 전혀 확인할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 내부 트랜잭션이 실제 물리 트랜잭션을 커밋한다면 트랜잭션이 끝나버리기 때문에 트랜잭션을 시작한 외부 트랜잭션까지 이어갈 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 내부 트랜잭션은 DB 커넥션을 통한 물리 트랜잭션을 커밋하면 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 이러한 중복 커밋 문제를 해결하기 위해 여러 트랜잭션이 함께 사용되는 경우 &lt;b&gt;처음 트랜잭션을 시작한 외부 트랜잭션이 실제 물리 트랜잭션을 관리&lt;/b&gt;하도록 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;❔ 내부 트랜잭션이 외부 트랜잭션에 참여한다는 의미&lt;br /&gt;&amp;bull; 내부 트랜잭션이 외부 트랜잭션을 그대로 이어 받아 따른다는 뜻&lt;br /&gt;&amp;bull; 외부에서 시작된 물리 트랜잭션의 범위가 내부 트랜잭션까지 넓어진다는 뜻&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 전파가 동작하는 과정을 정리하자면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz2erf/btsi0ZPYTr5/QQr485EAgLegsJAMCXfkw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz2erf/btsi0ZPYTr5/QQr485EAgLegsJAMCXfkw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz2erf/btsi0ZPYTr5/QQr485EAgLegsJAMCXfkw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz2erf%2Fbtsi0ZPYTr5%2FQQr485EAgLegsJAMCXfkw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;274&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션 요청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;txManager.getTransacion()를 호출해 외부 트랜잭션을 시작&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 데이터소스를 통해 커넥션을 생성&lt;/li&gt;
&lt;li&gt;생성한 커넥션을 수동 커밋 모드(setAutoCommit(false))로 설정하며 &lt;b&gt;물리 트랜잭션을 시작&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 트랜잭션 동기화 매니저에 커넥션을 보관&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 트랜잭션을 생성한 결과를 Transaction에 담아 반환하는데, 여기에 신규 트랜잭션 여부가 담겨있어 isNewTransaction()을 통해 확인 가능&lt;/li&gt;
&lt;li&gt;로직1이 사용되고, 커넥션이 필요한 경우 트랜잭션 동기화 매니저를 통해 트랜잭션이 적용된 커넥션을 획득하여 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;내부 트랜잭션 요청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;txManager.getTransaction()을 호출해 내부 트랜잭션을 시작&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 트랜잭션 동기화 매니저를 통해 기존 트랜잭션이 존재하는지 확인&lt;/li&gt;
&lt;li&gt;존재하면, 새로운 커넥션을 생성하지 않고 기존 트랜잭션에 참여&lt;/li&gt;
&lt;li&gt;기존 트랜잭션에 참여했기 때문에 isNewTransaction() 결과가 false&lt;/li&gt;
&lt;li&gt;로직2가 사용되고, 커넥션이 필요한 경우 트랜잭션 동기화 매니저를 통해 외부 트랜잭션이 보관한 커넥션을 획득하여 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;576&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MzlPW/btsi10VAQEa/Gfr4aqJ4e5Uj5YKonjW0Hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MzlPW/btsi10VAQEa/Gfr4aqJ4e5Uj5YKonjW0Hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MzlPW/btsi10VAQEa/Gfr4aqJ4e5Uj5YKonjW0Hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMzlPW%2Fbtsi10VAQEa%2FGfr4aqJ4e5Uj5YKonjW0Hk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;274&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;576&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부 트랜잭션 응답
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로직2가 끝나고 트랜잭션 매니저를 통해 내부 트랜잭션을 커밋&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 커밋 시점에 신규 트랜잭션 여부에 따라 다르게 동작, 내부 트랜잭션은 신규 트랜잭션이 아니기 때문에 &lt;b&gt;실제 커밋을 호출하지 않음&lt;/b&gt; (물리 트랜잭션은 외부 트랜잭션이 종료될 때까지 이어져야 함)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 트랜잭션 응답
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로직1이 끝나고 트랜잭션 매니저를 통해 외부 트랜잭션을 커밋&lt;/li&gt;
&lt;li&gt;외부 트랜잭션은 신규 트랜잭션이기 때문에 &lt;b&gt;DB 커넥션에 실제 커밋을 호출&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;실제 데이터베이스에 커밋이 반영되고, 물리 트랜잭션이 끝남&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;외부 롤백&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내부 트랜잭션은 커밋되는데, 외부 트랜잭션이 롤백되는 상황에 대해 알아보자.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bw53Gm/btsi2hiCVzG/YFa9aGtEOxe3tq1EBHqIc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bw53Gm/btsi2hiCVzG/YFa9aGtEOxe3tq1EBHqIc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bw53Gm/btsi2hiCVzG/YFa9aGtEOxe3tq1EBHqIc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbw53Gm%2Fbtsi2hiCVzG%2FYFa9aGtEOxe3tq1EBHqIc1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;195&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;410&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/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 id=&quot;code_1686121173256&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
void outer_rollback() {
    log.info(&quot;외부 트랜잭션 시작&quot;);
    TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());

    log.info(&quot;내부 트랜잭션 시작&quot;);
    TransactionStatus inner = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info(&quot;내부 트랜잭션 커밋&quot;);
    txManager.commit(inner);

    log.info(&quot;외부 트랜잭션 롤백&quot;);
    txManager.rollback(outer);
}&lt;/code&gt;&lt;/pre&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;2490&quot; data-origin-height=&quot;494&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRLBCg/btsi3WrdH6v/kRNcAnnkgfPppRApceQmb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRLBCg/btsi3WrdH6v/kRNcAnnkgfPppRApceQmb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRLBCg/btsi3WrdH6v/kRNcAnnkgfPppRApceQmb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRLBCg%2Fbtsi3WrdH6v%2FkRNcAnnkgfPppRApceQmb1%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;2490&quot; height=&quot;494&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2490&quot; data-origin-height=&quot;494&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션이 물리 트랜잭션을 시작하고 롤백하는 것을 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;내부 트랜잭션은 앞서 말한대로 직접 물리트랜잭션에 관여하지 않는다.&lt;/li&gt;
&lt;li&gt;결과적으로 외부 트랜잭션에서 시작한 물리 트랜잭션의 범위가 내부 트랜잭션까지 사용되며, &lt;b&gt;외부 트랜잭션이 롤백되면서 전체 내용은 모두 롤백&lt;/b&gt;된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;내부 롤백&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번엔 내부 트랜잭션은 모두 롤백되는데, 외부 트랜잭션이 커밋되는 상황이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;412&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgxny0/btsiZXdWib1/foueWZeuNpNqzwOFqRdus1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgxny0/btsiZXdWib1/foueWZeuNpNqzwOFqRdus1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgxny0/btsiZXdWib1/foueWZeuNpNqzwOFqRdus1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgxny0%2FbtsiZXdWib1%2FfoueWZeuNpNqzwOFqRdus1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;196&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;412&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/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 id=&quot;code_1686122941462&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
void inner_rollback() {
    log.info(&quot;외부 트랜잭션 시작&quot;);
    TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());

    log.info(&quot;내부 트랜잭션 시작&quot;);
    TransactionStatus inner = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info(&quot;내부 트랜잭션 롤백&quot;);
    txManager.rollback(inner);

    log.info(&quot;외부 트랜잭션 커밋&quot;);
    txManager.commit(outer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;534&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KxRvA/btsi4MPo8JQ/Ob9huXdwv4BFu4RE1Or9F1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KxRvA/btsi4MPo8JQ/Ob9huXdwv4BFu4RE1Or9F1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KxRvA/btsi4MPo8JQ/Ob9huXdwv4BFu4RE1Or9F1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKxRvA%2Fbtsi4MPo8JQ%2FOb9huXdwv4BFu4RE1Or9F1%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;2130&quot; height=&quot;534&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;2130&quot; data-origin-height=&quot;534&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부 트랜잭션 롤백
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Participating transaction failed - making existing transaction as rollback-only&lt;/li&gt;
&lt;li&gt;내부 트랜잭션을 롤백하면 실제 물리 트랜잭션은 롤백하지 않는다. 대신 &lt;b&gt;기존 트랜잭션을 롤백 전용으로 표시&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 트랜잭션 커밋
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Global transaction is marked as rollback-only&lt;/li&gt;
&lt;li&gt;커밋을 호출했지만, &lt;b&gt;전체 트랜잭션이 롤백 전용으로 표시되어 있어 물리 트랜잭션을 롤백&lt;/b&gt;한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 전파가 동작하는 과정을 정리하자면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;616&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Yaqrm/btsi10IqTTI/2mNXcyoba6PqkLlOtvjaRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Yaqrm/btsi10IqTTI/2mNXcyoba6PqkLlOtvjaRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Yaqrm/btsi10IqTTI/2mNXcyoba6PqkLlOtvjaRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYaqrm%2Fbtsi10IqTTI%2F2mNXcyoba6PqkLlOtvjaRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;616&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부 트랜잭션 응답
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로직2가 끝나고 트랜잭션 매니저를 통해 내부 트랜잭션을 롤백&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 롤백 시점에 신규 트랜잭션 여부에 따라 다르게 동작, 내부 트랜잭션의 경우 신규 트랜잭션이 아니기 때문에 실제 롤백을 호출하지 않음&lt;/li&gt;
&lt;li&gt;내부 트랜잭션은 물리 트랜잭션을 롤백하지 않는 대신에 &lt;b&gt;트랜잭션 동기화 매니저에 rollbackOnly=true 표시&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 트랜잭션 응답
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로직1이 끝나고 트랜잭션 매니저를 통해 외부 트랜잭션을 커밋&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 커밋 시점에 신규 트랜잭션 여부에 따라 다르게 동작, 외부 트랜잭션의 경우 신규 트랜잭션이기 때문에 DB 커넥션에 실제 커밋을 호출해야 함&lt;/li&gt;
&lt;li&gt;실제 커밋을 호출하기 이전에 트랜잭션 동기화 매니저에 &lt;b&gt;롤백 전용 표시(rollbackOnly=true)가 있는지 확인&lt;/b&gt;, 있으면 물리 트랜잭션을 커밋하지 않고 &lt;b&gt;롤백&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;실제 데이터베이스에 롤백이 반영되고, 물리 트랜잭션 종료&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저에 커밋을 호출한 개발자 입장에서는 커밋을 기대했지만 롤백 전용 표시로 인해 실제로는 기대하지 않은 롤백이 되었기 때문에 &lt;b&gt;UnexpectedRollbackException&lt;/b&gt; 예외 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;논리 트랜잭션이 하나라도 롤백되면 물리 트랜잭션은 롤백된다.&lt;/li&gt;
&lt;li&gt;내부 논리 트랜잭션이 롤백되면 롤백 전용 마크(rollbackOnly=true)를 표시한다.&lt;/li&gt;
&lt;li&gt;외부 트랜잭션을 커밋할 때 롤백 전용 마크를 확인해, 표시되어 있으면 물리 트랜잭션을 롤백한 뒤 UnexpectedRollbackException 예외를 던진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션 전파 옵션&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 다양한 트랜잭션 전파 옵션을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 별도의 설정을 하지 않으면 기본적으로 REQUIRED가 사용된다.&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;실무에서는 대부분 REQUIRED 옵션을 사용하고, 아주 가끔 REQUIRES_NEW 옵션을 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나머지 옵션은 거의 사용하지 않아 가볍게 알아두고 필요할 때 찾아보면 된다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 75.233%; height: 237px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;옵션&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; height: 18px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; height: 37px; text-align: center;&quot;&gt;REQUIRED&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; height: 37px; text-align: left;&quot;&gt;기존 트랜잭션 없음 : 새로운 트랜잭션 생성&lt;br /&gt;기존 트랜잭션 있음 : 기존 트랜잭션 참여&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; height: 37px; text-align: center;&quot;&gt;REQUIRES_NEW&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; height: 37px; text-align: left;&quot;&gt;기존 트랜잭션 없음 : 새로운 트랜잭션 생성&lt;br /&gt;기존 트랜잭션 있음 : 새로운 트랜잭션 생성&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; height: 17px; text-align: center;&quot;&gt;SUPPROT&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; height: 17px; text-align: left;&quot;&gt;기존 트랜잭션 없음 : 트랜잭션 없이 진행&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존 트랜잭션 있음 :&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기존 트랜잭션 참여&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; height: 17px; text-align: center;&quot;&gt;NOT_SUPPROT&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; height: 17px; text-align: left;&quot;&gt;기존 트랜잭션 없음 : 트랜잭션 없이 진행&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존 트랜잭션 있음 :&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;트랜잭션 없이 진행 (&lt;/span&gt;기존 트랜잭션 보류)&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; text-align: center; height: 37px;&quot;&gt;MANDATORY&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; text-align: left; height: 37px;&quot;&gt;기존 트랜잭션 없음 : IllegalTrassactionStateException 예외 발생&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존 트랜잭션 있음 :&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;기존 트랜잭션 참여&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; text-align: center; height: 37px;&quot;&gt;NEVER&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; text-align: left; height: 37px;&quot;&gt;기존 트랜잭션 없음 : 트랜잭션 없이 진행&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존 트랜잭션 있음 :&lt;span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;IllegalTrassactionStateException 예외 발생&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 37px;&quot;&gt;
&lt;td style=&quot;width: 21.89%; text-align: center; height: 37px;&quot;&gt;NESTED&lt;/td&gt;
&lt;td style=&quot;width: 50.976%; text-align: left; height: 37px;&quot;&gt;기존 트랜잭션 없음 : 새로운 트랜잭션 생성&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;기존 트랜잭션 있음 :&lt;span&gt;&lt;span&gt;&amp;nbsp;중첩 트랜잭션 생성&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;REQUIRES_NEW&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;외부 트랜잭션과 내부 트랜잭션을 완전히 분리해서 각각 별도의 물리 트랜잭션을 사용하는 방법이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;508&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWy7Is/btsi2emc0b9/AWkQvD8axrKKualNWsSuw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWy7Is/btsi2emc0b9/AWkQvD8axrKKualNWsSuw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWy7Is/btsi2emc0b9/AWkQvD8axrKKualNWsSuw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWy7Is%2Fbtsi2emc0b9%2FAWkQvD8axrKKualNWsSuw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;241&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;508&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;물리 트랜잭션을 분리하려면 내부 트랜잭션을 시작할 때 REQUIRES_NEW 옵션을 주면 된다.&lt;/li&gt;
&lt;li&gt;외부 트랜잭션과 내부 트랜잭션이 각각 별도의 물리 트랜잭션을 가짐 (DB 커넥션을 따로 사용)&lt;/li&gt;
&lt;li&gt;커밋과 롤백이 각각 별도로 이뤄져 내부 트랜잭션에 문제가 발생해 롤백하더라도 외부 트랜잭션에 영향을 주지 않음&lt;/li&gt;
&lt;li&gt;로직2는 롤백되고, 로직1은 커밋된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로 알아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1686127600294&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
void inner_rollback_requires_new() {
    log.info(&quot;외부 트랜잭션 시작&quot;);
    TransactionStatus outer = txManager.getTransaction(new DefaultTransactionAttribute());
    log.info(&quot;outer.isNewTransaction()={}&quot;, outer.isNewTransaction());

    log.info(&quot;내부 트랜잭션 시작&quot;);
    DefaultTransactionAttribute definition = new DefaultTransactionAttribute();
    definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); // 항상 새로운 트랜잭션 사용
    TransactionStatus inner = txManager.getTransaction(definition);
    log.info(&quot;inner.isNewTransaction()={}&quot;, inner.isNewTransaction());

    log.info(&quot;내부 트랜잭션 롤백&quot;);
    txManager.rollback(inner);

    log.info(&quot;외부 트랜잭션 커밋&quot;);
    txManager.commit(outer);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;2234&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTzw0W/btsi4bV9x3j/wKgbkkiBpWdJ69kzNu6rHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTzw0W/btsi4bV9x3j/wKgbkkiBpWdJ69kzNu6rHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTzw0W/btsi4bV9x3j/wKgbkkiBpWdJ69kzNu6rHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTzw0W%2Fbtsi4bV9x3j%2FwKgbkkiBpWdJ69kzNu6rHK%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;2234&quot; height=&quot;750&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;2234&quot; data-origin-height=&quot;750&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션 시작
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션을 시작해 conn0을 획득하고 manual commit으로 변경해 물리 트랜잭션을 시작한다.&lt;/li&gt;
&lt;li&gt;외부 트랜잭션은 신규 트랜잭션이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;내부 트랜잭션 시작
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부 트랜잭션 시작 시 전파 옵션으로 PROPAGATION_REQUIRES_NEW 옵션을 사용하면 내부 트랜잭션을 시작할 때 기존 트랜잭션에 참여하는 것이 아니라 새로운 물리 트랜잭션을 만들어서 시작한다.&lt;/li&gt;
&lt;li&gt;따라서 기존에 있는 conn0은 잠시 미뤄두고(Suspending), 새로운 conn1을 획득하여 manual commit으로 변경해 물리 트랜잭션을 시작한다.&lt;/li&gt;
&lt;li&gt;내부 트랜잭션도 완전히 새로운 신규 트랜잭션으로 생성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;내부 트랜잭션 롤백
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부 트랜잭션이 신규 트랜잭션이므로 실제 물리 트랜잭션(conn1)을 롤백한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 트랜잭션 커밋
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션이 신규 트랜잭션이므로 실제 물리 트랜잭션(conn0)을 커밋한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션 전파가 동작하는 과정을 정리하자면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;622&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ox3wb/btsiWSKXOgp/MWhfqMWhXpbFDk9KPzzBnK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ox3wb/btsiWSKXOgp/MWhfqMWhXpbFDk9KPzzBnK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ox3wb/btsiWSKXOgp/MWhfqMWhXpbFDk9KPzzBnK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOx3wb%2FbtsiWSKXOgp%2FMWhfqMWhXpbFDk9KPzzBnK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;295&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;622&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션 요청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션을 통해 물리 트랜잭션을 시작한다.&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 커넥션을 생성하고 수동 커밋 모드로 설정해 물리 트랜잭션을 시작한다.&lt;/li&gt;
&lt;li&gt;트랜잭션 동기화 매니저에 커넥션을 보관한다.&lt;/li&gt;
&lt;li&gt;로직1 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;내부 트랜잭션 요청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;REQUIRES_NEW 옵션과 함께 내부 트랜잭션을 시작한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 매니저는 옵션을 확인하고, 기존 트랜잭션에 참여하는 것이 아니라 새로운 트랜잭션을 시작한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;트랜잭션 매니저는 커넥션을 생성하고 수동 커밋 모드로 설정해 물리 트랜잭션을 시작한다.&lt;/li&gt;
&lt;li&gt;트랜잭션 동기화 매니저에 커넥션을 보관한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때 con1은 잠시 보류되고, con2가 사용된다. (내부 트랜잭션을 완료할 때까지 con2 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;로직2 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bBWyCI/btsi3wGlKBj/xksFqtenyofM9aO7lehBN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bBWyCI/btsi3wGlKBj/xksFqtenyofM9aO7lehBN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bBWyCI/btsi3wGlKBj/xksFqtenyofM9aO7lehBN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbBWyCI%2Fbtsi3wGlKBj%2FxksFqtenyofM9aO7lehBN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;288&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부 트랜잭션 응답
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;로직2가 끝나면 트랜잭션 매니저를 통해 내부 트랜잭션을 롤백한다.&lt;/li&gt;
&lt;li&gt;내부 트랜잭션이 신규 트랜잭션이므로 실제 롤백을 호출한다.&lt;/li&gt;
&lt;li&gt;내부 트랜잭션이 con2 물리 트랜잭션을 롤백하고, con2는 종료되거나 커넥션 풀에 반납된다.&lt;/li&gt;
&lt;li&gt;con1의 보류가 끝나고 다시 con1을 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 트랜잭션 응답
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부 트랜잭션에 커밋을 요청한다.&lt;/li&gt;
&lt;li&gt;외부 트랜잭션은 신규 트랜잭션이므로 물리 트랜잭션을 커밋한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이때 rollbackOnly 설정을 확인한다. 없으므로 커밋한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 트랜잭션이 con1 물리 트랜잭션을 커밋하고,&amp;nbsp; con1은 종료되거나 커넥션 풀에 반납된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/DB 접근기술</category>
      <category>propagation</category>
      <category>spring</category>
      <category>transaction</category>
      <category>트랜잭션 전파</category>
      <category>트랜잭션이 둘 이상일 때</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/290</guid>
      <comments>https://jollyn.tistory.com/290#entry290comment</comments>
      <pubDate>Wed, 7 Jun 2023 10:06:17 +0900</pubDate>
    </item>
    <item>
      <title>트랜잭션 이해하기</title>
      <link>https://jollyn.tistory.com/280</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은 &lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[인프런] 스프링 DB 2편 - 데이터 접근 활용 기술&lt;/a&gt;&amp;nbsp;강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;스프링 트랜잭션&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 트랜잭션 사용 방식&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 선언적 트랜잭션 관리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Transactional 애노테이션을 선언해 트랜잭션을 적용&lt;/li&gt;
&lt;li&gt;해당 로직에 트랜잭션을 적용하겠다고 선언하기만 하면 트랜잭션이 적용되는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 프로그래밍 방식 트랜잭션 관리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 매니저 또는 트랜잭션 템플릿 등을 사용해 트랜잭션 관련 코드를 직접 작성하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그래밍 방식의 트랜잭션 관리를 사용하면, 애플리케이션 코드가 트랜잭션이라는 기술 코드와 강하게 결합되기 때문에&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서는 &lt;b&gt;대부분 선언적 트랜잭션 관리를 사용&lt;/b&gt;한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링이 제공하는 트랜잭션 AOP&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링은 트랜잭션 AOP를 처리하기 위한 모든 기능을 제공한다. 스프링 부트를 사용하면 트랜잭션 AOP를 처리하기 위해 필요한 스프링 빈들도 자동으로 등록해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 개발자는 트랜잭션 처리가 필요한 곳에&amp;nbsp;@Transactional 애노테이션만 붙이면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링의 트랜잭션 AOP는 이 애노테이션을 인식해 트랜잭션을 처리하는 프록시를 적용해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  프록시 도입 전&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ETOcm/btsahKufSXL/Kkw6WAIbIvHBeHHCAp14TK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ETOcm/btsahKufSXL/Kkw6WAIbIvHBeHHCAp14TK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ETOcm/btsahKufSXL/Kkw6WAIbIvHBeHHCAp14TK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FETOcm%2FbtsahKufSXL%2FKkw6WAIbIvHBeHHCAp14TK%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;450&quot; height=&quot;192&quot; data-origin-width=&quot;766&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1681558056080&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Service {
    public void logic() {
        // 트랜잭션 시작
        TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

        try {
            // 비즈니스 로직
            bizLogin(fromId, toId, money);
            transactionManager.commit(status); // 성공시 커밋
        } catch (Exception e) {
            transactionManager.rollback(status); // 실패시 롤백
            throw new IllegalStateException(e);
        }
    }
}&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;&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGKux8/btsakcQ38rg/KsqKFeV5akmOYlxBZttrR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGKux8/btsakcQ38rg/KsqKFeV5akmOYlxBZttrR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGKux8/btsakcQ38rg/KsqKFeV5akmOYlxBZttrR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGKux8%2FbtsakcQ38rg%2FKsqKFeV5akmOYlxBZttrR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;155&quot; data-origin-width=&quot;1240&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1681559351194&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TransactionProxy {
    private MemberService target;

    public void logic() { //트랜잭션 시작
        TransactionStatus status = transactionManager.getTransaction(..);

        try {
            //실제 대상 호출 target.logic();
            transactionManager.commit(status); //성공시 커밋 } 
        catch (Exception e) {
            transactionManager.rollback(status); //실패시 롤백
            throw new IllegalStateException(e);
        }
    } 
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1681559125513&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Service {
    public void logic() {
        // 트랜잭션 관련 코드 제거, 순수 비즈니스 로직만 남음
        bizLogic(fromId, toId, money);
    }
}&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;&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1230&quot; data-origin-height=&quot;661&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lsMwt/btsatUPieL5/bipgTJccrMuAsRKbKkVy1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lsMwt/btsatUPieL5/bipgTJccrMuAsRKbKkVy1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lsMwt/btsatUPieL5/bipgTJccrMuAsRKbKkVy1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlsMwt%2FbtsatUPieL5%2FbipgTJccrMuAsRKbKkVy1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;335&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1230&quot; data-origin-height=&quot;661&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션은 커넥션에 con.setAutocommit(&lt;b&gt;false&lt;/b&gt;)를 지정하면서 시작한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;같은 트랜잭션을 유지하려면 같은 데이터베이스 커넥션&lt;/b&gt;을 사용해야 한다.&lt;/li&gt;
&lt;li&gt;이를 위해 스프링 내부에서는 &lt;b&gt;트랜잭션 동기화 매니저&lt;/b&gt;가 사용된다.&lt;/li&gt;
&lt;li&gt;JdbcTemplate을 포함한 대부분의 데이터 접근 기술들은 트랜잭션을 유지하기 위해 내부에서 트랜잭션 동기화 매니저를 통해 리소스(커넥션)를 동기화 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션 적용&lt;/b&gt;&lt;/h2&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;public 메서드만 트랜잭션 적용&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링의 트랜잭션 AOP 기능은 기본적으로 public 메서드에만 트랜잭션을 적용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;public이 아닌 곳은 트랜잭션 적용을 무시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 레벨에 트랜잭션을 적용하는 경우가 있는데, 그러면 의도하지 않는 곳까지 과도하게 트랜잭션이 적용될 수있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션은 주로 비즈니스 로직의 시작점에 걸기 때문에 외부에 열어준 곳을 시작점으로 사용한다. 이러한 이유로 스프링은 public 메서드에만 트랜잭션을 적용하도록 막아두었다.&lt;/p&gt;
&lt;pre id=&quot;code_1685532321262&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Transactional
public class TransactionalTest {
    public method1();     // 트랜잭션 적용 o
    method2();            // 트랜잭션 적용 x
    protectied method3(); // 트랜잭션 적용 x
    privatemethod4();     // 트랜잭션 적용 x
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트랜잭션 적용 확인하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션은 AOP를 기반으로 동작하기 때문에 실제로 트랜잭션이 적용되고 있는지 아닌지 확인하기가 어렵다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 트랜잭션이 실제 적용되고 있는지 확인하는 방법에 대해 알아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1681560368115&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@SpringBootTest
public class TxBasicTest {
    @Autowired
    BasicService basicService;

    @Test
    void proxyCheck() {
        log.info(&quot;aop class = {}&quot;, basicService.getClass());
        assertThat(AopUtils.isAopProxy(basicService)).isTrue();
    }

    @Test
    void txCheck() {
        basicService.tx();
        basicService.nonTx();
    }

    @TestConfiguration
    static class TxApplyBasicConfig {
        @Bean
        BasicService basicService() {
            return new BasicService();
        }
    }

    static class BasicService {
        @Transactional
        public void tx() {
            log.info(&quot;call tx&quot;);
            boolean txActive = TransactionSynchronizationManager.isActualTransactionActive(); // 트랜잭션이 적용되어 있는지 확인
            log.info(&quot;tx active = {}&quot;, txActive);
        }

        public void nonTx() {
            log.info(&quot;call nonTx&quot;);
            boolean txActive = TransactionSynchronizationManager.isActualTransactionActive(); // 트랜잭션이 적용되어 있는지 확인
            log.info(&quot;tx active = {}&quot;, txActive);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;AopUtils.isAopProxy()&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Transactional을 클래스나 메서드에 하나라도 있으면 트랜잭션 AOP는 실제 객체(basicService)를 대상으로 &lt;b&gt;프록시 객체(basicService...$$CGLIB)를 만들어 스프링 빈에 등록&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;주입을 받을 때도 실제 객체 대신에 프록시 객체가 주입된다. (프록시는 실제 객체를 상속해 만들어지기 때문에 다형성 활용 가능)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 주입받은 basicService의 클래스 이름을 출력해보면 프록시 클래스의 이름이 출력되는 것을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;48&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/liKxf/btsamWmt21X/LqArnVrppAKZCE0A8mqsJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/liKxf/btsamWmt21X/LqArnVrppAKZCE0A8mqsJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/liKxf/btsamWmt21X/LqArnVrppAKZCE0A8mqsJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FliKxf%2FbtsamWmt21X%2FLqArnVrppAKZCE0A8mqsJK%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;1904&quot; height=&quot;48&quot; data-origin-width=&quot;1904&quot; data-origin-height=&quot;48&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;TransactionSynchronizationManager.isActualTransactionActive()&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 쓰레드에 &lt;b&gt;트랜잭션이 적용되어 있는지 확인&lt;/b&gt;할 수 있는 기능이다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;결과가 ture면 트랜잭션이 적용되어 있는 것으로, 트랜잭션의 적용 여부를 가장 확실하게 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHGgBe/btsajdbDfsM/Olyyx6ZcsNcLL1FLZEjkP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHGgBe/btsajdbDfsM/Olyyx6ZcsNcLL1FLZEjkP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHGgBe/btsajdbDfsM/Olyyx6ZcsNcLL1FLZEjkP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHGgBe%2FbtsajdbDfsM%2FOlyyx6ZcsNcLL1FLZEjkP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;186&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;트랜잭션 로그 추가&lt;/b&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;  application.propterties&lt;/p&gt;
&lt;pre id=&quot;code_1681549244723&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;logging.level.org.springframework.transaction.interceptor=TRACE&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1934&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cioRY8/btsaqP1PGtD/i0mUMMtWgGOgBsCPn0ui31/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cioRY8/btsaqP1PGtD/i0mUMMtWgGOgBsCPn0ui31/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cioRY8/btsaqP1PGtD/i0mUMMtWgGOgBsCPn0ui31/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcioRY8%2FbtsaqP1PGtD%2Fi0mUMMtWgGOgBsCPn0ui31%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;1934&quot; height=&quot;274&quot; data-origin-width=&quot;1934&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Getting transaction &amp;rarr; &quot;트랜잭션을 시작했다&quot;&lt;/li&gt;
&lt;li&gt;Completing transaction &amp;rarr; &quot;트랜잭션을 완료했다&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;트랜잭션 적용 위치에 따른 우선순위&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Transactional의 적용 위치에 따라 우선순위는 어떻게 달라질까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서 우선순위는 &lt;b&gt;항상 더 구체적이고 자세한 것이 높은 우선순위&lt;/b&gt;를 가진다는 것만 기억하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Transactional도 마찬가지로 예를 들어 메서드와 클래스에 애노테이션을 붙일 수 있다면, 더 구체적인 메서드가 더 높은 우선순위를 가진다.&lt;/p&gt;
&lt;pre id=&quot;code_1681563152719&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest
public class TxLevelTest {

    @Autowired
    LevelService service;

    @Test
    void orderTest() {
        service.write();
        service.read();
    }

    @TestConfiguration
    static class TxLevelTestConfig {
        @Bean
        LevelService levelService() {
            return new LevelService();
        }
    }

    @Slf4j
    @Transactional(readOnly = true) // 읽기 전용 트랜잭션
    static class LevelService {
        @Transactional(readOnly = false)
        public void write() {
            log.info(&quot;call write&quot;);
            printTxInfo();
        }

        public void read() {
            log.info(&quot;call read&quot;);
            printTxInfo();
        }

        private void printTxInfo() {
            boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info(&quot;tx active = {}&quot;, txActive);
            boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
            log.info(&quot;tx readOnly = {}&quot;, readOnly);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Tcxpv/btsakicvpM5/DGYyBeKiDylgINGOqpTV0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Tcxpv/btsakicvpM5/DGYyBeKiDylgINGOqpTV0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Tcxpv/btsakicvpM5/DGYyBeKiDylgINGOqpTV0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTcxpv%2FbtsakicvpM5%2FDGYyBeKiDylgINGOqpTV0k%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;1980&quot; height=&quot;448&quot; data-origin-width=&quot;1980&quot; data-origin-height=&quot;448&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션 AOP 주의사항&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프록시 내부 호출 문제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@Transactinal을 사용하는 트랜잭션 AOP는 프록시를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 프록시 방식의 AOP는 메서드 내부 호출에 프록시를 적용할 수 없다는 문제가 발생한다.&lt;/p&gt;
&lt;pre id=&quot;code_1685540338902&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@SpringBootTest
public class InternalCallTest {
    @Autowired
    CallService callService;

    @Test
    void externalCall() {
        callService.external();
    }

    @TestConfiguration
    static class InternalCallTestConfig {
        @Bean
        CallService callService() {
            return new CallService();
        }
    }

    @Slf4j
    static class CallService {    
        public void external() {
            log.info(&quot;call external&quot;);
            printTxInfo();
            internal(); // 내부 호출
        }

        @Transactional
        public void internal() {
            log.info(&quot;call internal&quot;);
            printTxInfo();
        }

        private void printTxInfo() {
            boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info(&quot;tx active = {}&quot;, txActive);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 트랜잭션을 사용하는 메서드를 별도의 클래스로 분리해 문제를 해결할 수 있다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1685540288746&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
@SpringBootTest
public class InternalCallTest {
    @Autowired
    CallService callService;

    @Test
    void externalCall() {
        callService.external();
    }

    @TestConfiguration
    static class InternalCallTestConfig {
        @Bean
        CallService callService() {
            return new CallService(internalService());
        }

        @Bean
        InternalService internalService() {
            return new InternalService();
        }
    }

    @Slf4j
    @RequiredArgsConstructor
    static class CallService {
        private final InternalService internalService;

        public void external() {
            log.info(&quot;call external&quot;);
            printTxInfo();
            internalService.internal(); // 외부 호출
        }

        private void printTxInfo() {
            boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info(&quot;tx active = {}&quot;, txActive);
        }
    }

    static class InternalService {
        @Transactional
        public void internal() {
            log.info(&quot;call internal&quot;);
            printTxInfo();
        }

        private void printTxInfo() {
            boolean txActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info(&quot;tx active = {}&quot;, txActive);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;초기화 시점 문제&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기화 코드에 @PostConstruct와 @Transactional을 함께 사용하면 트랜잭션이 적용되지 않는 문제가 발생한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제가 발생하는 이유는 초기화 코드가 먼저 호출되고, 그 이후에 트랜잭션 AOP가 적용되기 때문에 초기화 시점에는 트랜잭션을 획득할 수가 없는 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1685539913099&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBootTest
public class InitTxTest {
    @Autowired Hello hello;

    @Test
    void go() {
        // 초기화 코드는 스프링이 초기화 시점에 호출
    }

    @TestConfiguration
    static class InitTxTestConfig {
        @Bean
        Hello hello() {
            return new Hello();
        }
    }

    @Slf4j
    static class Hello {
        @PostConstruct
        @Transactional
        public void init() {
            boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
            log.info(&quot;Hello init @PostConstruct tx active = {}&quot;, isActive);
        }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1685540067003&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hello init @PostConstruct tx active = false&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;@EventListener(ApplicationReadyEvent.class)&lt;/b&gt;를 사용해 문제를 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ApplicationReadyEvent를 사용하면 트랜잭션 AOP를 포함한 스프링이 컨테이너가 완전히 생성된 이후에 이벤트가 붙은 메서드를 호출하기 때문에 트랜잭션이 적용된다.&lt;/p&gt;
&lt;pre id=&quot;code_1685539889734&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
static class Hello {
    @EventListener(ApplicationReadyEvent.class)
    @Transactional
    public void init() {
        boolean isActive = TransactionSynchronizationManager.isActualTransactionActive();
        log.info(&quot;Hello init ApplicationReadyEvent tx active = {}&quot;, isActive);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1685540046291&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Getting transaction for [hello.springtx.apply.InitTxTest$Hello.init]
Hello init ApplicationReadyEvent tx active = true
Completing transaction for [hello.springtx.apply.InitTxTest$Hello.init]&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션 옵션&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;value (트랜잭션 매니저 지정)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 트랜잭션 매니저를 지정하려면 &lt;b&gt;value&lt;/b&gt; 또는 &lt;b&gt;transactionManager&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 애노테이션의 속성이 하나일 경우 다음과 같이 value는 생략이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1685537795067&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class TxService {
    @Transactional(value=&quot;aTxManager&quot;)
    public void a() {...}

    @Transactional(&quot;bTxManager&quot;)
    public void b() {...}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;rollbackFor (예외 롤백 지정)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외 발생 시 스프링 트랜잭션의 기본 정책은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언체크 예외(RuntimeException, Error) 발생 : 롤백&lt;/li&gt;
&lt;li&gt;체크 예외(Exception) 발생 : 커밋&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;rollbackFor&lt;/b&gt; 옵션을 사용하면 기본 정책에 추가로 어떤 예외가 발생할 때 롤백할 지 지정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1685538144710&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 체크 예외인 Exception이 발생해도 롤백 진행
@Transactional(rollbackFor = Exception.class)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 &lt;b&gt;noRollbackFor&lt;/b&gt; 옵션을 사용하면 기본 정책에 추가로 어떤 예외가 발생할 때 롤백하면 안되는지 지정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1685538267032&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 언체크 예외인 RuntimeException 발생해도 롤백하지 않음
@Transactional(noRollbackFor = RuntimeException.class)&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;a href=&quot;https://jollyn.tistory.com/270&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;체크 예외 vs 언체크(런타임) 예외 더 알아보기&lt;/a&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;Isolation (격리 수준 지정)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Isolation 옵션을 사용해 트랜잭션 격리 수준을 지정할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 값은 데이터베이스에서 설정한 트랜잭션 격리 수준을 사용하는 DEFAULT이며, 대부분은 이 경우를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(애플리케이션 개발자가 트랜잭션 격리 수준을 직접 지정하는 경우는 드뭄)&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 56.6275%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6306%; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;격리 수준&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6067%; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;설명&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6306%; text-align: center;&quot;&gt;&lt;b&gt;DEFAULT&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6067%; text-align: center;&quot;&gt;데이터베이스 설정에 따름&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6306%; text-align: center;&quot;&gt;&lt;b&gt;READ_UNCOMMITTED&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6067%; text-align: center;&quot;&gt;커밋되지 않은 읽기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6306%; text-align: center;&quot;&gt;&lt;b&gt;READ_COMMITTED&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6067%; text-align: center;&quot;&gt;커밋된 읽기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6306%; text-align: center;&quot;&gt;&lt;b&gt;REPEATABLE_READ&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6067%; text-align: center;&quot;&gt;반복 가능한 읽기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 22.6306%; text-align: center;&quot;&gt;&lt;b&gt;SERIALIZABLE&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 31.6067%; text-align: center;&quot;&gt;직렬화 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;timeout&lt;/b&gt;&lt;/h3&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;p data-ke-size=&quot;size16&quot;&gt;timeoutString을 사용해 숫자 대신 문자 값으로 지정하는 것도 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;readOnly&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션은 기본적으로 읽기와 쓰기가 모두 가능한 트랜잭션이 생성되는데,&amp;nbsp;&lt;b&gt;readOnly=true&lt;/b&gt; 옵션을 사용하면 읽기 전용 트랜잭션이 생성된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 등록, 수정, 삭제가 안되고 오직 &lt;b&gt;읽기 기능만 동작&lt;/b&gt;하며 읽기에서 다양한 성능 최적화가 발생할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;readOnly 옵션은 크게 3곳에 적용된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;프레임워크&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JdbcTemplate은 읽기 전용 트랜잭션 안에서 변경 기능을 실행하면 예외를 던짐&lt;/li&gt;
&lt;li&gt;JPA는 읽기 전용 트랜잭션의 경우 커밋 시점에 플러시를 호출하지 않음. 추가로 변경이 필요 없기 때문에 변경 감지를 위한 스냅샷 객체도 생성하지 않음. &amp;rarr; 다양한 최적화 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JDBC&lt;/b&gt; &lt;b&gt;드라이버&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;DB와 드라이버 버전에 따라 다르게 동작하기 때문에 사전에 확인 필요&lt;/li&gt;
&lt;li&gt;읽기 전용 트랜잭션에서 변경 쿼리 발생 시 예외를 던짐&lt;/li&gt;
&lt;li&gt;읽기, 쓰기 베이터베이스를 구분하여 요청 (읽기 전용 트랜잭션의 경우 읽기 데이터베이스의 커넥션을 획득하여 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터베이스&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터베이스에 따라 읽기 전용 트랜잭션의 경우 읽기만 하면 되기 때문에  내부에서 성능 최적화 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;propagation (트랜잭션 전파)&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/DB 접근기술</category>
      <category>@Transactional</category>
      <category>트랜잭션</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/280</guid>
      <comments>https://jollyn.tistory.com/280#entry280comment</comments>
      <pubDate>Thu, 1 Jun 2023 02:44:38 +0900</pubDate>
    </item>
    <item>
      <title>[Spring + AWS] SdkClientException: Failed to connect to service endpoint</title>
      <link>https://jollyn.tistory.com/288</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  문제 발생 상황&lt;/h2&gt;
&lt;pre id=&quot;code_1683618510335&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;com.amazonaws.SdkClientException: Failed to connect to service endpoint: 
	at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:100) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:70) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.internal.InstanceMetadataServiceResourceFetcher.readResource(InstanceMetadataServiceResourceFetcher.java:75) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.internal.EC2ResourceFetcher.readResource(EC2ResourceFetcher.java:66) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.util.EC2MetadataUtils.getItems(EC2MetadataUtils.java:402) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.util.EC2MetadataUtils.getData(EC2MetadataUtils.java:371) ~[aws-java-sdk-core-1.11.792.jar:na]
	at org.springframework.cloud.aws.context.support.env.AwsCloudEnvironmentCheckUtils.isRunningOnCloudEnvironment(AwsCloudEnvironmentCheckUtils.java:38) ~[spring-cloud-aws-context-2.2.6.RELEASE.jar:2.2.6.RELEASE]
	at org.springframework.cloud.aws.context.annotation.OnAwsCloudEnvironmentCondition.matches(OnAwsCloudEnvironmentCondition.java:38) ~[spring-cloud-aws-context-2.2.6.RELEASE.jar:2.2.6.RELEASE]
	at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$TrackedConditionEvaluator.shouldSkip(ConfigurationClassBeanDefinitionReader.java:489) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:140) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:129) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:343) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:247) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:311) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:112) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:746) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:564) ~[spring-context-5.3.25.jar:5.3.25]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.9.jar:2.7.9]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:731) ~[spring-boot-2.7.9.jar:2.7.9]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.9.jar:2.7.9]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:307) ~[spring-boot-2.7.9.jar:2.7.9]
	at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:164) ~[spring-boot-2.7.9.jar:2.7.9]
	at saramdle.blog.BlogApplication.main(BlogApplication.java:19) ~[classes/:na]
Caused by: java.net.ConnectException: Host is down (connect failed)
	at java.base/java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:na]
	at java.base/java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:412) ~[na:na]
	at java.base/java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:255) ~[na:na]
	at java.base/java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:237) ~[na:na]
	at java.base/java.net.Socket.connect(Socket.java:608) ~[na:na]
	at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:177) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:508) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:603) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.&amp;lt;init&amp;gt;(HttpClient.java:276) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:375) ~[na:na]
	at java.base/sun.net.www.http.HttpClient.New(HttpClient.java:396) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1253) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1232) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1081) ~[na:na]
	at java.base/sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:1015) ~[na:na]
	at com.amazonaws.internal.ConnectionUtils.connectToEndpoint(ConnectionUtils.java:52) ~[aws-java-sdk-core-1.11.792.jar:na]
	at com.amazonaws.internal.EC2ResourceFetcher.doReadResource(EC2ResourceFetcher.java:80) ~[aws-java-sdk-core-1.11.792.jar:na]
	... 23 common frames omitted&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  문제 원인 파악&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;spring-cloud-aws를 이용한 프로젝트를 aws의 ec2 환경이 아닌 로컬 환경에서 실행시켜 발생하는 warning이다.&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;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  문제 해결&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법1) 단순 로그 숨김&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1683621574679&quot; class=&quot;vbnet&quot; data-ke-language=&quot;vbnet&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;logging:
  level.com:
    amazonaws:
      util:
        EC2MetadataUtils: error&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ec2 환경에서 실행하면 해결되는 warning이지만 로컬에서 실행할 때도 해당 에러를 보고 싶지 않다면 해당 클래스의 로그 레벨을 조정해주면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 이 방법은 로그를 안보이게 할 뿐 딜레이 되는건 여전하기 때문에 다른 방법을 알아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법2) ec2가 아닌 환경의 시스템 환경변수 생성&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;run - configuration&lt;/li&gt;
&lt;li&gt;&amp;nbsp;vm option에 다음 문장 추가&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1683624557300&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-Dcom.amazonaws.sdk.disableEc2Metadata=true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2044&quot; data-origin-height=&quot;1344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs0Pd1/btsezLHXRcB/iDEO0C7GEorKU7IfaySRkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs0Pd1/btsezLHXRcB/iDEO0C7GEorKU7IfaySRkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs0Pd1/btsezLHXRcB/iDEO0C7GEorKU7IfaySRkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs0Pd1%2FbtsezLHXRcB%2FiDEO0C7GEorKU7IfaySRkk%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;2044&quot; height=&quot;1344&quot; data-origin-width=&quot;2044&quot; data-origin-height=&quot;1344&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가후 다시 실행해보면 에러 메세지가 다음과 같이 바뀐다.&lt;/p&gt;
&lt;pre id=&quot;code_1683624684502&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;com.amazonaws.util.EC2MetadataUtils      : Unable to retrieve the requested metadata
# com.amazonaws.AmazonClientException: EC2 Instance Metadata Service is disabled&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 ec2 메타데이터를 제외하고 실행한다는 의미로, 애플리케이션 실행 시 딜레이가 없어졌다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 해당 문구도 출력을 원하지 않는다면 방법1의 로그 설정을 추가해주면 된다!&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lannstark.tistory.com/71&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Failed to connect to service endpoint 해결&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://lemontia.tistory.com/1006&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;aws sdk 에러 안띄우기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://kim-jong-hyun.tistory.com/79&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Spring Cloud AWS 의존성 추가시 &quot;Failed to connect to service endpoint&quot; 에러 발생원인 및 해결 방법&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/59517989/spring-cloud-aws-sqs-fails-to-connect-to-service-endpoint-locally&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stackoverflow - Spring Cloud AWS SQS fails to connect to service endpoint locally&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/삽질기록</category>
      <category>ConnectException</category>
      <category>Failed to connect to service endpoint</category>
      <category>SdkClientException</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/288</guid>
      <comments>https://jollyn.tistory.com/288#entry288comment</comments>
      <pubDate>Tue, 9 May 2023 16:50:19 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] Establishing SSL connection without server's identity verification is not recommended</title>
      <link>https://jollyn.tistory.com/287</link>
      <description>&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  문제 발생 상황&lt;/h2&gt;
&lt;pre id=&quot;code_1683614133291&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WARN: Establishing SSL connection without server's identity verification is not recommended.
According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set.
For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'.
You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  문제 원인 파악&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 MySQL 8을 연결하면 발생하는 에러다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL이 8로 업그레이드되면서 여러가지 보안이 강화되었고, 연결시 기본적으로 SSL 통신을 사용하도록 변경되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메세지중 SSL 통신시 서버 인증서를 검증할 수 없다는 내용이 있으며 이는 서버의 SSL 인증서가 Java의 신뢰하는 인증서 목록에 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;  문제 해결&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법1) 서버 인증서 검증 끄기(권장)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1683614693381&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:0000/database이름?useSSL=true&amp;amp;autoReconnect=true&amp;amp;verifyServerCertificate=false
   	username:
   	password:&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSL을 사용하도록 설정하고, 서버 인증서를 검증하는 옵션인 verifyServerCertifivate를 false로 두어 인증서 검증을 해제하여 에러를 해결할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법2) SSL 사용 해제하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1683614774989&quot; class=&quot;shell&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:0000/database이름?useSSL=false
   	username:
   	password:&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSL을 사용하지 않으므로 SSL 인증서로 인한 에러를 해결할 수 있다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;하지만, 다음과 같이 SSL 사용을 해제하는 방식은 보안 측면에서 권장하지 않는다.&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.lesstif.com/java/java-mysql-8-establishing-ssl-connection-without-server-s-identity-verification-is-not-recommended-113346792.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Java에서 MySQL 8 연결 에러&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/삽질기록</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/287</guid>
      <comments>https://jollyn.tistory.com/287#entry287comment</comments>
      <pubDate>Tue, 9 May 2023 15:50:22 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] JPA 설정 총 정리 : ddl-auto 옵션, 실행 쿼리 보기(SpringBoot 3.x 버전 변경 추가)</title>
      <link>https://jollyn.tistory.com/242</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터베이스 연동&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1678883416738&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  datasource:
    url: jdbc:h2:tcp://localhost/~/test
    username: sa
    password:
    driver-class-name: org.h2.Driver&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;spring.datasource : DB 연결정보&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JPA ddl-auto 옵션&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1680498397939&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  jpa:
    open-in-view: false
    hibernate:
      ddl-auto: create&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;open-in-view : osiv 웹 요청이 완료될 때까지 영속성을 가지는 옵션 (켜두면 성능상 안 좋기 때문에 false 사용)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;hibernate.ddl-auto :&amp;nbsp;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;create&lt;/b&gt; : 기존 테이블 삭제 후 다시 테이블 생성 (DROP + CREATE)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;create-drop&lt;/b&gt; : 테이블 생성 후 종료시점에 테이블 삭제 (CREATE + DROP)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;update&lt;/b&gt; : 변경만 반영&lt;/li&gt;
&lt;li&gt;&lt;b&gt;validate&lt;/b&gt; : 엔티티와 테이블이 정상 매핑되는지만 확인&lt;/li&gt;
&lt;li&gt;&lt;b&gt;none&lt;/b&gt; : 사용하지 않음(실제로는 없는 값이지만 관례상 표시)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;실행 쿼리 출력&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;콘솔에 직접 출력하는 방식&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1680498445788&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  jpa:
    properties:
      hibernate:
        show_sql: true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1802&quot; data-origin-height=&quot;184&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPLLh9/btsyML9eRS3/KBWM5EwbuKVaTsO77ATsSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPLLh9/btsyML9eRS3/KBWM5EwbuKVaTsO77ATsSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPLLh9/btsyML9eRS3/KBWM5EwbuKVaTsO77ATsSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPLLh9%2FbtsyML9eRS3%2FKBWM5EwbuKVaTsO77ATsSK%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;1802&quot; height=&quot;184&quot; data-origin-width=&quot;1802&quot; data-origin-height=&quot;184&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;로그로 출력하는 방식&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697680076653&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;logging.level:
    org.hibernate:
    	SQL: debug&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2292&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCJm6G/btsyLLaRa57/lURhrVbVk88Yzxj7sTlPHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCJm6G/btsyLLaRa57/lURhrVbVk88Yzxj7sTlPHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCJm6G/btsyLLaRa57/lURhrVbVk88Yzxj7sTlPHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCJm6G%2FbtsyLLaRa57%2FlURhrVbVk88Yzxj7sTlPHk%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;2292&quot; height=&quot;196&quot; data-origin-width=&quot;2292&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;다양한 출력 형태 옵션&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1697680114188&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;spring:
  jpa:
    properties:
      hibernate:
        format_sql: true
        highlight_sql: true
        		
logging.level:
  org.hibernate:
    type.descriptor.sql: trace
    //type.descriptor.sql.BaiscBinder: trace&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;format_sql : 실행 쿼리를 한줄이 아니라 가독성있게 포맷팅하여 출력&lt;/li&gt;
&lt;li&gt;highlight_sql : SQL문을 하이라이팅&lt;/li&gt;
&lt;li&gt;type.descriptor.sql : 실행 쿼리에 바인딩되는 파라미터를 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2366&quot; data-origin-height=&quot;486&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vqHp0/btsyMMfZCHW/XmPN5v453iU5K5Ko6K7mwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vqHp0/btsyMMfZCHW/XmPN5v453iU5K5Ko6K7mwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vqHp0/btsyMMfZCHW/XmPN5v453iU5K5Ko6K7mwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvqHp0%2FbtsyMMfZCHW%2FXmPN5v453iU5K5Ko6K7mwk%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;2366&quot; height=&quot;486&quot; data-origin-width=&quot;2366&quot; data-origin-height=&quot;486&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링 부트 3.x 버전부터 변경사항&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트 2.x 버전에서는 잘 출력되는데 스프링 부트 3.x 버전에서는 바인딩 파라미터가 출력되지 않아 찾아보니 옵션이 조금 달라졌다고 한다. 현재 3.x 이상 버전을 사용한다면 해당 옵션을 사용해주도록 하자.&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;  application.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1681869094103&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;logging.level:
    org.hibernate:
    	orm.jdbc.bind: trace&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;외부 라이브러리 사용&lt;/b&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1686130419024&quot; style=&quot;background-color: #ffffff; color: #434549; text-align: start;&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - gavlyukovskiy/spring-boot-data-source-decorator: Spring Boot integration with p6spy, datasource-proxy, flexy-pool and s&quot; data-og-description=&quot;Spring Boot integration with p6spy, datasource-proxy, flexy-pool and spring-cloud-sleuth - GitHub - gavlyukovskiy/spring-boot-data-source-decorator: Spring Boot integration with p6spy, datasource-p...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/gavlyukovskiy/spring-boot-data-source-decorator&quot; data-og-url=&quot;https://github.com/gavlyukovskiy/spring-boot-data-source-decorator&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/u0Kly/hyRRO8u4zc/5BQJYOinQARy0kIJdUUFsk/img.png?width=1200&amp;amp;height=600&amp;amp;face=963_133_1068_247&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://github.com/gavlyukovskiy/spring-boot-data-source-decorator&quot; data-source-url=&quot;https://github.com/gavlyukovskiy/spring-boot-data-source-decorator&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/u0Kly/hyRRO8u4zc/5BQJYOinQARy0kIJdUUFsk/img.png?width=1200&amp;amp;height=600&amp;amp;face=963_133_1068_247');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - gavlyukovskiy/spring-boot-data-source-decorator: Spring Boot integration with p6spy, datasource-proxy, flexy-pool and s&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;Spring Boot integration with p6spy, datasource-proxy, flexy-pool and spring-cloud-sleuth - GitHub - gavlyukovskiy/spring-boot-data-source-decorator: Spring Boot integration with p6spy, datasource-p...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;build.gradle&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1686130419026&quot; class=&quot;bash&quot; style=&quot;background-color: #ffffff; color: #434549; text-align: start;&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6'&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&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1351&quot; data-origin-height=&quot;92&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SwZcX/btsi3p1G85I/pIzkPywi3R4pCkeFCKaKhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SwZcX/btsi3p1G85I/pIzkPywi3R4pCkeFCKaKhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SwZcX/btsi3p1G85I/pIzkPywi3R4pCkeFCKaKhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSwZcX%2Fbtsi3p1G85I%2FpIzkPywi3R4pCkeFCKaKhk%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;1351&quot; height=&quot;92&quot; data-origin-width=&quot;1351&quot; data-origin-height=&quot;92&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;text-align: start;&quot; href=&quot;https://lannstark.tistory.com/14&quot;&gt;Spring Boot SQL 보기 옵션 총 정리&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://vkein.tistory.com/entry/JPA-%EC%84%A4%EC%A0%95h2-%EC%83%98%ED%94%8C-applicationyml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JPA 설정 샘플 (application.yml)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ttl-blog.tistory.com/107&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JPA 데이터베이스 설정&lt;/a&gt;&lt;/p&gt;</description>
      <category>  Spring/JPA</category>
      <category>ddl-auto</category>
      <category>ddl-auto 옵션</category>
      <category>JPA</category>
      <category>jpa 테이블 생성</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/242</guid>
      <comments>https://jollyn.tistory.com/242#entry242comment</comments>
      <pubDate>Wed, 19 Apr 2023 11:02:58 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] Auditing 기능을 사용해 공통 칼럼(등록일, 수정일 등) 관리하기</title>
      <link>https://jollyn.tistory.com/277</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Auditing 기능이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA를 사용해 도메인을 관계형 데이터베이스 테이블에 매핑할 때 도메인들이 공통적으로 가지고 있는 컬럼이 존재한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 생성일, 등록일 같은 것들이 있다. 데이터베이스에 누가, 언제했는지 기록을 남기는 생성일, 수정일 컬럼은 굉장히 중요한 데이터라고 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 Spring Data JPA는 Auditing이라는 기능을 제공해준다.&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;사용방법&lt;/b&gt;&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;  build.gradle&lt;/p&gt;
&lt;pre id=&quot;code_1679488848982&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Auditing 기능을 사용하기 위해 Jpa 의존성을 추가해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  추상 클래스 생성&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  BaseTimeEntity&lt;/p&gt;
&lt;pre id=&quot;code_1679489091449&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Getter
@MappedSuperclass 
@EntityListeners(AuditingEntityListener.class) 
public abstract class BaseTimeEntity{
    @CreatedDate
    private LocalDateTime createdDate;

    @LastModifiedDate
    private LocalDateTime modifiedDate;
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;@MappedSuperclass&lt;/b&gt; : JPA Entity들이 해당 클래스를 상속할 경우 createdDate, updatedDate를 컬럼으로 인식&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@EntityListeners(AuditingEntityListener.class)&lt;/b&gt; : 해당 클래스에 Auditing 기능을 포함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@CreatedDate&lt;/b&gt; : Entity가 생성되어 저장될 때 시간을 자동 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@LastModifiedDate&lt;/b&gt; : 조회한 Entity의 값이 변경될 때 시간을 자동 저장&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Date 자료형을 지양하고 java 8 버전에 추가된 LocalDate, LocalDateTime을 사용하는 것을 권장한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  클래스 상속&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  Post&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679491713692&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Post extends BaseTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String title;
    
    private String contents;

    @Builder
    private Post(String title, String contents) {
        this.title = title;
        this.contents = contents;
    }
    
    public void update(String title, String contents) {
        this.title = title;
        this.contents = contents;
    }
}&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;  JPA Auditing 활성화&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679489352238&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@EnableJpaAuditing 
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 클래스에 @EnableJpaAuditing 애노테이션을 적용해 JPA Auditing 기능을 활성화해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  테스트&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679491210380&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Test
@DisplayName(&quot;게시물을 저장하면 생성, 수정시간이 자동으로 생성된다.&quot;)
void generateTimeOfPost() {
    // given
    Post post = Post.builder().build();
    Post savePost = postRepository.save(post);

    // when
    Post findPost = postRepository.findById(savePost.getId());

    System.out.println(&quot;createdDate = &quot; + findPost.getCreatedDate());
    System.out.println(&quot;updatedDate = &quot; + findPost.getUpdatedDate());

    // then
    assertThat(findPost.getCreatedDate()).isNotNull();
    assertThat(findPost.getUpdatedDate()).isNotNull();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZZrc4/btr5rfYLrGq/H4rVfyQPh6xwQLeIY4GCP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZZrc4/btr5rfYLrGq/H4rVfyQPh6xwQLeIY4GCP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZZrc4/btr5rfYLrGq/H4rVfyQPh6xwQLeIY4GCP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZZrc4%2Fbtr5rfYLrGq%2FH4rVfyQPh6xwQLeIY4GCP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;88&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Refernce&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.auditing&quot;&gt;JPA Auditing 공식문서&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://europani.github.io/spring/2021/10/05/027-baseTimeEntity.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JPA BaseTimeEntity&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://webcoding-start.tistory.com/53&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JPA Auditing 기능이란?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ojt90902.tistory.com/711&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JPA Base Entity 사용한 Audit 기능 사용하기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@wonizizi99/SpringData-JPA-Auditing&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Auditing 적용 직접 구현하기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://web-km.tistory.com/42&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Auditing 기능 살펴보기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Spring/JPA</category>
      <category>auditing</category>
      <category>JPA</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/277</guid>
      <comments>https://jollyn.tistory.com/277#entry277comment</comments>
      <pubDate>Mon, 3 Apr 2023 13:58:19 +0900</pubDate>
    </item>
    <item>
      <title>데이터 접근 기술 (SQL Mapper 기술 - JdbcTemplate, MyBatis)</title>
      <link>https://jollyn.tistory.com/275</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은 &lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-2/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[인프런] 스프링 DB 2편 - 데이터 접근 활용 기술&lt;/a&gt;&amp;nbsp;강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터 접근 기술&lt;/b&gt;&lt;/h2&gt;
&lt;h3 style=&quot;text-align: left;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;SQL Mapper 기술&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;개발자가 SQL만 작성&lt;/b&gt;하면 해당 SQL의 결과를 객체로 편하게 매핑해준다.&lt;/li&gt;
&lt;li&gt;JDBC를 직접 사용할 때 발생하는 여러가지&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중복을 제거&lt;/b&gt;해주고, 기타 개발자에게 여러 편리한 기능을 제공해준다.&lt;/li&gt;
&lt;li&gt;예) &lt;b&gt;Jdbctemplate&lt;/b&gt;, &lt;b&gt;MyBatis&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ORM 관련 기술&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL Mapper 기술은 SQL을 개발자가 직접 작성해야 하지만, JPA는 기본적인&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SQL을 대신 작성하고 처리&lt;/b&gt;해준다.&lt;br /&gt;따라서 개발자는 저장하고 싶은 객체를 마치 자바 컬렉션에 저장하고 조회하듯이 사용하면 ORM 기술이 데이터베이스에 해당 객체를 저장하고 조회해준다.&lt;/li&gt;
&lt;li&gt;예) &lt;b&gt;JPA&lt;/b&gt;, &lt;b&gt;Hibernate&lt;/b&gt;, &lt;b&gt;스프링 데이터 JPA&lt;/b&gt;, &lt;b&gt;Querydsl&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 자바 진영의 ORM 표준이고, Hibernate는 JPA에서 가장 많이 사용하는 구현체이다&lt;/li&gt;
&lt;li&gt;스프링 데이터 JPA, Querydsl은 JPA를 더욱 편리하게 사용할 수 있도록 도와주는 프로젝트이다. 실무에서 JPA를 사용한다면 이 프로젝트로 필수로 함께 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JdbcTemplate&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JdbcTemplate은 JDBC를 매우 편리하게 사용할 수 있게 도와준다.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;장점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설정이 편리하다&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;jdbcTemplate은 spring-jdbc 라이브러리에 포함되어 있어 복잡한 설정 없이 바로 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JDBC의 &lt;b&gt;반복 문제 해결&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JdbcTemplate은 템플릿 콜백 패턴을 사용해 JDBC를 직접 사용할 때 발생하는 반복 작업을 대신 처리해준다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커넥션 획득&lt;/li&gt;
&lt;li&gt;statement 준비 및 실행&lt;/li&gt;
&lt;li&gt;결과를 반복하도록 루프 실행&lt;/li&gt;
&lt;li&gt;커넥션 종료, 리소스 종료&lt;/li&gt;
&lt;li&gt;트랙잭션을 다루기 위한 커넥션 동기화&lt;/li&gt;
&lt;li&gt;예외 발생시 스프링 예외 변환기 실행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;개발자는 SQL을 작성하고, 전달할 파라미터를 정의하고, 응답 값을 매핑해주기만 하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;단점&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;동적 SQL을 해결하기 어렵다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JdbcTemplate 사용법&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;JdbcTemplate에 대한 사용법은&amp;nbsp;&lt;a href=&quot;http://%20https://docs.spring.io/spring-framework/docs/current/reference/html/data- access.html#jdbc-JdbcTemplate&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;스프링 JdbcTemplate 공식 메뉴얼&lt;/a&gt;에 자세히 소개되어 있으므로 참고하자.&lt;/blockquote&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;단건 조회 - queryForObject()&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1678693626694&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// int 데이터 조회
int rowCount = jdbcTemplate.queryForObjecct(&quot;select count(*) from actor&quot;, Integer.class);

// string 데이터 조회
String lastName = jdbcTemplate.queryForObject(&quot;select last_name from actor where id = ?&quot;, String.class, 100L);

// 객체 조회 (ResultSet을 객체로 매핑하기 위한 RowMapper 필요)
Actor actor = jdbcTemplate.queryForObject(&quot;select first_name, last_name form actor where id = ?,
    (resultSet, rowNum) -&amp;gt; {
        Actor newActor = new Actor();
        newActor.setFirstName(resultSet.getString(&quot;first_name&quot;);
        newActor.setLastName(resultSet.getString(&quot;last_name&quot;);
        return newActor;
    },
    100L);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회 결과가 1개일 경우 &lt;b&gt;queryForObject&lt;/b&gt;()를 사용한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조회 대상이 &lt;b&gt;단순 데이터&lt;/b&gt;일 경우 : 두번째 인자에 타입(Integer.class, String.class)을 지정&lt;/li&gt;
&lt;li&gt;조회 대상이 &lt;b&gt;객체&lt;/b&gt;일 경우 : 결과를 객체로 매핑해야하기 때문에 두번째 인자에 RowMapper를 사용해야 한다. (예제에서는 람다 사용)&lt;/li&gt;
&lt;/ul&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;b&gt;목록 조회 - query()&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1678694256297&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Actor&amp;gt; actor = jdbcTemplate.queryForObject(&quot;select first_name, last_name form actor where id = ?,
    (resultSet, rowNum) -&amp;gt; {
        Actor actor = new Actor();
        newActor.setFirstName(resultSet.getString(&quot;first_name&quot;);
        newActor.setLastName(resultSet.getString(&quot;last_name&quot;);
        return actor;
    });&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조회 결과가 여러개일 경우 &lt;b&gt;query&lt;/b&gt;()를 사용한다. 사용시 결과를 리스트로 반환한다.&amp;nbsp; &amp;nbsp;&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;b&gt;등록, 수정, 삭제 - update()&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1678694622226&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 등록
jdbcTemplate.update(
    &quot;insert into actor (first_name, last_name) values (?, ?)&quot;,
    &quot;Leonor&quot;, &quot;Watling&quot;);

// 수정
jdbcTemplate.update(
    &quot;update actor set last_name = ? where id = ?&quot;,
    &quot;Banjo&quot;, 527L);
    
// 삭제
jdbcTemplate.update(
    &quot;delete form actor where id = ?&quot;,
    Long.valueOf(actorId));&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;&lt;b&gt;기타 - execute()&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1678695346759&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;jdbcTemplate.execute(&quot;create table mytable (id integer, name varchar(100)&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;임의의 SQL을 실행하는 경우 execute()를 사용한다. 테이블을 생성하는 DDL에 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JdbcTemplate 기능&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;JdbcTemplate&lt;/b&gt; : 순서 기반 파라미터 바인딩을 지원 (순서를 잘못 입력할 경우 치명적 오류 발생)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;NamedParameterJdbcTemplate&lt;/b&gt; : 이름 기반 파리미터 바인딩 지원 (권장)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SimpleJdbcInsert&lt;/b&gt; : INSERT SQL을 편리하게 사용하도록 제공&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SimpleJdbcCall&lt;/b&gt; : 스토어드 프로시저를 편리하게 호출하도록 제공&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실무에서 가장 간단하고 실용적인 방법으로 SQL을 사용하려 할때 JdbcTemplate을 사용하면 된다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;또한 JPA와 같은 ORM 기술을 사용하면서 동시에 SQL을 직접 작성해야 할 때 JdbcTemplate을 함께 사용할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;하지만 JdbcTemplate는 &lt;b&gt;동적 쿼리 문제&lt;/b&gt;를 해결하지 못한다는 단점이 있으며, SQL을 자바 코드로 작성하기 때문에 SQL 라인이 코드를 넘어갈 때 마다 문자 더하기를 해줘야 한다는 단점이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이러한 동적 쿼리 문제를 해결하면서 SQL도 더욱 편리하게 작성할 수 있도록 도와주는 MyBatis 기술이 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MyBatis&lt;/b&gt;&lt;/h2&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MyBatis는 JdbcTemplate보다 더 많은 기능을 제공하는 SQL Mapper이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;JdbcTemplate vs MyBatis&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JdbcTemplate은 스프링에 내장된 기능이기 때문에 별도의 설정 없이 사용할 수 있지만, MyBaits는 약간의 설정이 필요하다는 단점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 MyBatis는 SQL을 XML에 편리하게 작성할 수 있고, 동적쿼리를 매우 편리하게 작성할 수 있다는 매력적인 장점이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 프로젝트에 동적쿼리와 복잡한 쿼리가 많다면 MyBatis를 사용하고, 단순한 쿼리들이 많다면 JdbcTemplate을 사용하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  JdbcTemplate - SQL 여러줄&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679982037644&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String sql = &quot;update item &quot; +
	&quot;set item_name=:itemNmae, price=:price, quantity=:quantity &quot; +
    &quot;where id=:id&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  MyBatis - SQL 여러줄&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1679982037645&quot; class=&quot;applescript&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;update id=&quot;update&quot;&amp;gt;
	update item
    set item_name = #{itemName},
    	price = #{price},
        quantity = #{quantity}
    where id = #{id}
&amp;lt;/update&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MyBatis 설정(gradle)&lt;/b&gt;&lt;/h3&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;  build.gradle&lt;/p&gt;
&lt;pre id=&quot;code_1679316515164&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;MyBatis는 스프링이 공식적으로 버전을 관리해주지 않아 버전 정보를 추가해줘야 한다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;스프링 부트 3.0 이상을 사용한다면 mybatis-spring-boot-starter:3.0.1을 사용해야 한다.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  MyBatis 설정정보 추가&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;  application.properties&lt;/p&gt;
&lt;pre id=&quot;code_1679317220295&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# MyBatis
mybatis.type-aliases-package=hello.itemservice.domain
mybatis.configuration.map-underscore-to-camel-case=true
logging.level.hello.itemservice.repository.mybatis=trace&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;mybatis.type.aliases-package
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MyBatis에서 타입 정보를 사용할 때 패키지 이름을 적어줘야 하는데, 여기에 명시해주면 &lt;b&gt;패키지 이름 생략이 가능&lt;/b&gt;하다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지정한 패키지와 그 하위 패키지&lt;/b&gt;가 자동으로 인식된다.&lt;/li&gt;
&lt;li&gt;여러 위치를 지정하려면 &lt;b&gt;,&lt;/b&gt; 또는 &lt;b&gt;;&lt;/b&gt; 로 구분한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;mybatis.configuration.map-underscore-to-camel-case=true
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;언더바를 카멜로 자동 변경해주는 기능을 활성화한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 객체 : 카멜 표기법 ex) itemName&lt;/li&gt;
&lt;li&gt;데이터베이스&amp;nbsp; : 언더바 표기법 ex) item_name&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;logging.level.hello.itemservice.repository.mybatis=trace
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Mybatis에서 실행되는 쿼리 로그를 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;웹 애플리케이션을 실행하는 main, 테스트를 실행하는 test 각 위치의 application.properties 모두 해당 설정정보를 추가해줘야 한다. (test 위치에 추가해주지 않을 경우 반영되지 않아 정상 실행되지 않는다.)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MyBatis 사용법&lt;/b&gt;&lt;/h3&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;MyBatis에 대한 사용법은 &lt;a href=&quot;https://mybatis.org/mybatis-3/ko/index.html&quot;&gt;MyBatis 공식 메뉴얼&lt;/a&gt;에 자세히 소개되어 있으므로 참고하자.&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  MyBatis 매퍼 인터페이스 생성&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;  java.hello.itemservice.repository.mybatis.ItemMapper&lt;/p&gt;
&lt;pre id=&quot;code_1679318242517&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Mapper
public interface ItemMapper {
    void save(Item item);

    void update(@Param(&quot;id&quot;) Long id, @Param(&quot;updateParam&quot;) ItemUpdateDto updateParam);

    List&amp;lt;Item&amp;gt; findAll(ItemSearchCond itemSearch);

    Optional&amp;lt;Item&amp;gt; findById(Long id);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 MyBatis 매핑 xml을 호출해주는 매퍼 인터페이스를 생성해준다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 인터페이스는 &lt;b&gt;@Mapper&lt;/b&gt; 애노테이션을 붙여줘야 MyBatis에서 인식할 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 인터페이스의 메서드를 호출하면 xml의 해당 SQL을 실행하고 그 결과를 반환한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  XML 매핑 파일 생성&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;  resources.hello.itemservice.repository.mybatis.ItemMapper&lt;/p&gt;
&lt;pre id=&quot;code_1679319351556&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE mapper PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
        &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&amp;gt;

&amp;lt;mapper namespace=&quot;hello.itemservice.repository.mybatis.ItemMapper&quot;&amp;gt;
    &amp;lt;insert id=&quot;save&quot; useGeneratedKeys=&quot;true&quot; keyProperty=&quot;id&quot;&amp;gt;
        insert into item (item_name, price, quantity)
        values (#{itemName}, #{price}, #{quantity})
    &amp;lt;/insert&amp;gt;

    &amp;lt;update id=&quot;update&quot;&amp;gt;
        update item
        set item_name=#{updateParam.itemName},
        price=#{updateParam.price},
        quantity=#{updateParam.quantity}
        where id = #{id}
    &amp;lt;/update&amp;gt;

    &amp;lt;select id=&quot;findById&quot; resultType=&quot;Item&quot;&amp;gt;
        select id, item_name, price, quantity
        from item
        where id = #{id}
    &amp;lt;/select&amp;gt;

    &amp;lt;select id=&quot;findAll&quot; resultType=&quot;Item&quot;&amp;gt;
        select id, item_name, price, quantity
        from item
        &amp;lt;where&amp;gt;
            &amp;lt;if test=&quot;itemName != null and itemName != ''&quot;&amp;gt;
                and item_name like concat('%',#{itemName},'%')
            &amp;lt;/if&amp;gt;
            &amp;lt;if test=&quot;maxPrice != null&quot;&amp;gt;
                and price &amp;amp;lt;= #{maxPrice}
            &amp;lt;/if&amp;gt;
        &amp;lt;/where&amp;gt;
    &amp;lt;/select&amp;gt;
&amp;lt;/mapper&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;이 파일은 자바 코드가 아니기 때문에 src/main/resources 하위에 만들어야 하며, 꼭&amp;nbsp;&lt;b&gt;매퍼 인터페이스와 패키지 위치를 맞춰주어야 한다&lt;/b&gt;.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;namespace로 앞서 만든 매퍼 인터페이스를 지정하면 된다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;만약 XML 파일을 다른 위치에 두고 싶다면?&lt;/b&gt; &lt;br /&gt;application.properties에 다음 설정을 추가해주면 된다.&lt;br /&gt;
&lt;pre id=&quot;code_1679319870095&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mybatis.mapper-locations=classpath:mapper/**/*.xml&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;insert&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1679319976886&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void save(Item item);

&amp;lt;insert id=&quot;save&quot; useGeneratedKeys=&quot;true&quot; keyProperty=&quot;id&quot;&amp;gt;
    insert into item (item_name, price, quantity)
    values (#{itemName}, #{price}, #{quantity})
&amp;lt;/insert&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;insert&amp;gt;&lt;/b&gt; 태그 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;id&lt;/b&gt; : 매퍼 인터페이스에 설정한 메서드 이름을 지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;파라미터&lt;/b&gt; : #{} 문법을 사용해 매퍼에서 넘긴 객체의 프로퍼티 이름을 지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;userGeneratedKeys&lt;/b&gt; : 데이터베이스가 키를 생성해주는 IDENTITY 전략일 경우 지정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;keyProperty&lt;/b&gt; : 생성되는 키의 속성 이름 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;update&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1679320211250&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;void update(@Param(&quot;id&quot;) Long id, @Param(&quot;updateParam&quot;) ItemUpdateDto updateParam);

&amp;lt;update id=&quot;update&quot;&amp;gt;
  update item
  set item_name=#{updateParam.itemName},
      price=#{updateParam.price},
      quantity=#{updateParam.quantity}
  where id = #{id}
&amp;lt;/update&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;update&amp;gt;&lt;/b&gt; 태그 사용&lt;/li&gt;
&lt;li&gt;파라미터가 한개일 경우 @Param을 지정하지 않아도 되지만, 두개 이상일 경우 &lt;b&gt;@Param으로 이름을 지정&lt;/b&gt;해서 구분해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;select&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1679320319182&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Optional&amp;lt;Item&amp;gt; findById(Long id);

&amp;lt;select id=&quot;findById&quot; resultType=&quot;Item&quot;&amp;gt;
  select id, item_name, price, quantity
  from item
  where id = #{id}
&amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1679320490504&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Item&amp;gt; findAll(ItemSearchCond itemSearch);

&amp;lt;select id=&quot;findAll&quot; resultType=&quot;Item&quot;&amp;gt;
  select id, item_name, price, quantity
  from item
  &amp;lt;where&amp;gt;
      &amp;lt;if test=&quot;itemName != null and itemName != ''&quot;&amp;gt;
          and item_name like concat('%',#{itemName},'%')
      &amp;lt;/if&amp;gt;
      &amp;lt;if test=&quot;maxPrice != null&quot;&amp;gt;
          and price &amp;amp;lt;= #{maxPrice}
      &amp;lt;/if&amp;gt;
  &amp;lt;/where&amp;gt;
&amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;&amp;lt;select&amp;gt;&lt;/b&gt; 태그 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;resultType&lt;/b&gt; : 반환 타입 명시
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여기서는 결과를 Item 객체에 매핑한다.&lt;/li&gt;
&lt;li&gt;원래는 패키지 이름을 모두 적어줘야 하지만, 앞서 application.properties에 관련 속성(mybatis.type-aliases-package)을 지정해주었기 때문에 패키지명을 생략할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) resultType=&quot;hello.itemservice.domain.Item&quot; &amp;rarr; resultType=&quot;Item&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;lt;where&amp;gt;, &amp;lt;if&amp;gt; 같은 &lt;b&gt;동적 쿼리 문법&lt;/b&gt;을 통해 편리한 동적 쿼리 지원
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;if&amp;gt; : 해당 조건 만족 시 구문 추가&lt;/li&gt;
&lt;li&gt;&amp;lt;where&amp;gt; : 적절하게 where 문장을 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&amp;amp;lt; : XML에서는 태그로 &amp;lt; , &amp;gt; 같은 특수 문자를 사용하기 때문에 데이터 영역에는 해당 특수문자를 사용할 수 없어 다음과 같이 표현한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt; : &amp;amp;lt;&lt;/li&gt;
&lt;li&gt;&amp;gt; : &amp;amp;gt;&lt;/li&gt;
&lt;li&gt;&amp;amp; : &amp;amp;amp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MyBatis 동작원리&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞서 만들어준 매퍼 인터페이스(ItemMapper)의 구현체를 만들어주지 않았지만 정상 동작하는 것을 확인할 수 있었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 껍데기 역할만 제공해줄&amp;nbsp; 뿐이며 스프링 빈으로 등록될 수도 없다.(스프링 빈에는 객체 인스턴스가 등록)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 어떻게 동작할 수 있는 것일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;MyBatis 스프링 연동 모듈&lt;/b&gt;에서 이런 부분을 자동으로 처리해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/87qSG/btr5oqHg5So/tBlhMLWkjpbeZ6elIKqUc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/87qSG/btr5oqHg5So/tBlhMLWkjpbeZ6elIKqUc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/87qSG/btr5oqHg5So/tBlhMLWkjpbeZ6elIKqUc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F87qSG%2Fbtr5oqHg5So%2FtBlhMLWkjpbeZ6elIKqUc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;214&quot; data-origin-width=&quot;1750&quot; data-origin-height=&quot;750&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션 로딩 시점에 MyBatis 스프링 연동 모듈은 @Mapper 애노테이션이 붙어있는 인터페이스를 조회한다.&lt;/li&gt;
&lt;li&gt;매퍼 인터페이스를 찾으면 동적 프록시 기술을 사용해 매퍼 인터페이스(ItemMapper)의 구현체를 만든다.&lt;/li&gt;
&lt;li&gt;생성된 구현체를 기반으로 스프링 빈에 등록한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MyBatis 스프링 연동 모듈을 통해 생성된 &lt;b&gt;동적 프록시 객체&lt;/b&gt;를 스프링 빈으로 등록해 사용하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 ItemMapper의 클래스를 로그로 찍어보면 실제로 프록시 기술이 사용되었음을 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;70&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz0ewc/btr5h9y4pOw/ROwaK3R0cm394A7OypirHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz0ewc/btr5h9y4pOw/ROwaK3R0cm394A7OypirHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz0ewc/btr5h9y4pOw/ROwaK3R0cm394A7OypirHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz0ewc%2Fbtr5h9y4pOw%2FROwaK3R0cm394A7OypirHK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;33&quot; data-origin-width=&quot;1476&quot; data-origin-height=&quot;70&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;MyBatis 스프링 연동 모듈이 자동으로 등록해주는 부분은 MyBatisAutoConfiguration 클래스를 참고하자.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MyBatis 스프링 연동 모듈이 만들어주는 매퍼 구현체 덕분에 인터페이스 만으로 편리하게 XML의 데이터를 찾아 호출할 수 있다.&lt;/li&gt;
&lt;li&gt;매퍼 구현체를 사용하면 스플이 &lt;b&gt;예외 추상화도 함께 적용&lt;/b&gt;된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MyBatis에서 발생한 예외를 스프링 예외 추상화인 DataAccessException에 맞게 변환해서 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;MyBatis 스프링 연동 모듈이 많은 부분을 자동으로 설정해주는데, 데이터베이스 커넥션, 트랜잭션과 관련된 기능도 MyBatis와 함께 연동하고 동기화해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;MyBatis 기능&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MyBatis에는 여러 기능이 있는데 여기서는 간단하게 소개 정도만 한다. 자세한 내용은 공식문서 링크를 통해 확인해보자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/dynamic-sql.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;동적 SQL 처리 기능&lt;/a&gt; (if, foreeach, choose, trim)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/java-api.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;애노테이션으로 SQL 작성 기능&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XML 대신 애노테이션에 SQL을 작성할 수 있다.&lt;/li&gt;
&lt;li&gt;@Insert, @Update, @Delete, @Select 기능을 제공한다.&lt;/li&gt;
&lt;li&gt;동적 SQL이 해결되지 않으므로 간단한 경우에만 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1679978112849&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Select(&quot;select id, item_name, price, quantity from item where id=#{id}&quot;)
Optional&amp;lt;Item&amp;gt; findById(Long id);&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/sqlmap-xml.html#%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%8C%80%EC%B2%B4-string-substitution&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;문자열 대체 기능&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;#{} : ?로 파라미터 바인딩 처리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;${}&lt;/b&gt; : 문자 그대로를 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1679981320526&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Select(&quot;select * from user where ${column} = #{value}&quot;)
User findByColumn(@Param(&quot;column&quot;) String column, @Param(&quot;value&quot;) String value);&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;${} 사용 시 SQL 인젝션 공격의 위험이 있어 &lt;b&gt;가급적 사용하면 안된다&lt;/b&gt;. 사용하더라고 매우 주의깊에 사용해야 한다.&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;nbsp;&lt;a href=&quot;https://mybatis.org/mybatis-3/ko/sqlmap-xml.html#sql&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;재사용 가능한 SQL 조각&lt;/a&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&amp;lt;sql&amp;gt;을 사용하면 SQL 코드를 재사용 할 수 있다.&lt;/li&gt;
&lt;li&gt;&amp;lt;include&amp;gt;를 통해 &amp;lt;sql&amp;gt; 조각을 찾아서 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/DB 접근기술</category>
      <category>jdbcTemplate</category>
      <category>mybatis</category>
      <category>SQL Mapper</category>
      <category>데이터 접근 기술</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/275</guid>
      <comments>https://jollyn.tistory.com/275#entry275comment</comments>
      <pubDate>Fri, 10 Mar 2023 20:40:01 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 체크 예외와 언체크 예외</title>
      <link>https://jollyn.tistory.com/270</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은 &lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1/dashboard&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[인프런] 스프링 DB 1편 - 데이터 접근 핵심 원리&lt;/a&gt;&amp;nbsp;강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;자바의 예외 계층&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1604&quot; data-origin-height=&quot;956&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6IPPx/btr2D3fiF89/XqbTRzKYjPTXKcbQRnPCLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6IPPx/btr2D3fiF89/XqbTRzKYjPTXKcbQRnPCLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6IPPx/btr2D3fiF89/XqbTRzKYjPTXKcbQRnPCLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6IPPx%2Fbtr2D3fiF89%2FXqbTRzKYjPTXKcbQRnPCLk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;358&quot; data-origin-width=&quot;1604&quot; data-origin-height=&quot;956&quot;/&gt;&lt;/span&gt;&lt;/figure&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 style=&quot;width: 20.3489%; text-align: center;&quot;&gt;&lt;b&gt;Object&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.6511%;&quot;&gt;&amp;bull; 예외도 객체이므로 최상위 부모가 Object이다. (자바의 모든 객체의 최상위 부모는 Object)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.3489%; text-align: center;&quot;&gt;&lt;b&gt;Throwable&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.6511%;&quot;&gt;&amp;bull; 최상위 예외&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.3489%; text-align: center;&quot;&gt;&lt;b&gt;&lt;b&gt;Error&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.6511%;&quot;&gt;&amp;bull; 메모리 부족이나 시스템 오류와 같이 애플리케이션에서 &lt;b&gt;복구 불가능한 시스템 예외&lt;/b&gt;&lt;br /&gt;&amp;bull; 개발자는 이 예외를 잡으려고 해서는 안된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.3489%; text-align: center;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;Exception&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.6511%;&quot;&gt;&amp;bull; &lt;b&gt;체크 예외&lt;/b&gt;&lt;br /&gt;&amp;bull; &lt;span&gt;애플리케이션 로직에서 사용할 수 있는 실질적인 최상위 예외이다.&lt;br /&gt;&lt;/span&gt;&amp;bull;&lt;span&gt;&lt;b&gt; 컴파일러가 체크하는&lt;/b&gt; 예외 (단 RuntimeException은 예외)&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 20.3489%; text-align: center;&quot;&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;&lt;b&gt;RuntimeException&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 79.6511%;&quot;&gt;&amp;bull; &lt;b&gt;언체크 예외&lt;/b&gt;, 런타임 예외&lt;br /&gt;&amp;bull; &lt;b&gt;컴파일러가 체크 하지 않는&lt;/b&gt; 예외&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;예외 처리 규칙&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예외는 2가지 기본 규칙을 가진다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예외는 &lt;b&gt;잡아서 처리&lt;/b&gt;하거나 &lt;b&gt;던져야&lt;/b&gt; 한다.&lt;/li&gt;
&lt;li&gt;예외를 잡거나 던질때 &lt;b&gt;지정한 예외뿐만 아니라 그 예외의 자식들도 함께 처리&lt;/b&gt;된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) Exception을 catch로 잡으면 그 하위 예외들도 모두 잡을 수 있다.&lt;/li&gt;
&lt;li&gt;ex) Exception을 throws로 던지면 그 하위 예외들도 모두 던질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 예외를 처리하지 못하고 계속 던지면 어떻게 될까?&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바 main() 쓰레드의 경우 예외 로그를 출력하며 &lt;b&gt;시스템 종료&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;웹 애플리케이션의 경우 여러 사용자의 요청을 처리하기 때문에 하나의 예외 때문에 시스템이 종료되어서는 안된다.&lt;br /&gt;따라서 WAS가 해당 예외를 받아 처리하는데, 주로 사용자에게 개발자가 지정해준 &lt;b&gt;오류 페이지&lt;/b&gt;를 보여준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;체크 예외 vs 언체크 예외&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;체크 예외&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Exception과 그 하위 예외는 모두 &lt;b&gt;컴파일러가 체크&lt;/b&gt;하는 체크 예외이다. (RuntimeException은 예외)&lt;/li&gt;
&lt;li&gt;체크 예외는 &lt;b&gt;반드시 잡아서 처리하거나 밖으로 던지도록 throws 선언&lt;/b&gt;을 해야 한다.&lt;/li&gt;
&lt;li&gt;그렇지 않을 경우 &lt;b&gt;컴파일 오류가 발생&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;비즈니스 의미가 있는 예외로 사용한다.&lt;/li&gt;
&lt;li&gt;장점 : 개발자가 실수로 예외를 누락하지 않도록 컴파일러를 통해 문제를 잡아주는 안전 장치이다.&lt;/li&gt;
&lt;li&gt;단점 : 개발자가 모든 체크 예외를 반드시 잡거나 던지도록 처리해줘야 하기 때문에, 신경쓰고 싶지 않은 예외까지 모두 챙겨야하므로 번거롭다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1678170864301&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
class CheckedTest {
    @Test
    void checked_catch() {
        Service service = new Service();
        service.callCatch();
    }

    @Test
    void checked_throws() {
        Service service = new Service();
        assertThatThrownBy(() -&amp;gt; service.callThrow())
                .isInstanceOf(MyCheckedException.class);
    }

    static class MyCheckedException extends Exception {
        /**
         * Exception을 상속받은 예외는 체크 예외가 된다.
         */
        MyCheckedException(String message) {
            super(message);
        }
    }

    /**
     * Checked 예외는
     * 예외를 잡아서 처리하거나, 던지거나 둘중 하나를 필수로 선택해야 한다.
     */
    static class Service {
        Repository repository = new Repository();

        /**
         * 체크 예외를 잡아서 처리하는 코드
         */
        void callCatch() {
            try {
                repository.call();
            } catch (MyCheckedException e) {
                // 예외 처리 로직
                log.info(&quot;예외 처리, message={}&quot;, e.getMessage(), e);
            }
        }

        /**
         * 체크 예외를 밖으로 던지는 코드
         * 체크 예외는 예외를 잡지 않고 밖으로 던지면 throws 예외를 메서드에 필수로 선언해야한다.
         * @throws MyCheckedException
         */
        void callThrow() throws MyCheckedException {
            repository.call();
        }
    }

    static class Repository {
        void call() throws MyCheckedException {
            throw new MyCheckedException(&quot;ex&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;언체크 예외 (런타임 예외)&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RuntimeException과 그 하위 예외는 언체크 예외로 분류된다.&lt;/li&gt;
&lt;li&gt;언체크 예외는 &lt;b&gt;컴파일러가 예외를 체크하지 않는다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;체크 예외와 기본적으로 동일하지만, 언체크 예외는 예외를 던지는 &lt;b&gt;throws를 선언하지 않고 생략&lt;/b&gt;할 수 있다. &amp;rarr; 자동으로 예외를 던짐&lt;/li&gt;
&lt;li&gt;복구 불가능한 예외로 사용한다.&lt;/li&gt;
&lt;li&gt;장점 : 신경쓰고 싶지 않은 언체크 예외를 무시할 수 있다.&lt;/li&gt;
&lt;li&gt;단점 : 개발자가 실수로 예외를 누락할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1678173811152&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Slf4j
class UncheckedTest {
    @Test
    void unchecked_catch() {
        Service service = new Service();
        service.callCatch();
    }

    @Test
    void unchecked_throw() {
        Service service = new Service();
        assertThatThrownBy(service::callThrow)
                .isInstanceOf(MyUncheckedException.class);
    }

    /**
     * RuntimeException을 상속받은 예외는 언체크 예외가 된다.
     */
    static class MyUncheckedException extends RuntimeException {
        public MyUncheckedException(String message) {
            super(message);
        }
    }

    /**
     * Unchecked 예외는
     * 예외를 잡거나, 던지지 않아도 된다.
     * 예외를 잡지 않으면 자동으로 밖으로 던진다.
     */
    static class Service {
        Repository repository = new Repository();

        /**
         * 필요한 경우 예와를 잡아서 처리하면 된다.
         */
        void callCatch() {
            try {
                repository.call();
            } catch (MyUncheckedException e) {
                // 예외 처리 로직
                log.info(&quot;예외 처리, message={}&quot;, e.getMessage(), e);
            }
        }

        /**
         * 예외를 잡지 않아도 된다. 자연스럽게 상위로 넘어간다.
         * 체크 예와와 다르기 throws 예외 선언을 하지 않아도 된다.
         */
        void callThrow() {
            repository.call();
        }
    }

    static class Repository {
        void call() {
            throw new MyUncheckedException(&quot;ex&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;언제 체크 예외를 사용하고 언체크 예외를 사용할까?&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기본적으로 언체크(런타임) 예외를 사용&lt;/b&gt;하자.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;체크 예외는&lt;/b&gt; &lt;b&gt;비즈니스 로직상 의도적으로 던지는 예외에만 사용&lt;/b&gt;하자.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반드시 처리해야 하는 예외일 경우 컴파일러가 누락을 체크해주는 체크 예외를 사용해 놓치는 경우가 없도록 한다.&lt;/li&gt;
&lt;li&gt;하지만 100% 체크 예외로 만들어야 하는 것은 아니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;예) 계좌 이체 실패 예외, 결제시 포인트 부족 예외, 로그인 id 및 pw 불일치 예외&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주문을 하는데 상황에 따라 다음과 같이 조치할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정상&lt;/b&gt; : 주문시 결제를 성공하면 주문 데이터를 저장하고 결제 상태를 [완료]로 처리한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;시스템 예외 (언체크)&lt;/b&gt; : 주문시 내부에 복구 불가능한 예외가 발생하면 전체 데이터를 롤백한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;비즈니스 예외 (체크)&lt;/b&gt; : 주문시 결제 잔고가 부족하면 주문 데이터를 저장하고, 결제 상태를 [대기]로 처리한다. 이후에 잔고 부족을 알리고 별도의 계좌로 입금하도록 안내한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 결제 잔고 부족 시 NotEnoughMoneyException이라는 체크 예외가 발생한다고 가정한다면, 이 예외는 시스템에 문제가 있어서 발생하는 예외가 아님을 생각해볼 수 있다. 고객의 잔고가 부족한 것은 시스템 상의 문제가 아니라 비즈니스 상황에서 문제가 되어 발생한 예외인 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 예외를 비즈니스 예외라 한다. 비즈니스 예외는 매우 중요하고 반드시 처리해줘야 하는 경우가 많으므로 체크 예외를 고려할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 생각해보면 체크 예외가 언체크 예외보다 더 안전하고 좋다고 생각이 든다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 왜 기본적으로 언체크 예외를 사용하는 것이 좋을까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;체크 예외는 다음과 같은 문제점이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;복구 불가능한 예외&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 예외는 복구가 불가능하며, 서비스나 컨트롤러는 이러한 문제를 해결할 수 없다. 따라서 이런 문제에 대해서는 오류 로그를 남기고 해당 오류를 개발자가 빨리 인지하는 것이 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;의존 관계에 대한 문제&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대부분의 예외는 복구 불가능한 예외이지만 체크 예외이기 때문에 컨트롤러나 서비스 입장에서는 본인이 처리할 수 없어도 어쩔 수 없이 throws를 통해 던지는 예외를 선언해줘야 한다. 따라서 해당 예외 객체에 의존하게 된다.&lt;/li&gt;
&lt;li&gt;이는 만약 JDBC 기술을 사용하다가 JPA로 변경했을 때 예를 들어 예외가 SQLException에서 JPAException으로 변경된다면 컨트롤러 및 서비스 클래스를 모두 변경해줘야 함을 의미한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;예외를 처리하는 다양한 방법&lt;/b&gt;&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스프링이 제공하는 추상화된 예외로 변환&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k5Hh2/btr2DF1VxPE/WlpOE1VUd1uWMXlKCD31I1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k5Hh2/btr2DF1VxPE/WlpOE1VUd1uWMXlKCD31I1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k5Hh2/btr2DF1VxPE/WlpOE1VUd1uWMXlKCD31I1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk5Hh2%2Fbtr2DF1VxPE%2FWlpOE1VUd1uWMXlKCD31I1%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;450&quot; height=&quot;322&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1100&quot;/&gt;&lt;/span&gt;&lt;/figure&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;DataAccessException 예외 (최상위)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NonTransient 예외&lt;/li&gt;
&lt;li&gt;Transient 예외&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 예외들은 특정 기술(JDBC, JPA 등)에 종속적이지 않게 설계되어 있기 때문에 서비스 계층에서 예외 처리가 필요하다면 종속적인 SQLException을 직접 사용하는 것이 아니라 스프링이 제공하는 데이터 접근 예외를 사용하면 된다.&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;스프링은 예외 변환기(SQLExceptionTranslator)를 통해 적절한 스프링 데이터 접근 예외로 알아서 변환도 해준다.&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mangkyu.tistory.com/152&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;체크 예외와 언체크 예외/런타임예외의 차이와 올바른 예외 처리 방법&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.inflearn.com/course/lecture?courseSlug=%EC%8A%A4%ED%94%84%EB%A7%81-db-2&amp;amp;unitId=114687&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[인프런] 스프링 DB 2편 - 데이터 접근 활용 기술 (예외와 트랜잭션 커밋, 롤백 활용)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>☕ Java/이론</category>
      <category>DataAccessException</category>
      <category>Exception</category>
      <category>런타임 예외</category>
      <category>스프링 예외 처리</category>
      <category>언체크 예외</category>
      <category>자바</category>
      <category>자바 예외처리 방법</category>
      <category>체크 예외</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/270</guid>
      <comments>https://jollyn.tistory.com/270#entry270comment</comments>
      <pubDate>Tue, 7 Mar 2023 17:59:26 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 인터넷 기술</title>
      <link>https://jollyn.tistory.com/265</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HTTP&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMEM2R/btr1HgOLDeP/lDIegCJfufR7kBVfR5zpfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMEM2R/btr1HgOLDeP/lDIegCJfufR7kBVfR5zpfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMEM2R/btr1HgOLDeP/lDIegCJfufR7kBVfR5zpfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMEM2R%2Fbtr1HgOLDeP%2FlDIegCJfufR7kBVfR5zpfK%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;250&quot; height=&quot;177&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hyper Text Transfer Protocol의 약어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;WWW 서버와 WWW 클라이언트 간의 통신을 수행하는 데 사용&lt;/b&gt;하는 네트워크 프로토콜&lt;/li&gt;
&lt;li&gt;WWW 서버로부터 정보를 취득할 때 HTTP 프로토콜을 사용해 통신한다.&lt;/li&gt;
&lt;li&gt;HTTP는 달라고 요청된 &lt;b&gt;데이터에 데이터 속성(정적 이미지, 텍스트 등)을 헤더로 붙여 반환&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;일반적으로 80번 통신 포트 사용&lt;/li&gt;
&lt;li&gt;HTTP에 의한 파일 전송은 요청에 대한 응답을 처리한 후 연결이 끊어지므로 여러 페이지에 걸쳐 처리해야 할 경우 페이지 간 정보를 유지할 수 없다는 단점이 있었지만,
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTTP 1.1에서 &lt;b&gt;연결을 끊지 않은 채 여러 요청을 계속 수행&lt;/b&gt;할 수 있도록 기능이 확장되었다.&lt;/li&gt;
&lt;li&gt;HTTP/2는 &lt;b&gt;하나의 연결 내 동시에 여러 개를 요청&lt;/b&gt;할 수 있도록 하는 등 효율성을 높이고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;SMTP&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Simple Mail Transfer Protocol의 약어&lt;/li&gt;
&lt;li&gt;전자 메일을 보내는 데(&lt;b&gt;송신&lt;/b&gt;) 사용되는&amp;nbsp;네트워크 프로토콜&lt;/li&gt;
&lt;li&gt;일반적으로 25번 포트 사용&lt;/li&gt;
&lt;li&gt;SMTP를 지원하는 서버는 SMTP 서버라고 한다.&lt;/li&gt;
&lt;li&gt;전자 메일을 보내면 보낸 사람의 STMP 서버로 데이터가 발송되고, 거기서는 SMTP 서버에서 대상 메일 서버로 전송되어 받는 사람의 메일 박스에 저장된다.&lt;/li&gt;
&lt;li&gt;이때 SMTP의 역할은 &lt;b&gt;상대 메일 서버에 전달하는 것&lt;/b&gt;까지다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;462&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJA05s/btr1KvYQv8o/C7MYoKo8nj58xrTcC39rm0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJA05s/btr1KvYQv8o/C7MYoKo8nj58xrTcC39rm0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJA05s/btr1KvYQv8o/C7MYoKo8nj58xrTcC39rm0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJA05s%2Fbtr1KvYQv8o%2FC7MYoKo8nj58xrTcC39rm0%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;450&quot; height=&quot;168&quot; data-origin-width=&quot;1234&quot; data-origin-height=&quot;462&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;POP&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Post Office Protocol의 약어&lt;/li&gt;
&lt;li&gt;인터넷 메일 &lt;b&gt;수신&lt;/b&gt;에 사용되는 네트워크 프로토콜&lt;/li&gt;
&lt;li&gt;일반적으로 110번 포트 사용&lt;/li&gt;
&lt;li&gt;메일 서버에 접속해 전송된 전자 메일을 자신의 메일 박스로 받기 위한 프로토콜이다.&lt;/li&gt;
&lt;li&gt;기본적으로 &lt;b&gt;열람하는 데이터를 모두 다운로드하여 서버에 남기지 않는다&lt;/b&gt;. 따라서 한번 수신한 전자 메일은 인터넷에 연결하지 않아도 읽을 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;454&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGXduz/btr16jDQpIG/Ef1o2KtSQCXnYt6dqXpbIK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGXduz/btr16jDQpIG/Ef1o2KtSQCXnYt6dqXpbIK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGXduz/btr16jDQpIG/Ef1o2KtSQCXnYt6dqXpbIK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGXduz%2Fbtr16jDQpIG%2FEf1o2KtSQCXnYt6dqXpbIK%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;450&quot; height=&quot;173&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;454&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;IMAP&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Internet Message Access Protocol의 약어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;수신&lt;/b&gt;한 인터넷 메일을 서버에서 가져오는 네트워크 프로토콜&lt;/li&gt;
&lt;li&gt;일반적으로 143번 포트 사용&lt;/li&gt;
&lt;li&gt;현재 IMAP4 버전&lt;/li&gt;
&lt;li&gt;POP와 동일하게 메일을 가져오기 위한 수신용 프로토콜이지만 근본적인 개념과 데이터를 보존하는 장소에 차이가 있다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;POP
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수신 메일을 다운로드하기 위한 프로토콜로, &lt;b&gt;서버에 데이터를 남기지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;여러 컴퓨터에서 같은 &lt;b&gt;데이터를 공유하는 것이 어려움&lt;/b&gt;, &lt;span style=&quot;color: #9d9d9d;&quot;&gt;ex) 회사 컴퓨터에서 받은 전자 메일을 집 컴퓨터에서 볼 수 없음&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;IMAP
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;POP와 달리 &lt;b&gt;모든 송수신 데이터를 서버에서 관리&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;해당 프로토콜을 지원하는 전자 메일 소프트웨어만 있으면 어느 컴퓨터에서도 같은 &lt;b&gt;데이터를 공유할 수 있음&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1190&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q9u5B/btr1T5GYk9E/HkwHfEkD5235ZyMlfw5U71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q9u5B/btr1T5GYk9E/HkwHfEkD5235ZyMlfw5U71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q9u5B/btr1T5GYk9E/HkwHfEkD5235ZyMlfw5U71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ9u5B%2Fbtr1T5GYk9E%2FHkwHfEkD5235ZyMlfw5U71%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;450&quot; height=&quot;732&quot; data-origin-width=&quot;1190&quot; data-origin-height=&quot;732&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NNTP&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Network News Transfer Protocol&lt;/li&gt;
&lt;li&gt;인터넷상의 &lt;b&gt;전자 회의실 시스템인 유즈넷에 사용&lt;/b&gt;되는 프로토콜&lt;/li&gt;
&lt;li&gt;일반적으로 119번 포트 사용&lt;/li&gt;
&lt;li&gt;게시물 배포, 게시물 접수, 뉴스 서버간의 게시물 교환에 이용된다.&lt;/li&gt;
&lt;li&gt;뉴스 서버는 게시물을 받으면 그 내용을 인접한 뉴스 서버에도 전달한다. 이때 무조건 전달하는 것은 아니고 상대 뉴스 서버가 그 게시물을 가지고 있지 않은 경우에만 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;670&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ok0HT/btr24kPB44K/QlVYAA1k8oXxYRpYqHKVkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ok0HT/btr24kPB44K/QlVYAA1k8oXxYRpYqHKVkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ok0HT/btr24kPB44K/QlVYAA1k8oXxYRpYqHKVkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fok0HT%2Fbtr24kPB44K%2FQlVYAA1k8oXxYRpYqHKVkK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;235&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;670&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;FTP&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;File Transfer Protocol&lt;/li&gt;
&lt;li&gt;서버와 클라이언트라는 두 컴퓨터 간에 &lt;b&gt;파일을 전송하기 위한&lt;/b&gt; 네트워크 프로토콜&lt;/li&gt;
&lt;li&gt;일반적으로 데이터 제어용으로 21번, 전송용으로 20번 포트 사용&lt;/li&gt;
&lt;li&gt;파일 다운로드, 업로드 외에 파일의 권한 변경이나 디렉터리 작성 등 다양한 조작을 할 수 있다.&lt;/li&gt;
&lt;li&gt;특징
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;FTP에 의한 파일 전송은 사용자 인증부터 시작해 인증에 성공한 사용자는 FTP 명령을 사용해 다양한 조작이 가능하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사용자 인증을 통해 사용자별로 세세한 권한을 설정&lt;/b&gt;할 수 있다.&lt;br /&gt;예) 특정 사용자는 참조만 가능하게 하거나, 특정 폴더는 일부 사용자만 참조할 수 있도록 서버에서 제한 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;FTP로 파일 전송 시 ASCII 모드와 바이너리 모드라는 두가지 모드 존재
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ASCII 모드&lt;/b&gt; : 주로 텍스트 파일 전송에 사용하는 모드로, 파일 내 개행 코드를 전송할 시스템에 맞는 형태로 변환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;바이너리 모드&lt;/b&gt; : 어떠한 변환도 하지 않는 모드로, 프로그램의 실행 파일이나 동영상 파일 등과 같이 파일 내용이 변경되면 안되는 데이터를 전송할 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bRr3ua/btr3a7uI1ro/iarazlJPThBSZetMM1OQi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bRr3ua/btr3a7uI1ro/iarazlJPThBSZetMM1OQi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bRr3ua/btr3a7uI1ro/iarazlJPThBSZetMM1OQi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbRr3ua%2Fbtr3a7uI1ro%2FiarazlJPThBSZetMM1OQi0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;285&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;814&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;SSL&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Secure Sockets Layer&lt;/li&gt;
&lt;li&gt;인터넷에서 안전하게 정보를 교환하기 위해 사용하는 &lt;b&gt;암호화 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;서로를 &lt;b&gt;인증&lt;/b&gt;시켜 도용을 방지하고, &lt;b&gt;통신 데이터를 암호화&lt;/b&gt;하여 데이터의 도청이나 조작을 방지하는 등 안전한 통신을 보장한다.&lt;/li&gt;
&lt;li&gt;OSI 참조 모델에 &lt;b&gt;전송 계층과 응용 계층 사이&lt;/b&gt;에 위치한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;716&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/partq/btr3Bvv1klY/a5Q6ZjqP76uL09324j4tRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/partq/btr3Bvv1klY/a5Q6ZjqP76uL09324j4tRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/partq/btr3Bvv1klY/a5Q6ZjqP76uL09324j4tRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpartq%2Fbtr3Bvv1klY%2Fa5Q6ZjqP76uL09324j4tRK%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;450&quot; height=&quot;228&quot; data-origin-width=&quot;1416&quot; data-origin-height=&quot;716&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HTTPS&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJNhCa/btr3kyAuAU9/ysLGFzE9o3HwJ3XJl87sik/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJNhCa/btr3kyAuAU9/ysLGFzE9o3HwJ3XJl87sik/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJNhCa/btr3kyAuAU9/ysLGFzE9o3HwJ3XJl87sik/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJNhCa%2Fbtr3kyAuAU9%2FysLGFzE9o3HwJ3XJl87sik%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;300&quot; height=&quot;210&quot; data-origin-width=&quot;750&quot; data-origin-height=&quot;526&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hyper Text Transfer Protocol over SSL&lt;/li&gt;
&lt;li&gt;WWW 서비스로 서버와의 통신에 사용되는 프로토콜인 HTTP에 SSL에 의한 암호화 통신을 추가한 프로토콜&lt;/li&gt;
&lt;li&gt;WWW 서버와 웹 브라우저 간 통신이 암호화되어 신용카드 번호나 개인정보 등을 안전하게 교환할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NTP&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nJNZp/btr3Swt0xuY/URU00CtfUSpBvE605ExT4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nJNZp/btr3Swt0xuY/URU00CtfUSpBvE605ExT4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nJNZp/btr3Swt0xuY/URU00CtfUSpBvE605ExT4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnJNZp%2Fbtr3Swt0xuY%2FURU00CtfUSpBvE605ExT4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;117&quot; data-origin-width=&quot;1180&quot; data-origin-height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Network Time Protocol&lt;/li&gt;
&lt;li&gt;인터넷에서 표준으로 사용되는 &lt;b&gt;시간 정보 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;네트워크에 있는 컴퓨터 시각을 동기화 하는데 사용&lt;/li&gt;
&lt;li&gt;NTP 서버는 계층 구조로 되어 있으며, Stratum 1부터 Stratum2, 3 ... 순서대로 15단계까지 계층화할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;868&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crMZPs/btr3HVPo5ho/uUMlhdUXb3DCL7KK6gOS90/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crMZPs/btr3HVPo5ho/uUMlhdUXb3DCL7KK6gOS90/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crMZPs/btr3HVPo5ho/uUMlhdUXb3DCL7KK6gOS90/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrMZPs%2Fbtr3HVPo5ho%2FuUMlhdUXb3DCL7KK6gOS90%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;247&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;868&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MIME&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PLsgr/btr3SHWB0QR/nWDB08yRMy3zg9bfgUD4eK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PLsgr/btr3SHWB0QR/nWDB08yRMy3zg9bfgUD4eK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PLsgr/btr3SHWB0QR/nWDB08yRMy3zg9bfgUD4eK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPLsgr%2Fbtr3SHWB0QR%2FnWDB08yRMy3zg9bfgUD4eK%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;650&quot; height=&quot;136&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Multipurpost Internet Mail Extensions&lt;/li&gt;
&lt;li&gt;전자 메일은 원래 ASCII 문자만 처리할 수 있다. 그래서 한국어 같은 멀티 바이트 문자나 화상 데이터 등의 파일을 첨부할 수 있도록 확장한 규격이 MIME이다.&lt;/li&gt;
&lt;li&gt;전자 메일은 ASCII 문자밖에 취급할 수 없어 MIME은 데이터를 ASCII 문자로 변환해 본문에 붙여 넣는다.&lt;br /&gt;이때 그대로 변환하면 본래 문장과 구별이 어려워 메일을 여러 부분으로 나누어 어떤 데이터인지 종류를 기입한다.&lt;/li&gt;
&lt;li&gt;S/MIME은 MIME에 암호화나 전자 서명의 기능을 추가한 규격이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;ICMP&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cQoHnO/btr3S1otZQ1/Ygfk80bB8YpmObO3HTiQE0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cQoHnO/btr3S1otZQ1/Ygfk80bB8YpmObO3HTiQE0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cQoHnO/btr3S1otZQ1/Ygfk80bB8YpmObO3HTiQE0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcQoHnO%2Fbtr3S1otZQ1%2FYgfk80bB8YpmObO3HTiQE0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;149&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Internet Control Message Protocol&lt;/li&gt;
&lt;li&gt;TCP/IP의 패킷 전송에서 발생한 &lt;b&gt;각종 에러 정보를 보고하기 위해 사용&lt;/b&gt;하는 네트워크 프로토콜&lt;/li&gt;
&lt;li&gt;통신 중 에러가 발생하면 ICMP는&lt;b&gt; 에러가 발생한 곳에서 패킷의 발송지로 에러 정보를 거꾸로 전송&lt;/b&gt;한다. 따라서 네트워크에서 발생한 오류 내용을 알 수 있다.&lt;/li&gt;
&lt;li&gt;ICMP를 이용한 네트워크 확인 명령어
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;ping&lt;/b&gt; : 네트워크의 소통을 확인하기 위한 명령어, 패킷이 잘 도착하고 응답이 이뤄졌는지 확인한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;traceroute&lt;/b&gt; : 네트워크 경로를 조사하기 위한 명령어, 원하는 컴퓨터에 도착할 때까지 어떤 라우터를 경유하는지 정보를 알 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;854&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/owqpm/btr3SuqOZG5/l2W5798my4Zq6MkjHZeq20/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/owqpm/btr3SuqOZG5/l2W5798my4Zq6MkjHZeq20/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/owqpm/btr3SuqOZG5/l2W5798my4Zq6MkjHZeq20/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fowqpm%2Fbtr3SuqOZG5%2Fl2W5798my4Zq6MkjHZeq20%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;450&quot; height=&quot;317&quot; data-origin-width=&quot;1212&quot; data-origin-height=&quot;854&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;HTML&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKyHQ7/btr3U4ruMKQ/U9xD25ZXo9zV0440q81Qhk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKyHQ7/btr3U4ruMKQ/U9xD25ZXo9zV0440q81Qhk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKyHQ7/btr3U4ruMKQ/U9xD25ZXo9zV0440q81Qhk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKyHQ7%2Fbtr3U4ruMKQ%2FU9xD25ZXo9zV0440q81Qhk%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;250&quot; height=&quot;209&quot; data-origin-width=&quot;702&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Hyper Text Markup Language&lt;/li&gt;
&lt;li&gt;인터넷에서 널리 사용되는 &lt;b&gt;WWW용 문서를 작성하는 언어&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;문서에 &lt;b&gt;링크를 설정해 문서끼리 서로 연결&lt;/b&gt;이 가능하다.&lt;/li&gt;
&lt;li&gt;HTML 형식은 태그라는 예약어를 텍스트 파일에 넣어서 문서의 모양과 논리 구조를 지정한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예) &amp;lt;h1&amp;gt;, &amp;lt;dev&amp;gt;, &amp;lt;span&amp;gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CSS&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;684&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kT12q/btr38puOqYG/94l8nmbT88letCRlPazTpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kT12q/btr38puOqYG/94l8nmbT88letCRlPazTpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kT12q/btr38puOqYG/94l8nmbT88letCRlPazTpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkT12q%2Fbtr38puOqYG%2F94l8nmbT88letCRlPazTpK%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;250&quot; height=&quot;221&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;684&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Cascading Style Sheets&lt;/li&gt;
&lt;li&gt;HTML로 작성된 문서의 레이아웃 같은 &lt;b&gt;모양을 정의&lt;/b&gt;하는 언어&lt;/li&gt;
&lt;li&gt;CSS 등장으로 문서와 레이아웃의 정의가 분리&lt;/li&gt;
&lt;li&gt;폰트, 색, 배경 등 다양한 속성을 지정할 수 있다.&lt;/li&gt;
&lt;li&gt;시각적인 표현을 CSS로 분리해 같은 HTML 문서라도 다양한 형태로 표현 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;XML&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqJCnW/btr6otJqVcu/rq0z5umuOOtAKyWPHPUj70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqJCnW/btr6otJqVcu/rq0z5umuOOtAKyWPHPUj70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqJCnW/btr6otJqVcu/rq0z5umuOOtAKyWPHPUj70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqJCnW%2Fbtr6otJqVcu%2Frq0z5umuOOtAKyWPHPUj70%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;300&quot; height=&quot;252&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;eXtensible Markup Language&lt;/li&gt;
&lt;li&gt;HTML 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;마크업 언어&lt;/b&gt;로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;태그를 사용해 문서 구조를 표현&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;XML vs HTML 차이점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HTML은 문서 구조 + 문서 모양을 표현하는 태그를 사용해 CSS 같은 스타일 시트 언어가 따로 없어도 된다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;XML은 문서 모양을 표현하는 태그가 없고, 단지 문서 구조 및 데이터의 속성을 표현하기 위한 태그만을 사용해 CSS 같은 스타일 시트 언어가 필수적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;XML은 &lt;b&gt;데이터 자체를 표현하는데 특화된 언어이다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;태그를 고유하게 정의해 데이터의 속성을 세밀하게 표현할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;860&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cr9WAT/btr6oeMqSsn/VftggBePk622h0e9IJF9VK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cr9WAT/btr6oeMqSsn/VftggBePk622h0e9IJF9VK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cr9WAT/btr6oeMqSsn/VftggBePk622h0e9IJF9VK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcr9WAT%2Fbtr6oeMqSsn%2FVftggBePk622h0e9IJF9VK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;243&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;860&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JavaScript&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스크립팅 언어의 일종&lt;/li&gt;
&lt;li&gt;HTML 파일에 프로그램을 작성하면 웹 사이트에 &lt;b&gt;동적 효과&lt;/b&gt;(메뉴 조작, 입력, 체크같은 움직임)를 줄 수 있다.&lt;/li&gt;
&lt;li&gt;스크립팅 언어는 간단한 프로그래밍 언어라고 불리며, 복잡한 절차 없이 작성한 프로그램을 실행할 수 있다는 특징이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;1376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CTRVr/btr37uXpTZ7/cB7K4JG8whuNvvkP9DtiX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CTRVr/btr37uXpTZ7/cB7K4JG8whuNvvkP9DtiX0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CTRVr/btr37uXpTZ7/cB7K4JG8whuNvvkP9DtiX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCTRVr%2Fbtr37uXpTZ7%2FcB7K4JG8whuNvvkP9DtiX0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;391&quot; data-origin-width=&quot;1408&quot; data-origin-height=&quot;1376&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;CMS&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Contents Management System의 약어&lt;/li&gt;
&lt;li&gt;웹 사이트를 구축, 운용하기 위해 필요한 도구들이 패키지화된 웹 시스템&lt;/li&gt;
&lt;li&gt;블로그 작성도구로 이용된다.&lt;/li&gt;
&lt;li&gt;이전 웹 사이트 구축 시 콘텐츠와 사이트 구성이 밀접하게 연결되어 있으므로, 전문지식이 필요하고 구성을 유연하게 변경할 수 없었지만, CMS를 사용하면 콘텐츠의 입력 및 관리와 웹 사이트에서 보이는 부분의 처리까지 시스템이 관리해준다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDBeM1/btr4Yu9uRU9/4efXK45yLoQnsXQdTlAO8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDBeM1/btr4Yu9uRU9/4efXK45yLoQnsXQdTlAO8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDBeM1/btr4Yu9uRU9/4efXK45yLoQnsXQdTlAO8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDBeM1%2Fbtr4Yu9uRU9%2F4efXK45yLoQnsXQdTlAO8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;162&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;578&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;쿠키&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;웹 브라우저와 WWW 서버 간&lt;/b&gt;에 암묵적인 &lt;b&gt;정보 교환&lt;/b&gt;을 실시하기 위한 장치&lt;/li&gt;
&lt;li&gt;쿠키 사용 시 클라이언트에 대한 &lt;b&gt;고유 정보를 기억&lt;/b&gt;하고 웹 사이트를 개인화 할 수 있다.&lt;br /&gt;&amp;rarr; 주로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용자를 식별&lt;/b&gt;하는 것을 목적으로 이용&lt;/li&gt;
&lt;li&gt;WWW 서버의 지시에 따라 웹 브라우저가 클라이언트 컴퓨터에 쿠키를 저장하고, 쿠키에 의해 저장된 정보는 액세스한 URL이 쿠키의 정보와 일치할 경우 자동으로 WWW 서버로 전송된다.&lt;/li&gt;
&lt;li&gt;하지만 쿠키가 저장하는 정보는 암호화되지 않아 클라이언트 컴퓨터에서 쉽게 변조할 수 있어 보안에 관련된 정보를 쿠키로 저장하는 것은 매우 위험하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;1410&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzFzNX/btr4w6v9OkB/jBdiJfhjK0BmE46Biw89gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzFzNX/btr4w6v9OkB/jBdiJfhjK0BmE46Biw89gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzFzNX/btr4w6v9OkB/jBdiJfhjK0BmE46Biw89gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzFzNX%2Fbtr4w6v9OkB%2FjBdiJfhjK0BmE46Biw89gk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;347&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;1410&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;RSS&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Resource Description Framework Site Summary&lt;/li&gt;
&lt;li&gt;웹 사이트의 제목이나 내용을 간단히 요약해 배포하기 위한 포맷&lt;/li&gt;
&lt;li&gt;주로 &lt;b&gt;업데이트 정보를 공개하는 데 사용&lt;/b&gt;된다.&lt;/li&gt;
&lt;li&gt;RSS 리더라는 소프트웨어를 이용해 RSS 정보를 취득하고 갱신 정보를 참조한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1436&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1iHZ9/btr6tYIieaL/zHEonzx9ytiuniBGtQQC5k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1iHZ9/btr6tYIieaL/zHEonzx9ytiuniBGtQQC5k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1iHZ9/btr6tYIieaL/zHEonzx9ytiuniBGtQQC5k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1iHZ9%2Fbtr6tYIieaL%2FzHEonzx9ytiuniBGtQQC5k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;350&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1436&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Dynamic DNS&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdGBX1/btr7s4u11VS/mSJAuxvU8efQKzbS0RAB4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdGBX1/btr7s4u11VS/mSJAuxvU8efQKzbS0RAB4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdGBX1/btr7s4u11VS/mSJAuxvU8efQKzbS0RAB4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdGBX1%2Fbtr7s4u11VS%2FmSJAuxvU8efQKzbS0RAB4k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;167&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자신이 소유하고 있는 데이터베이스 정보가 변경되면 즉시 통지하거나 변경 부분만 전송하는 기능이 있는 DNS&lt;/li&gt;
&lt;li&gt;갱신이 반영될 때까지 3일 정도 시간이 필요한 일반 DNS와 달리 변경 사항을 곧바로 통지하기 때문에 변경 사항이 전 세계에 즉시 반영된다.&lt;/li&gt;
&lt;li&gt;Dynamic DNS를 이용한 서브 도메인 발행 서비스를 이용하면, ADSL과 같이 IP 주소가 변하는 환경에서도 고정 도메인 이름을 사용하기 때문에 외부에서 엑세스가 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;클라우드&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;366&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1cT9p/btr7OynFvn9/pO5akbz0Y4LTuf3llrVK9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1cT9p/btr7OynFvn9/pO5akbz0Y4LTuf3llrVK9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1cT9p/btr7OynFvn9/pO5akbz0Y4LTuf3llrVK9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1cT9p%2Fbtr7OynFvn9%2FpO5akbz0Y4LTuf3llrVK9k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;124&quot; data-origin-width=&quot;1178&quot; data-origin-height=&quot;366&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷을 구름(cloud)에 빗대어 표현한 것으로, 네트워크 관리를 신경 쓰지 않고 서비스를 이용할 수 있는 클라우드 컴퓨팅의 약칭이다.&lt;/li&gt;
&lt;li&gt;데이터와 소프트웨어를 내 컴퓨터가 아닌 구름(인터넷)에 있는 서버가 관리하고, 사용자는 필요에 따라 여기에 접속해 사용하는 서비스 형태를 나타낸다. 예) 웹 메일 서비스(Gmail)&lt;/li&gt;
&lt;li&gt;접속 환경만 갖추면 클라우드형 서비스를 이용할 수 있으며, 도입 비용이 저렴하고 데이터 관리나 백업은 기본적으로 서비스를 제공하는 쪽에서 알아서 해준다는 장점이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/265</guid>
      <comments>https://jollyn.tistory.com/265#entry265comment</comments>
      <pubDate>Fri, 3 Mar 2023 13:36:07 +0900</pubDate>
    </item>
    <item>
      <title>커넥션 풀(Connection Pool)</title>
      <link>https://jollyn.tistory.com/263</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은&amp;nbsp;&lt;a href=&quot;https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-db-1/dashboard&quot;&gt;[인프런] 스프링 DB 1편 - 데이터 접근 핵심 원리&lt;/a&gt;을 강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;커넥션 풀이란?&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹 컨테이너(WAS)가 실행되면 &lt;b&gt;일정량의 커넥션을 미리 만들어 pool에 보관&lt;/b&gt;했다가, 클라이언트 요청이 오면 자신이 가지고 있는 커넥션을 빌려주고 임무가 완료되면 &lt;b&gt;다시 커넥션을 반납 받아&lt;/b&gt; pool에 보관하는 프로그래밍 기법이다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션 로직은 DB 드라이버를 통해&lt;b&gt; 커넥션을 조회&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;DB 드라이버는 &lt;b&gt;DB와 TCP/IP 커넥션을 연결&lt;/b&gt; (이때 3 way handshake 같은 TCP/IP 연결을 위한 네트워크 동작 발생)&lt;/li&gt;
&lt;li&gt;DB 드라이버는 TCP/IP 커넥션이&amp;nbsp; 연결되면 &lt;b&gt;ID, PW 같은 부가정보를 DB에게 전달&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;DB는 ID, PW를 통해 내부 인증을 한 뒤 내부에 &lt;b&gt;DB 세션을 생성&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;DB는 커넥션 생성이 완료되었다는 응답을 보냄&lt;/li&gt;
&lt;li&gt;DB 드라이버는 &lt;b&gt;커넥션 객체를 생성&lt;/b&gt;해 클라이언트에 &lt;b&gt;반환&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 과정은 매우 복잡하고 많은 시간이 소요된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;고객이 애플리케이션을 사용할 때 SQL을 실행하는 시간 뿐만 아니라 커넥션을 새로 만드는 시간까지 추가되어 응답 속도가 느려진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 문제를 해결하기 위해 &lt;b&gt;커넥션을 미리 생성해두고 사용&lt;/b&gt;하는 &lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;커넥션 풀&lt;/b&gt;&lt;/span&gt;&lt;b&gt;을 사용한다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;커넥션 풀 어떻게 쓸까?&lt;/b&gt;&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;몇 개의 커넥션을 보관할 지는 서비스마다 다르지만 기본값은 보통 10개이다.&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;커넥션 풀에 보관되어 있는 커넥션은 이미 TCP/IP로 DB와 연결되어 있는 상태이기 때문에 &lt;b&gt;즉시 SQL을 DB에 전달이 가능&lt;/b&gt;하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DB 드라이버를 통해 새로운 커넥션을 획득해서 사용하는 것이 아닌, 커넥션 풀을 통해 이미 생성되어 있는 커넥션을 객체 참조로 그냥 가져다 쓰기만 하면 되는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커넥션 풀에 커넥션을 요청하면 커넥션 풀은 자신이 가지고 있는 커넥션 중 하나를 반환한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플리케이션 로직은 &lt;b&gt;반환 받은 커넥션을 사용해 SQL을 DB에 전달하고 그 결과를 받아 처리&lt;/b&gt;한다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;&amp;rarr; 기존 커넥션을 새로 만드는 시간 절약됨!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;커넥션을 모두 사용한 후에는 커넥션을 종료하지 않고, 다시 사용할 수 있도록 해당 커넥션을 커넥션 풀에 그대로 반환해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(⭐️ &lt;b&gt;커넥션이 살아있는 상태로 반환&lt;/b&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;적절한 커넥션 풀의 숫자&lt;/b&gt;는 서비스의 특징, 애플리케이션 서버 스펙, DB 서버 스펙에 따라 다르기 때문에 &lt;b&gt;성능 테스트를 통해 결정&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li&gt;커넥션 풀은 &lt;b&gt;서버당 최대 커넥션 수를 제한할 수 있다&lt;/b&gt;. 따라서 DB에 무한정 연결 생성을 막아줘 &lt;b&gt;DB를 보호&lt;/b&gt;하는 효과도 있다.&lt;/li&gt;
&lt;li&gt;실무에서는 커넥션 풀을 항상 기본으로 사용&lt;/li&gt;
&lt;li&gt;커넥션 풀을 직접 구현할 수도 있지만, 뛰어난 오픈소스 커넥션 풀이 많아 &lt;b&gt;오픈소스 커넥션 풀을 사용&lt;/b&gt;하는 것이 좋다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ex) commons-dbcp2, tomcat-jdbc pool, &lt;b&gt;HikariCP&lt;/b&gt; 등&lt;/li&gt;
&lt;li&gt;성능과 사용의 편리함 측면에서 최근 대부분 HikariCP를 사용 (스프링 부트 2.0부터 기본 커넥션 풀로 제공)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/DB 접근기술</category>
      <category>커넥션 풀</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/263</guid>
      <comments>https://jollyn.tistory.com/263#entry263comment</comments>
      <pubDate>Thu, 2 Mar 2023 20:36:00 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 인터넷 기초</title>
      <link>https://jollyn.tistory.com/261</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;인터넷&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;708&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3PcWO/btr0hdmrn7h/JjaFNvEdoR8spU7yfzBxj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3PcWO/btr0hdmrn7h/JjaFNvEdoR8spU7yfzBxj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3PcWO/btr0hdmrn7h/JjaFNvEdoR8spU7yfzBxj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3PcWO%2Fbtr0hdmrn7h%2FJjaFNvEdoR8spU7yfzBxj1%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;250&quot; height=&quot;215&quot; data-origin-width=&quot;824&quot; data-origin-height=&quot;708&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;TCP/IP&lt;/b&gt;라는 패킷 통신 유형의 네트워크 프로토콜을 이용해 전 세계 규모로 서로 연결한 거대한 컴퓨터 네트워크&lt;/li&gt;
&lt;li&gt;현재 &lt;b&gt;WWW&lt;/b&gt;(World Wide Web)나 &lt;b&gt;전자 메일&lt;/b&gt; 같은 서비스가 주로 사용되고 있다.&lt;/li&gt;
&lt;li&gt;ISP(Internet Serivces Provider)라는 접속 사업자가 개인이 인터넷에 접속할 수 있도록 연결해준다.&lt;/li&gt;
&lt;li&gt;인터넷에서는 각 네트워크를 서로 연결하는 &lt;b&gt;라우터가 물통 릴레이처럼 패킷을 중계해 데이터를 주고 받는다&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;ISP&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;724&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdyFxK/btr0zFQltJY/wxHE9EszwT7PwfVlpMY5C0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdyFxK/btr0zFQltJY/wxHE9EszwT7PwfVlpMY5C0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdyFxK/btr0zFQltJY/wxHE9EszwT7PwfVlpMY5C0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdyFxK%2Fbtr0zFQltJY%2FwxHE9EszwT7PwfVlpMY5C0%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;250&quot; height=&quot;243&quot; data-origin-width=&quot;746&quot; data-origin-height=&quot;724&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Internet Services Provider의 약어&lt;/li&gt;
&lt;li&gt;인터넷 연결을 제공하는 서비스 공급자&lt;/li&gt;
&lt;li&gt;전화 회선이나 전용 회선을 사용해 일반 사용자의 요청을 받아 인터넷에 연결한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;과거 : 아날로그 모뎀을 사용한 다이얼업 접속 방법 사용&lt;/li&gt;
&lt;li&gt;최근 : ADSL, 광케이블과 같은 상시 접속 방법 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;인터넷 접속 제공 서비스 뿐만 아니라 이메일 주소 발급, 홈페이지 공간 대여 같은 서비스도 제공한다.&lt;/li&gt;
&lt;li&gt;ISP를 이용한 인터넷 접속은 인터넷에 연결되어 있는 LAN에 참가하려고 요청하는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;KRNIC&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;652&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SvdWv/btr0JA7h6Sb/8OC2VnsOskvSKGJlUEhL7K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SvdWv/btr0JA7h6Sb/8OC2VnsOskvSKGJlUEhL7K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SvdWv/btr0JA7h6Sb/8OC2VnsOskvSKGJlUEhL7K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSvdWv%2Fbtr0JA7h6Sb%2F8OC2VnsOskvSKGJlUEhL7K%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;450&quot; height=&quot;205&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;652&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Korea Network Information Center의 약어&lt;/li&gt;
&lt;li&gt;한국 인터넷 정보 센터로, &lt;b&gt;한국의 글로벌 IP 주소 할당&lt;/b&gt; 업무를 수행한다.&lt;/li&gt;
&lt;li&gt;인터넷에서 사용하는 공인 IP 주소는 전 세계를 통틀어 고유한 값이어야 하기 때문에 값이 중복되지 않도록 KRNIC라는 전문 기관에서 관리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;WWW&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;420&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/URXVY/btr0BXwhLhx/KuklVaa90bhyRnCg936U3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/URXVY/btr0BXwhLhx/KuklVaa90bhyRnCg936U3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/URXVY/btr0BXwhLhx/KuklVaa90bhyRnCg936U3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FURXVY%2Fbtr0BXwhLhx%2FKuklVaa90bhyRnCg936U3k%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;450&quot; height=&quot;132&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;420&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;World Wide Web의 약어로 WWW 혹은 Web이라 부른다.&lt;/li&gt;
&lt;li&gt;인터넷에서 표준으로 이용되고 있는 문서 시스템&lt;/li&gt;
&lt;li&gt;하나의 문서 내에 &lt;b&gt;이미지&lt;/b&gt;나 &lt;b&gt;음성&lt;/b&gt; 등 다양한 콘텐츠를 포함할 수 있고, &lt;b&gt;문서 간 링크&lt;/b&gt;를 설정해 문서끼리 서로 연결할 수 있다.&lt;/li&gt;
&lt;li&gt;WWW 문서는 HTML이라는 언어로 작성되어 있으며, 이 문서가 공개되어 있는 곳이 인터넷 상의 WWW 서버이다.&lt;br /&gt;&lt;b&gt;WWW 서버에 접속해 웹 브라우저라는 응용프로그램(사파리, 크롬 등)을 사용해 WWW 문서를 열람&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;웹 사이트&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biW0Sw/btr0HS1NYkQ/bQlcwswMZkwNes4O96SQ10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biW0Sw/btr0HS1NYkQ/bQlcwswMZkwNes4O96SQ10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biW0Sw/btr0HS1NYkQ/bQlcwswMZkwNes4O96SQ10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiW0Sw%2Fbtr0HS1NYkQ%2FbQlcwswMZkwNes4O96SQ10%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;235&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WWW 상에서 데이터나 파일이 한 곳에 모여 있는 장소
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 곳에 모여 있다? 여러 페이지로 나누어져 있는 정보를 모두 합쳐서 하나의 웹 사이트로 본다는 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;웹 사이트라고 하면 특정 페이지를 나타내지 않고 그 페이지의 모음을 의미하며, 개별 페이지는 웹 페이지라 표현한다.&lt;/li&gt;
&lt;li&gt;웹 사이트 주소를 기재할 때는 보통 해당 사이트의 메인이 되는 Top 페이지를 적는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;웹 브라우저&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;웹 사이트를 열람하기 위해 사용&lt;/b&gt;하는 응용프로그램 소프트웨어로, 줄여서 &quot;브라우저&quot;라고도 표현&lt;/li&gt;
&lt;li&gt;주로 인터넷에서 HTML 파일을 내려받아 텍스트를 변형하여 표시하는 역할을 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;1514&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dKQenn/btr0JA8KrWT/iwzAxxVmctWCIE33PNpK81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dKQenn/btr0JA8KrWT/iwzAxxVmctWCIE33PNpK81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dKQenn/btr0JA8KrWT/iwzAxxVmctWCIE33PNpK81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdKQenn%2Fbtr0JA8KrWT%2FiwzAxxVmctWCIE33PNpK81%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;425&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;1514&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;홈페이지&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;574&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Zp8Uf/btr07A0gNQr/7KdhdSe7qPsqAW27fk16cK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Zp8Uf/btr07A0gNQr/7KdhdSe7qPsqAW27fk16cK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Zp8Uf/btr07A0gNQr/7KdhdSe7qPsqAW27fk16cK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZp8Uf%2Fbtr07A0gNQr%2F7KdhdSe7qPsqAW27fk16cK%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;250&quot; height=&quot;184&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;574&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;본래는 웹 사이트를 실행했을 때 가장 먼저 표시되는 시작 화면을 의미&lt;/li&gt;
&lt;li&gt;하지만, WWW 상에서 데이터나 파일이 한 곳에 모여 있는 장소인 웹 사이트와 같은 의미로 사용되고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;URL&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Uniform Resource Locator의 약어&lt;/li&gt;
&lt;li&gt;인터넷 상에서 파일의 위치를 지정하기 위한 기술 형식이나 그에 의해 작성된 주소 그 자체&lt;/li&gt;
&lt;li&gt;WWW의 홈페이지 주소를 지정하기 위해 많이 사용된다.&lt;/li&gt;
&lt;li&gt;예) https://www.example.com/home/index.html&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;https &amp;rarr; 파일에 접근하는 방법, 프로토콜&lt;/li&gt;
&lt;li&gt;www.example.com &amp;rarr; 도메인 이름 (example.com 도메인에 속한 www라는 컴퓨터)&lt;/li&gt;
&lt;li&gt;home/index.html &amp;rarr; 파일명&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1240&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNVmYd/btr1blV3F7B/yTLz5dQIcuEoK1a7cG9Aq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNVmYd/btr1blV3F7B/yTLz5dQIcuEoK1a7cG9Aq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNVmYd/btr1blV3F7B/yTLz5dQIcuEoK1a7cG9Aq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNVmYd%2Fbtr1blV3F7B%2FyTLz5dQIcuEoK1a7cG9Aq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;353&quot; data-origin-width=&quot;1404&quot; data-origin-height=&quot;1240&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;전자 메일&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터 네트워크상에서 교환하는 편지&amp;nbsp;&lt;/li&gt;
&lt;li&gt;문서 외 다양한 파일을 첨부하여 보낼 수 있다.&lt;/li&gt;
&lt;li&gt;전자 메일을 사용하려면 전용 응용프로그램(메일러)를 사용해야 한다.&lt;/li&gt;
&lt;li&gt;송신된 전자 메일은 상대의 메일 서버에 보관되며, 상대방이 메일의 수신을 확인할 때 전달된다.&lt;/li&gt;
&lt;li&gt;전자 메일을 주고 받기 위해 ___@___co.kr과 같은 전자 메일 주소를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZC7pK/btr0RKvZUx4/QulXeQazyj80jfGARke2j0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZC7pK/btr0RKvZUx4/QulXeQazyj80jfGARke2j0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZC7pK/btr0RKvZUx4/QulXeQazyj80jfGARke2j0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZC7pK%2Fbtr0RKvZUx4%2FQulXeQazyj80jfGARke2j0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;240&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;유즈넷&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djAGjJ/btr07AUk2AG/ZsWvqkJzqckqoxYJv0srL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djAGjJ/btr07AUk2AG/ZsWvqkJzqckqoxYJv0srL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djAGjJ/btr07AUk2AG/ZsWvqkJzqckqoxYJv0srL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjAGjJ%2Fbtr07AUk2AG%2FZsWvqkJzqckqoxYJv0srL1%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;250&quot; height=&quot;219&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷의 전자 회의실 시스템&lt;/li&gt;
&lt;li&gt;사용자에 의한 정보 교환용 시스템으로 뉴스 그룹이라는 단위의 회의실로 나뉘어져 다양한 정보를 주고 받는다.&lt;/li&gt;
&lt;li&gt;유즈넷을 이용하기 위해서는 전용 응용프로그램이 많이 필요하며, 이 응용프로그램을 뉴스 리더라고 한다.&lt;/li&gt;
&lt;li&gt;인접한 뉴스 서버끼리 게시 내용을 전달하는 방식으로 세계 각지의 어느 뉴스 서버에서도 열람 가능하다.&lt;/li&gt;
&lt;li&gt;사용자가 감소함에 따라 현재는 거의 소멸되는 중&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포털 사이트&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹 브라우저를 실행할 때 처음 접속하는 웹 사이트&lt;/li&gt;
&lt;li&gt;예) 네이버나 구글 같은 검색 사이트&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;1014&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eayniE/btr0NN1HNQr/SKR1LjmFhnUGbgr6VD8Q1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eayniE/btr0NN1HNQr/SKR1LjmFhnUGbgr6VD8Q1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eayniE/btr0NN1HNQr/SKR1LjmFhnUGbgr6VD8Q1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeayniE%2Fbtr0NN1HNQr%2FSKR1LjmFhnUGbgr6VD8Q1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;284&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;1014&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;검색 사이트&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷에 공개된 정보를 키워드 등을 사용해 검색할 수 있는 웹 사이트&lt;/li&gt;
&lt;li&gt;서치 엔진, 검색 엔진이라고도 부름&lt;/li&gt;
&lt;li&gt;네이버, 구글이 대표적&lt;/li&gt;
&lt;li&gt;검색 사이트는 크게 전문 검색형, 디렉터리형으로 나눌수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;518&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcAPZI/btr1yz7ZR5A/6iwzBgLKtruP3XRVX9gK9K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcAPZI/btr1yz7ZR5A/6iwzBgLKtruP3XRVX9gK9K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcAPZI/btr1yz7ZR5A/6iwzBgLKtruP3XRVX9gK9K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbcAPZI%2Fbtr1yz7ZR5A%2F6iwzBgLKtruP3XRVX9gK9K%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;1806&quot; height=&quot;518&quot; data-origin-width=&quot;1806&quot; data-origin-height=&quot;518&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/261</guid>
      <comments>https://jollyn.tistory.com/261#entry261comment</comments>
      <pubDate>Wed, 22 Feb 2023 17:36:17 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 서비스와 프로토콜</title>
      <link>https://jollyn.tistory.com/258</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DNS&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Domain Name System의 약어&lt;/li&gt;
&lt;li&gt;도메인 이름(컴퓨터 이름)으로&lt;b&gt; IP 주소를 알아내는 서비스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;DNS 서비스가 실행되고 있는 컴퓨터를 &lt;b&gt;DNS 서버&lt;/b&gt;라고 하며, 서버 내에 도메인 이름과 IP 주소가 있는 데이터베이스를 관리한다.&lt;/li&gt;
&lt;li&gt;DNS 서버에게 물으면 데이터베이스를 검색해 도메인 이름에 해당하는 IP 주소를 반환해준다.&lt;br /&gt;&amp;rarr; 클라이언트는 이 IP 주소를 기반으로 통신&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1478&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dVPy0A/btrZjyK7aya/ZtE405zgWNatK6d4fSUr0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dVPy0A/btrZjyK7aya/ZtE405zgWNatK6d4fSUr0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dVPy0A/btrZjyK7aya/ZtE405zgWNatK6d4fSUr0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdVPy0A%2FbtrZjyK7aya%2FZtE405zgWNatK6d4fSUr0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;1478&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;1478&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;DHCP&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;580&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beI4Wk/btrZiQyZhd4/Y6WVXRGx6KmcdW8D5K1Rf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beI4Wk/btrZiQyZhd4/Y6WVXRGx6KmcdW8D5K1Rf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beI4Wk/btrZiQyZhd4/Y6WVXRGx6KmcdW8D5K1Rf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbeI4Wk%2FbtrZiQyZhd4%2FY6WVXRGx6KmcdW8D5K1Rf0%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;250&quot; height=&quot;195&quot; data-origin-width=&quot;744&quot; data-origin-height=&quot;580&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Dynamic Host Configuration Protocol의 약어&lt;/li&gt;
&lt;li&gt;컴퓨터에 IP 주소나 서브넷 마스크 같은 &lt;b&gt;네트워크 관련 설정을 자동으로 수행하는 서비스&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;DHCP를 사용하는 네트워크 환경에서 클라이언트가 요청하면 해당 네트워크를 이용하기 위한 각종 설정과 사용할 수 있는 IP 주소를 발급한다.&lt;br /&gt;&amp;rarr; 네트워크 접속에 필요한 모든 설정&lt;b&gt; 자동화&lt;br /&gt;&lt;/b&gt;&amp;rarr; 관리 노력 &amp;darr;&lt;br /&gt;&amp;rarr; 클라이언트의 설정 오류로 인한 문제 발생 X&lt;/li&gt;
&lt;li&gt;ISP(Internet Services Provider)로 인터넷에 접속할 경우 DHCP를 사용해 서버에서 네트워크 설정을 취득하는 것이 일반적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NetBIOS&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rReLT/btrZInnVBAR/nXNSmev4I8GWTKNOz7BmhK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rReLT/btrZInnVBAR/nXNSmev4I8GWTKNOz7BmhK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rReLT/btrZInnVBAR/nXNSmev4I8GWTKNOz7BmhK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrReLT%2FbtrZInnVBAR%2FnXNSmev4I8GWTKNOz7BmhK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;155&quot; data-origin-width=&quot;1428&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Network Basic Input/Output System의 약어로, 네트워크 기본 입출력 시스템을 의미&lt;/li&gt;
&lt;li&gt;네트워크 서비스를 이용하기 위한 &lt;b&gt;기본적인 입출력을 정의한 애플리케이션 프로그래밍 인터페이스&lt;/b&gt;(API)이다.&lt;/li&gt;
&lt;li&gt;OSI 참조 모델의 4번째 계층인 &lt;b&gt;전송 계층&lt;/b&gt;에 해당하는 서비스를 제공&lt;/li&gt;
&lt;li&gt;네트워크 서비스를 이용하는 프로그램은 NetBIOS를 호출해 파일 공유나 프린터 공유같은 기능을 구현한다.&lt;/li&gt;
&lt;li&gt;TCP/IP를 기본 프로토콜로 동작하는 NetBIOS를 &lt;b&gt;NBT&lt;/b&gt;(NETBIOS over TCP/IP)라고 한다.&lt;/li&gt;
&lt;li&gt;NetBIOS에 의해 구성된 네트워크에서는 16바이트짜리 NetBIOS 이름을 사용해 컴퓨터를 식별한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PPP&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oOsB7/btrZInhfhb9/lKIyR8HI0bwVtOnXVRukvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oOsB7/btrZInhfhb9/lKIyR8HI0bwVtOnXVRukvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oOsB7/btrZInhfhb9/lKIyR8HI0bwVtOnXVRukvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoOsB7%2FbtrZInhfhb9%2FlKIyR8HI0bwVtOnXVRukvK%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;250&quot; height=&quot;199&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Point to Point Protocol의 약어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;두 지점 사이를 연결하여 그 회선을 네트워크 회선으로 사용할 수 있도록 하는 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;OSI 참조 모델의 2계층인 데이터 링크 계층에 위치하며, 3계층 이상의 프로토콜과 조합해 이용한다.&lt;/li&gt;
&lt;li&gt;전화 회선을 사용해 컴퓨터를 네트워크에 연결할 때 자주 사용된다.&lt;/li&gt;
&lt;li&gt;PPP 접속 과정
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;맨 처음에 &lt;b&gt;사용자 인증&lt;/b&gt;을 실시&lt;/li&gt;
&lt;li&gt;인증이 완료되면 회선에서 사용할 프로토콜 등을 결정하여 그 회선을 &lt;b&gt;통신 경로로 확정&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;통신 경로가 확정되면 &lt;b&gt;TCP/IP 등의 프로토콜을 사용해 통신&lt;/b&gt; 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PPPoE&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;666&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2qSLU/btrZISHODL4/5x3dP3v7IR2bF7TGjlATd1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2qSLU/btrZISHODL4/5x3dP3v7IR2bF7TGjlATd1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2qSLU/btrZISHODL4/5x3dP3v7IR2bF7TGjlATd1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2qSLU%2FbtrZISHODL4%2F5x3dP3v7IR2bF7TGjlATd1%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;250&quot; height=&quot;225&quot; data-origin-width=&quot;740&quot; data-origin-height=&quot;666&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;PPP over Ethernet의 약어&lt;/li&gt;
&lt;li&gt;두 노드 사이를 연결해 통신하는데 사용하는 프로토콜인 &lt;b&gt;PPP를 이더넷에서 구현하기 위한 프로토콜&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;현재 ADSL에 의한 인터넷 접속 서비스의 대부분이 PPPoE 이용 + 가정용 라우터에서도 이용 증가 추세&lt;/li&gt;
&lt;li&gt;PPP와 마찬가지로 &lt;b&gt;인증을 실시해 두 지점 간 연결을 확정&lt;/b&gt;한다.&lt;/li&gt;
&lt;li&gt;이를 통해 일반 다이얼업 접속과 ADSL 접속 서비스를 모두 통합해 운영할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;430&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/coPVYn/btrZIKC3727/R8aqnimkjAf9b7b06AHq1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/coPVYn/btrZIKC3727/R8aqnimkjAf9b7b06AHq1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/coPVYn/btrZIKC3727/R8aqnimkjAf9b7b06AHq1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcoPVYn%2FbtrZIKC3727%2FR8aqnimkjAf9b7b06AHq1k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;151&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;430&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;PPTP&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Point-to-Point Tunneling Protocol의 약어&lt;/li&gt;
&lt;li&gt;PPP를 확장하여 TCP/IP 네트워크에 &lt;b&gt;가상으로 다이얼업 연결&lt;/b&gt;을 하기 위한 프로토콜&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;VPN 구축에 사용&lt;/b&gt;하는 암호화 기술 중 하나&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;인터넷 같은 불특정 다수의 사용자가 접속하는 네트워크에 &lt;/span&gt;&lt;b&gt;안전한 통신 경로를 확정하기 위해 사용&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;PPTP의&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;터널링 처리&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 지점 간 연결이 확정되면 PPP의 &lt;b&gt;데이터 패킷을 암호화&lt;/b&gt;한 후 IP 패킷에 추가하여 TCP/IP 네트워크로 전송&lt;/li&gt;
&lt;li&gt;본래 패킷이 은폐되어 통신 경로에서의 안전 보증&lt;/li&gt;
&lt;li&gt;이를 &lt;b&gt;접속이 확정된 두 지점 간을 안전한 전용 터널로 보호&lt;/b&gt;하는 처리, 즉 &quot;터널링 처리&quot;라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2170&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AjRQ3/btrZGXRhtQB/3Tzul8NeakZI0qG0ugvdY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AjRQ3/btrZGXRhtQB/3Tzul8NeakZI0qG0ugvdY1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AjRQ3/btrZGXRhtQB/3Tzul8NeakZI0qG0ugvdY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAjRQ3%2FbtrZGXRhtQB%2F3Tzul8NeakZI0qG0ugvdY1%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;2170&quot; height=&quot;346&quot; data-origin-width=&quot;2170&quot; data-origin-height=&quot;346&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;방화벽&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sCwSn/btrZ6jkClxv/fIwOxTWwsnzDi52E5K2edK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sCwSn/btrZ6jkClxv/fIwOxTWwsnzDi52E5K2edK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sCwSn/btrZ6jkClxv/fIwOxTWwsnzDi52E5K2edK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsCwSn%2FbtrZ6jkClxv%2FfIwOxTWwsnzDi52E5K2edK%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;250&quot; height=&quot;215&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;조직 내부의 로컬 네트워크와 인터넷 같은 외부 네트워크 사이에 설치하는 시스템으로, 외부로부터의 침입을 막는 역할&lt;/li&gt;
&lt;li&gt;내부 네트워크와 외부 네트워크 사이의 경계에 설치해 모든 통신을 차단하지만, 전부 차단하면 통신이 안되기 때문에 필요한 서비스에 대해서만 통과하도록 설정&lt;/li&gt;
&lt;li&gt;기능적인 역할만 할 뿐, 정해진 형태는 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;프록시 서버&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yxAUj/btrZ4b1ty1N/YAvEyNqw9KqgmGTy81DLqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yxAUj/btrZ4b1ty1N/YAvEyNqw9KqgmGTy81DLqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yxAUj/btrZ4b1ty1N/YAvEyNqw9KqgmGTy81DLqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyxAUj%2FbtrZ4b1ty1N%2FYAvEyNqw9KqgmGTy81DLqk%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;250&quot; height=&quot;211&quot; data-origin-width=&quot;830&quot; data-origin-height=&quot;700&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;대체 서버, 내부 네트워크의 컴퓨터를 대신해 외부 네트워크에 액세스하는 서버&lt;/li&gt;
&lt;li&gt;일반적으로 내부 네트워크와 외부 네트워크를 차단하는 &lt;b&gt;방화벽에서 실행&lt;/b&gt;된다.&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;외부에서 내부로의 액세스는 방화벽이 차단&lt;/li&gt;
&lt;li&gt;내부에서 외부로의 액세스는 프록시 서버가 대행 &amp;rarr; 네트워크 안정성 유지&lt;/li&gt;
&lt;li&gt;예) 특정 웹 사이트를 열람하고 싶은 경우 클라이언트에서 &quot;이 URL의 페이지를 원한다&quot;라는 요청을 프록시 서버에 전송, 프록시 서버가 대행하여 다운로드한 데이터를 클라이언트에 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1410&quot; data-origin-height=&quot;510&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zye9Q/btrZNLpEC7m/4ij0pkO8xfxbxBkAkSMaZ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zye9Q/btrZNLpEC7m/4ij0pkO8xfxbxBkAkSMaZ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zye9Q/btrZNLpEC7m/4ij0pkO8xfxbxBkAkSMaZ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fzye9Q%2FbtrZNLpEC7m%2F4ij0pkO8xfxbxBkAkSMaZ0%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;450&quot; height=&quot;163&quot; data-origin-width=&quot;1410&quot; data-origin-height=&quot;510&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;패킷 필터링&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;822&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baQh3K/btrZ9G8m7Bi/f1oR7yiJywinyDWuFGkBZ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baQh3K/btrZ9G8m7Bi/f1oR7yiJywinyDWuFGkBZ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baQh3K/btrZ9G8m7Bi/f1oR7yiJywinyDWuFGkBZ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaQh3K%2FbtrZ9G8m7Bi%2Ff1oR7yiJywinyDWuFGkBZ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;231&quot; data-origin-width=&quot;1424&quot; data-origin-height=&quot;822&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;라우터&lt;/b&gt;가 가진 기능 중 하나로, 미리 &lt;b&gt;정해진 규칙에 따라 통과하는 패킷을 제어&lt;/b&gt;하는 기능&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방화벽 구축 방법&lt;/b&gt; 중 가장 기본적인 방법&lt;/li&gt;
&lt;li&gt;허가되지 않는 패킷은 필터에 걸러져 모두 파기된다.&lt;/li&gt;
&lt;li&gt;어떤 패킷을 통과시킬지에 대한 규칙은 IP 주소나 TCP 등의 &lt;b&gt;프로토콜, 포트 번호에 따라 지정&lt;br /&gt;&amp;rarr; &lt;/b&gt;일반적으로 애플리케이션이 제공하는 서비스가 프로토콜과 포트 번호로 구별되기 때문에 이를 지정하여&lt;br /&gt;&amp;nbsp; &amp;nbsp; '&lt;b&gt;어떤 서비스를 통과시킬지'&lt;/b&gt;를 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NAT&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;678&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vqEQ8/btr0aPKOkQA/C9wKiXEMm6xzbm6gcUKrt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vqEQ8/btr0aPKOkQA/C9wKiXEMm6xzbm6gcUKrt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vqEQ8/btr0aPKOkQA/C9wKiXEMm6xzbm6gcUKrt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvqEQ8%2Fbtr0aPKOkQA%2FC9wKiXEMm6xzbm6gcUKrt0%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;250&quot; height=&quot;233&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Natwork Address Translation의 약어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사설 IP 주소와 공인 IP 주소를 일대일로 상호 변환&lt;/b&gt;하는 기술
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;인터넷에서는 공인 IP 주소를 사용해 통신&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;그런데 IP 주소는 32비트 숫자로 발행할 수 있는 수에 한계가 있기 때문에&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;LAN에서는 각 컴퓨터에 사설 IP 주소를 할당해 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;사설 IP만으로는 인터넷과 통신할 수 없기 때문에 인터넷에 액세스할 때만 NAT을 사용해 공인 IP 주소로 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;라우터 등에 많이 구현되어 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패킷을 재작성&lt;/b&gt;해 주소 변환
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷으로 나가는 패킷은 송신처 IP 주소를 NAT에서 관리하는 공인 IP 주소로 재작성해 전송&lt;/li&gt;
&lt;li&gt;인터넷에서 받은 패킷은 송신처 IP 주소를 사설 IP 주소에 재작성해 LAN에 전송&lt;/li&gt;
&lt;li&gt;내부에서는 사설 IP 주소를 사용, 외부와의 통신에는 자동으로 공인 IP 주소 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일대일로 주소 변환이 이뤄지기 때문에 &lt;b&gt;공인 IP 주소의 수 이상으로 동시에 인터넷과 통신 불가&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;920&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UdORg/btrZ5j1g48O/Wzx3kzciaKadKGyJZgcYyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UdORg/btrZ5j1g48O/Wzx3kzciaKadKGyJZgcYyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UdORg/btrZ5j1g48O/Wzx3kzciaKadKGyJZgcYyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUdORg%2FbtrZ5j1g48O%2FWzx3kzciaKadKGyJZgcYyk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;259&quot; data-origin-width=&quot;1420&quot; data-origin-height=&quot;920&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;IP 마스커레이드(NAPT)&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/md7mk/btr0hd7IULD/dBEY6AiI1DI4HpWgB1deq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/md7mk/btr0hd7IULD/dBEY6AiI1DI4HpWgB1deq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/md7mk/btr0hd7IULD/dBEY6AiI1DI4HpWgB1deq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fmd7mk%2Fbtr0hd7IULD%2FdBEY6AiI1DI4HpWgB1deq0%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;250&quot; height=&quot;217&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Network Address Port Translation의 약어&lt;/li&gt;
&lt;li&gt;LAN에서 사용하는 사설 IP 주소와 인터넷에서 사용하는 공인 IP 주소를&lt;b&gt; 일 대 다수&lt;/b&gt;로 상호 변환하는 기술&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사설 IP 주소와 공인 IP 주소를 일대일로 변환하는 NAT와 달리, IP 마스커레이드는 &lt;b&gt;TCP나 UDP 포트 번호까지 포함해서 변환하기 때문에 일 대 다수 변환이 가능&lt;/b&gt;하다.&lt;/li&gt;
&lt;li&gt;따라서 공인 IP 주소가 하나밖에 없는 환경에서도 &lt;b&gt;여러 컴퓨터가 동시에 인터넷 접속이 가능&lt;/b&gt;하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;주로 라우터 등에 많이 구현되어 있음&lt;/li&gt;
&lt;li&gt;일부 애플리케이션이 동작하지 않는 제약 발생
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;애플리케이션에 따라 통신에 사용하는 포트 번호를 고정하는 경우, 포트 번호까지 변환하는 IP 마스커레이드는 이용할 수 없음&lt;/li&gt;
&lt;li&gt;동일한 IP 주소에서의 접속은 하나로 한정하는 애플리케이션의 경우 여러 사용자가 동시에 서비스를 받을 수 없음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;1474&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cX4ktg/btr0hp1gqBg/LVMFFtc3kDGk3NepfhRB7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cX4ktg/btr0hp1gqBg/LVMFFtc3kDGk3NepfhRB7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cX4ktg/btr0hp1gqBg/LVMFFtc3kDGk3NepfhRB7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcX4ktg%2Fbtr0hp1gqBg%2FLVMFFtc3kDGk3NepfhRB7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;412&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;1474&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <category>네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/258</guid>
      <comments>https://jollyn.tistory.com/258#entry258comment</comments>
      <pubDate>Wed, 15 Feb 2023 12:59:39 +0900</pubDate>
    </item>
    <item>
      <title>MySQL 잘 사용하기 (1)</title>
      <link>https://jollyn.tistory.com/257</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;트랜잭션 (Transaction)&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt;&lt;span&gt;트랜잭션이란 &lt;/span&gt;데이터베이스의 상태를 변화시키기 해서 수행하는 작업의 단위를 뜻한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작업의 완전성 보장&lt;/li&gt;
&lt;li&gt;사용자의 작업셋을 모두 완벽하게 처리(커밋)하거나 처리하지 못하면 원상태로 복구(롤백)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;MySQL 스토리지 엔진&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SQL 엔진 vs 스토리지 엔진&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MyISAM&lt;/li&gt;
&lt;li&gt;&lt;b&gt;InnoDB&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;memory&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;InnoDB&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요즘은 다 InnoDB를 사용하는 추세이다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션 지원&lt;/li&gt;
&lt;li&gt;FK &amp;rarr; 관계형 데이터 베이스 사용 가능&lt;/li&gt;
&lt;li&gt;버퍼링 : 작업을 Buffer pool에 쌓아두었다가 한번에 처리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Database Lock&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Lock 단어 그대로 &quot;잠금&quot;의 의미를 갖는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 데이터를 동시에 여러 명이 조작할 수 없도록 잠그는 것으로, 동시성(concurrency)를 보장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 엔진락과 InnoDB락이 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;MySQL 엔진 락&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;글로벌 락&lt;/b&gt; : 전반적인 모든 조작을 멈춤&lt;/li&gt;
&lt;li&gt;&lt;b&gt;테이블 락&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 테이블을 대상으로 조작을 멈춤&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Read Lock : 데이터를 읽으려고 하니까 입력하지 못하도록 락을 걸음 &amp;rarr; INSERT 안됨&lt;/li&gt;
&lt;li&gt;Write Lock&amp;nbsp; : 데이터를 쓰려고 하니까 읽지못하도록 락을 걸음 &amp;rarr; SELECT 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네임드 락&lt;/b&gt; : 임의로 시간동안 조작 권한을 갖는 락을 획득&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메타데이터 락&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;InnoDB의 락 종류&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;레코드 락&lt;/b&gt; : 테이블의 row을 대상으로 락을 걸음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Auto Increment&lt;/b&gt; :&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&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;span&gt;릴리즈가 잘 처리되지 않아&lt;span&gt; 이미 연결이 끊겼음에도 락이 유지되고 있는 듯이 제한이 풀리지 않는다고 생각하면 된다.&lt;/span&gt;&lt;/span&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;&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;&lt;b&gt;격리 수준 (Isolation Level)&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Read Uncommitted&lt;/b&gt; : 커밋되지 않을 것을 읽을 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Read Committed&lt;/b&gt; : 커밋된 것을 읽을 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Repeatable Read&lt;/b&gt; (default) : 계속 읽을 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Serializable&lt;/b&gt; : 트랜잭션간 &lt;span&gt;완전히&lt;span&gt; &lt;/span&gt;&lt;/span&gt;격리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Read Uncommitted&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  터미널1&lt;/p&gt;
&lt;pre id=&quot;code_1676034041167&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1. 오토커밋 해제 및 격리수준 변경
set @@autocommit=0;
SELECT @@autocommit;
set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT @@transaction_isolation;

-- 4. 트랜잭션 시작하고 데이터 삽입
start transaction;
INSERT into test_table (id) values (123);

-- 6. 데이터 조회 (삽입한 데이터 보임)
SELECT * FROM test_table;

-- 7. 커밋 안하고 되돌리기로 마무리
rollback;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  터미널2&lt;/p&gt;
&lt;pre id=&quot;code_1676034056799&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 2. 격리수준 변경
set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT @@transaction_isolation;

-- 3. 데이터 조회 (터미널1에서 트랜잭션 시작 전)
SELECT * FROM test_table;

-- 5. 데이터 조회 (터미널1에서 삽입한 커밋전의 데이터가 보임)
SELECT * FROM test_table;&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;</description>
      <category>  Computer Science/데이터베이스</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/257</guid>
      <comments>https://jollyn.tistory.com/257#entry257comment</comments>
      <pubDate>Fri, 10 Feb 2023 21:58:57 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 하드웨어</title>
      <link>https://jollyn.tistory.com/255</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NIC&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;638&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/263jz/btrX2mYQsxB/DksmKZlUzkiTiHyItkLMe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/263jz/btrX2mYQsxB/DksmKZlUzkiTiHyItkLMe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/263jz/btrX2mYQsxB/DksmKZlUzkiTiHyItkLMe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F263jz%2FbtrX2mYQsxB%2FDksmKZlUzkiTiHyItkLMe1%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;300&quot; height=&quot;238&quot; data-origin-width=&quot;804&quot; data-origin-height=&quot;638&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Network Interface Card의 약어&lt;/li&gt;
&lt;li&gt;컴퓨터에 네트워크를 연결하기 위한 확장 카드&lt;/li&gt;
&lt;li&gt;두번째 링크 계층에서 작동하는 네트워크 구성 요소&lt;/li&gt;
&lt;li&gt;다른 말로 &quot;LAN 보드&quot;, &quot;LAN 카드&quot;, &quot;LAN 어댑터&quot;라고 표현하기도 한다.&lt;/li&gt;
&lt;li&gt;NIC는 변환기 역할을 해서 케이블에서의 단순 전기 신호를 디지털 신호로 변환해 컴퓨터에 전송된다.&lt;/li&gt;
&lt;li&gt;컴퓨터에 장착된 NIC에 LAN 케이블을 연결해 컴퓨터와 네트워크를 연결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;608&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPtwlB/btrX3ZhwjzM/PVHQ2yojc7faonQBUBb0i0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPtwlB/btrX3ZhwjzM/PVHQ2yojc7faonQBUBb0i0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPtwlB/btrX3ZhwjzM/PVHQ2yojc7faonQBUBb0i0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPtwlB%2FbtrX3ZhwjzM%2FPVHQ2yojc7faonQBUBb0i0%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;450&quot; height=&quot;191&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;608&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;LAN 케이블&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 컴퓨터를 네트워크에 연결하기 위해 사용하는 케이블&lt;/li&gt;
&lt;li&gt;전기 신호로 변환된 통신 데이터가 전송되는 경로로, LAN 케이블을 연결해 컴퓨터끼리 데이터를 주고받을 수 있다.&lt;/li&gt;
&lt;li&gt;사용하는 네트워크 규격에 따라 LAN 케이블의 종류가 다르다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BbWS4/btrX7YktTlA/NwONldv9C7wUNMDd2dgzP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BbWS4/btrX7YktTlA/NwONldv9C7wUNMDd2dgzP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BbWS4/btrX7YktTlA/NwONldv9C7wUNMDd2dgzP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBbWS4%2FbtrX7YktTlA%2FNwONldv9C7wUNMDd2dgzP0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;240&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;482&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;리피터&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;330&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dmNq72/btrYjC7JIlM/5as0LA0EjR62DeOfWYO0c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dmNq72/btrYjC7JIlM/5as0LA0EjR62DeOfWYO0c1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dmNq72/btrYjC7JIlM/5as0LA0EjR62DeOfWYO0c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdmNq72%2FbtrYjC7JIlM%2F5as0LA0EjR62DeOfWYO0c1%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;450&quot; height=&quot;122&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;330&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OSI 참조 모델 1계층인 &lt;b&gt;물리 계층&lt;/b&gt;에서 동작하는 장치&lt;/li&gt;
&lt;li&gt;LAN 케이블에 보내는 신호를 수신하여 &lt;b&gt;신호를 증폭한 후 다음 구간으로 재전송&lt;/b&gt;하는 역할 &amp;rarr; 증폭기&lt;/li&gt;
&lt;li&gt;네트워크는 LAN 케이블에 전기 신호를 보내서 통신 데이터를 전송하는데, 그러나 케이블이 길어지면 그 안에 흐르는 전기 신호가 감쇠하여 결국 해석할 수 없는 신호가 된다. 이때 &lt;b&gt;리피터가 감쇠한 전기 신호를 증폭해 재전송&lt;/b&gt;하여 케이블의 총 연장 거리를 늘릴 수 있다.&lt;/li&gt;
&lt;li&gt;하지만 입력된 파형을 증폭해 송출하기 때문에 불필요한 통신 패킷도 중계된다는 문제가 있다.&lt;/li&gt;
&lt;li&gt;리피터는 상한이 정해져 있다. 그 이유는 너무 많은 리피터를 거치면 신호가 왜곡되고 총 연장 거리가 너무 길어질 경우 콜리전(신호 출돌) 감지가 잘 동작하지 않기 때문이다.&lt;/li&gt;
&lt;li&gt;리피터를 여러 개 묶어서 멀티 포트로 사용하는 것을 &lt;b&gt;허브&lt;/b&gt;라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;브리지&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDaYcA/btrYpmYEMaJ/GJjHapDVHBXvS6tJUVuXiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDaYcA/btrYpmYEMaJ/GJjHapDVHBXvS6tJUVuXiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDaYcA/btrYpmYEMaJ/GJjHapDVHBXvS6tJUVuXiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDaYcA%2FbtrYpmYEMaJ%2FGJjHapDVHBXvS6tJUVuXiK%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;300&quot; height=&quot;255&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OSI 참조 모델 2계층인 &lt;b&gt;데이터 링크 계층&lt;/b&gt;에서 동작하는 장치&lt;/li&gt;
&lt;li&gt;서로 다른 세그먼트 사이를 연결하는 역할&lt;/li&gt;
&lt;li&gt;브리지는 수신된 패킷의 물리 주소(MAC 주소)를 기억해 네트워크상에서 패킷의 흐름을 제어한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MAC 주소를 바탕으로 주소테이블을 작성&lt;/li&gt;
&lt;li&gt;주소 테이블에 수신 패킷의 수신지가 있으면 해당 주소가 속해 있는 세그먼트에만 패킷을 전달&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;중계한 패킷을 전송할 때는 CSMA/CD 방식을 따르기 때문에 콜리전의 발생을 억제할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;라우터&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;642&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c00whY/btrYkD7ZsBA/kkEKwkRyGbNdDm20ABdYpk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c00whY/btrYkD7ZsBA/kkEKwkRyGbNdDm20ABdYpk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c00whY/btrYkD7ZsBA/kkEKwkRyGbNdDm20ABdYpk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc00whY%2FbtrYkD7ZsBA%2FkkEKwkRyGbNdDm20ABdYpk%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;300&quot; height=&quot;263&quot; data-origin-width=&quot;732&quot; data-origin-height=&quot;642&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OSI 참조 모델 3계층인 &lt;b&gt;네트워크 계층&lt;/b&gt;에서 동작하는 장치&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서로 다른 네트워크를 상호 연결&lt;/b&gt;하기 위해 사용&lt;/li&gt;
&lt;li&gt;네트워크 프로토콜 수준에서 경로 정보(라우팅 테이블)을 관리&lt;/li&gt;
&lt;li&gt;패킷의 IP 주소를 기반으로 수신지를 선택해 네트워크의 중계 역할을 담당한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;IP 주소 = 집주소, 라우터 = 우체국&lt;/li&gt;
&lt;li&gt;IP 주소를 바탕으로 수신지가 자신이 속한 네트워크 내에 있다면 외부로 송신하지 않음&lt;/li&gt;
&lt;li&gt;수신지가 외부의 네트워크인 경우 그쪽 네트워크를 담당하는 라우터에 패킷을 전송&lt;/li&gt;
&lt;li&gt;하지면 인터넷은 매우 방대하기 때문에 직접 수신지가 속한 네트워크에 전송하는 것은 불가능하다.&lt;/li&gt;
&lt;li&gt;따라서 몇 단계의 라우터를 거쳐서 최종 목적지 네트워크에 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;332&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uKFbu/btrYlzYF7bg/CtAn2mV8FE7G5KijQWV4Ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uKFbu/btrYlzYF7bg/CtAn2mV8FE7G5KijQWV4Ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uKFbu/btrYlzYF7bg/CtAn2mV8FE7G5KijQWV4Ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuKFbu%2FbtrYlzYF7bg%2FCtAn2mV8FE7G5KijQWV4Ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;116&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;332&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;허브&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;602&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbRFzn/btrYzkle3kR/CptCcJmgEAW8Lu2Or9lMl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbRFzn/btrYzkle3kR/CptCcJmgEAW8Lu2Or9lMl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbRFzn/btrYzkle3kR/CptCcJmgEAW8Lu2Or9lMl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbRFzn%2FbtrYzkle3kR%2FCptCcJmgEAW8Lu2Or9lMl1%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;450&quot; height=&quot;189&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;602&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;여러 개의 LAN 케이블을 연결&lt;/b&gt;하는 집선 장치&lt;/li&gt;
&lt;li&gt;내부적으로 리피터를 여러개 묶은 것으로 &quot;&lt;b&gt;멀티 포트 리피터&lt;/b&gt;&quot;, &quot;&lt;b&gt;리피터 허브&lt;/b&gt;&quot;라고도 부른다.&lt;/li&gt;
&lt;li&gt;허브에는 LAN 케이블 연결용 포트가 여러개 있으며, 이 포트에 컴퓨터를 연결한다.&lt;/li&gt;
&lt;li&gt;리피터와 마찬가지로 입력된 것을 단순히 증폭하여 송출하기 때문에 &lt;b&gt;송신된 데이터는 모든 포트로 전달&lt;/b&gt;된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스위칭 허브&lt;/b&gt; &lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/djRHRn/btrYszxcAMh/bKwawxp6wdL6aTrUI3bQt0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/djRHRn/btrYszxcAMh/bKwawxp6wdL6aTrUI3bQt0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/djRHRn/btrYszxcAMh/bKwawxp6wdL6aTrUI3bQt0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdjRHRn%2FbtrYszxcAMh%2FbKwawxp6wdL6aTrUI3bQt0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;192&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1430&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;스위칭 기능&lt;/b&gt;을 가진 허브
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스위칭 기능 : 허브가 가진 여러 포트 중 &lt;b&gt;실제 통신이 발생한 포트만&lt;/b&gt; 직접 연결하여 &lt;b&gt;패킷을 전달&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;따라서 다른 포트는 동시에 다른 통신 불가능&lt;/li&gt;
&lt;li&gt;패킷 충돌을 억제하므로 &lt;b&gt;네트워크 효율성 up&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;리피터의 집합체인 허브(리피터 허브)와 달리 스위칭 허브는 브리지를 멀티 포트화한 것으로 &quot;&lt;b&gt;멀티 포트 브리지&lt;/b&gt;&quot;라고도 부른다.&lt;/li&gt;
&lt;li&gt;스위칭 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;패킷 수신 시 그 패킷을 보낸&lt;b&gt; 포트&lt;/b&gt;와, 수신지의 &lt;b&gt;MAC 주소&lt;/b&gt;를 기억해 테이블을 만든다.&lt;/li&gt;
&lt;li&gt;이 테이블을 통해 어떤 포트에 어떤 MAC 주소를 가진 기기가 접속되어 있는지 관리하며 포트 분배를 진행한다.&lt;/li&gt;
&lt;li&gt;일부 포트가 통신 중이어도 비어 있는 다른 포트끼리 통신할 수 있어 대역을 유용하게 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;모뎀&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;344&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XYtwK/btrYz8lLJBE/dsiSpNOEdvQ1VEK7K7nZs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XYtwK/btrYz8lLJBE/dsiSpNOEdvQ1VEK7K7nZs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XYtwK/btrYz8lLJBE/dsiSpNOEdvQ1VEK7K7nZs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXYtwK%2FbtrYz8lLJBE%2FdsiSpNOEdvQ1VEK7K7nZs0%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;650&quot; height=&quot;165&quot; data-origin-width=&quot;1354&quot; data-origin-height=&quot;344&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아날로그 회선을 사용해 컴퓨터의 디지털 신호를 전송하는 장치(변조 복조기)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;변조(modulation)? &lt;/b&gt;디지털에서 아날로그로의 변환&lt;/li&gt;
&lt;li&gt;&lt;b&gt;복조(demodulation)? &lt;/b&gt;아날로그에서 디지털로의 변환&lt;/li&gt;
&lt;li&gt;0과 1만으로 표현되는 디지털 신호를 전화 회선과 같이 음성 전송을 주로 하는 아날로그 회선에 보내려면 변조 복조가 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;일반적인 모뎀은 전화 회선을 사용해 56kbps 속도 통신 가능&lt;/li&gt;
&lt;li&gt;전화선을 사용하는 &quot;아날로그 모뎀&quot;과 &quot;ADSL 모뎀&quot;, 케이블 TV 네트워크를 사용하는 &quot;케이블 모뎀&quot; 등이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;bps&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;bits per second의 약어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1초에 전송할 수 있는&lt;/b&gt; &lt;b&gt;비트의 수&lt;/b&gt;를 나타내는 단위&lt;/li&gt;
&lt;li&gt;bps는 &lt;b&gt;전송 속도의 단위&lt;/b&gt;로, 이 수치를 사용해 데이터 전송에 필요한 시간을 계산할 수 있다.&lt;/li&gt;
&lt;li&gt;예를 들어 1,000Mbps의 전송 속도를 가진 1000BASE_T의 경우 초당 1,000M비트를 전송할 수 있다는 의미이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;8&lt;/b&gt;비트 = &lt;b&gt;1&lt;/b&gt;바이트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비트&lt;/b&gt; :&lt;b&gt; &lt;/b&gt;컴퓨터의 데이터를 나타내는 최소 단위, 1과 0 중 하나의 값을 가짐&lt;/li&gt;
&lt;li&gt;&lt;b&gt;바이트&lt;/b&gt; : 컴퓨터의 데이터양을 나타내는 단위&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;게이트 웨이&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;720&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dBSQXj/btrYKGvUqQB/mS1k2zjo9k1QHJJ5gfHSvK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dBSQXj/btrYKGvUqQB/mS1k2zjo9k1QHJJ5gfHSvK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dBSQXj/btrYKGvUqQB/mS1k2zjo9k1QHJJ5gfHSvK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdBSQXj%2FbtrYKGvUqQB%2FmS1k2zjo9k1QHJJ5gfHSvK%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;300&quot; height=&quot;262&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;720&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 네트워크를 연결하여 서로 통신하기 위해 필요한 장비 및 시스템을 말한다.&lt;/li&gt;
&lt;li&gt;상대방의 네트워크에 맞는 규격으로 변환하여 서로 전송할 수 있게 한다. &amp;rarr; 번역기처럼 동작&lt;/li&gt;
&lt;li&gt;단순히 게이트웨이라 하면 LAN과 외부 네트워크의 출입구인 &quot;&lt;b&gt;라우터&lt;/b&gt;&quot;를 가리키는 경우가 많다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zJzMG/btrYQS9WzZU/XXQQDbcWOTGt1fkyvSbRE1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zJzMG/btrYQS9WzZU/XXQQDbcWOTGt1fkyvSbRE1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zJzMG/btrYQS9WzZU/XXQQDbcWOTGt1fkyvSbRE1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzJzMG%2FbtrYQS9WzZU%2FXXQQDbcWOTGt1fkyvSbRE1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;113&quot; data-origin-width=&quot;1426&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;콜리전&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;682&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TAopq/btrYLzpTprT/5orrMSUKVTQFqbeOyFWZN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TAopq/btrYLzpTprT/5orrMSUKVTQFqbeOyFWZN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TAopq/btrYLzpTprT/5orrMSUKVTQFqbeOyFWZN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTAopq%2FbtrYLzpTprT%2F5orrMSUKVTQFqbeOyFWZN0%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;300&quot; height=&quot;251&quot; data-origin-width=&quot;816&quot; data-origin-height=&quot;682&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충돌이라는 뜻을 가지며, 네트워크상의 여러 대의 컴퓨터가 동시에 패킷을 전송하면서 발생하는 &quot;&lt;b&gt;패킷의 충돌&lt;/b&gt;&quot;을 의미한다.&lt;/li&gt;
&lt;li&gt;이더넷과 같은 CSMA/CD 방식 네트워크에는 다른 곳에서 송신하지 않는 경우에만 데이터를 송신하는 방식을 가지고 있지만, 여러 대의 컴퓨터가 동시에 작업을 확인하면 전송이 겹치 는 경우가 생겨 콜리전이 발생한다.&lt;/li&gt;
&lt;li&gt;콜리전이 발생하면 충돌한 패킷은 손상되어 정상적인 통신을 할 수 없게 된다.&lt;/li&gt;
&lt;li&gt;&lt;span&gt;콜리전이 감지되면 재밍(전파 방해) 신호를 송신해 전송을 중지하고, 전송하려던 컴퓨터들은 일정 시간 대기하다가 다음 전송을 시도한다. 따라서 콜리전 발생시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 효율 저하&lt;/b&gt;를 일으키게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;MAC 주소&lt;/span&gt;&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;714&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dN0onH/btrZjeSCG6J/E9fTkGza0EvYaI1aph0gK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dN0onH/btrZjeSCG6J/E9fTkGza0EvYaI1aph0gK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dN0onH/btrZjeSCG6J/E9fTkGza0EvYaI1aph0gK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdN0onH%2FbtrZjeSCG6J%2FE9fTkGza0EvYaI1aph0gK1%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;300&quot; height=&quot;255&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;714&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;M&lt;/b&gt;edia &lt;b&gt;A&lt;/b&gt;ccess &lt;b&gt;C&lt;/b&gt;ontrol address의 약어&lt;/li&gt;
&lt;li&gt;각 NIC(Network Interface Card)별로 할당된 48비트의 고유 번호
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;앞자리 24비트 : 제조사의 식별 번호&lt;/li&gt;
&lt;li&gt;뒷자리 24비트 : 그 제조사가 자사 제품에 할당하는 고유 번호&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이더넷에서는 네트워크에 존재하는 노드를 모두 식별할 수 있어야 하므로 기기마다 고유 번호를 할당해 이를 바탕으로 데이터를 송수신한다.&lt;/li&gt;
&lt;li&gt;OSI 참조 모델의 데이터 링크 계층에서 동작하는 네트워크 장비는(브리지, 스위칭 허브) MAC 주소를 기반으로 노드를 식별하고 패킷을 전달한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;QoS&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;612&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ENYY6/btrZexeq3rK/0q1UYoE09FxEvKPbWm0aVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ENYY6/btrZexeq3rK/0q1UYoE09FxEvKPbWm0aVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ENYY6/btrZexeq3rK/0q1UYoE09FxEvKPbWm0aVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FENYY6%2FbtrZexeq3rK%2F0q1UYoE09FxEvKPbWm0aVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;189&quot; data-origin-width=&quot;1298&quot; data-origin-height=&quot;612&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Q&lt;/b&gt;uality &lt;b&gt;o&lt;/b&gt;f &lt;b&gt;S&lt;/b&gt;ervice의 약어&lt;/li&gt;
&lt;li&gt;네트워크상의 서비스에서 &lt;b&gt;통신의 품질을 확보하기 위해 사용하는 기술&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;주로 라우터 같은 네트워크 기기가 QoS 기능을 가지고 있으며, 우선 제어와 대역 제어라는 두가지 제어 형태로 나뉜다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;우선 제어&lt;/b&gt; : 패킷을 사용하는 서비스에 따라 우선순위를 정해 처리 순서를 바꿔 &lt;b&gt;우선순위가 높은 패킷을 먼저 발송&lt;/b&gt;하도록 함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;대역 제어&lt;/b&gt; : 라우터를 통과하는 &lt;b&gt;패킷의 종류에 따라 각각의 대역을 확보하거나 제한&lt;/b&gt;해 통신 품질을 유지함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;276&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cg2RWh/btrZcia7e2R/FyBfv90SG04cCEiTkkmnv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cg2RWh/btrZcia7e2R/FyBfv90SG04cCEiTkkmnv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cg2RWh/btrZcia7e2R/FyBfv90SG04cCEiTkkmnv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcg2RWh%2FbtrZcia7e2R%2FFyBfv90SG04cCEiTkkmnv1%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;850&quot; height=&quot;151&quot; data-origin-width=&quot;1556&quot; data-origin-height=&quot;276&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;UPnP&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;1186&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKcIBu/btrZjzvxzQG/vU9TvRoaOpIaqj0RB0k6S0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKcIBu/btrZjzvxzQG/vU9TvRoaOpIaqj0RB0k6S0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKcIBu/btrZjzvxzQG/vU9TvRoaOpIaqj0RB0k6S0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKcIBu%2FbtrZjzvxzQG%2FvU9TvRoaOpIaqj0RB0k6S0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;335&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;1186&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Universal Plug and Play의 약어 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(plug and play = 연결하면 사용할 수 있다.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;주변 장치를 컴퓨터에 연결할 때 구성이나 설정을 수행하지 않고도 자동으로 사용 및 제어하는 것을 목적으로 하는 규격&lt;/li&gt;
&lt;li&gt;마이크로 소프트사에 의해 제창&lt;/li&gt;
&lt;li&gt;유니버설 플러그 앤 플레이 규격을 지원하는 기기를 네트워크에 접속시키면, 네트워크에 참가하기 위한 IP 주소를 취득하거나 자신의 기능을 네트워크상의 각 기기에 통보하는 것들이 자동으로 수행된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;NAS&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7Tx6h/btrZjp7LFQg/YbKk5JRHMm2H6wKHnueRP0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7Tx6h/btrZjp7LFQg/YbKk5JRHMm2H6wKHnueRP0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7Tx6h/btrZjp7LFQg/YbKk5JRHMm2H6wKHnueRP0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7Tx6h%2FbtrZjp7LFQg%2FYbKk5JRHMm2H6wKHnueRP0%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;300&quot; height=&quot;239&quot; data-origin-width=&quot;752&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Network Attached Storage의 약어&lt;/li&gt;
&lt;li&gt;네트워크에 직접 연결해 사용하는 &lt;b&gt;외부 기억 장치&lt;/b&gt;(스토리지)&lt;/li&gt;
&lt;li&gt;네트워크로 모두와 공유하면서 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;네트워크를 통해 파일을 저렴하고 간단한 방식으로 공유할 수 있도록 한다.&lt;/li&gt;
&lt;li&gt;내부에 여러 개의 하드 디스크를 내장하여 데이터의 손실이나 시스템 다운을 방지하기 위한 &lt;b&gt;RAID&lt;/b&gt; 기능을 갖추고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <category>네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/255</guid>
      <comments>https://jollyn.tistory.com/255#entry255comment</comments>
      <pubDate>Fri, 3 Feb 2023 18:05:15 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 광역 통신망</title>
      <link>https://jollyn.tistory.com/252</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;WAN&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1hqjr/btrXoB9RECK/w2oURc9eqaufi61p5mJdfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1hqjr/btrXoB9RECK/w2oURc9eqaufi61p5mJdfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1hqjr/btrXoB9RECK/w2oURc9eqaufi61p5mJdfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1hqjr%2FbtrXoB9RECK%2Fw2oURc9eqaufi61p5mJdfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;234&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;광역 통신망 &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(Wide Area Network)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;전용선을 사용해 &lt;b&gt;서로 떨어져 있는 컴퓨터나 LAN 사이를 연결&lt;/b&gt;한 네트워크&lt;/li&gt;
&lt;li&gt;LAN처럼 직접 케이블을 연결하는 것이 아니라 통신 사업자가 제공하는 광역망을 이용해 구축한다.&lt;/li&gt;
&lt;li&gt;연결 방법
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;전용선&lt;/b&gt; : 거점 사이를 전용선으로 연결, 비용이 많이 듬&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전화 접속&lt;/b&gt; : 필요 시에만 공중 회선을 경유해 전화 접속으로 연결, 통신 시간에 따라 비용 변동&lt;/li&gt;
&lt;li&gt;&lt;b&gt;VPN&lt;/b&gt; : 인터넷에 가상 전용선 공간을 만들고 거점 사이를 연결, 비용 저렴, 보안 주의 필요&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;연결 방법&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;전용선&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;정액 요금을 내고 두 지점 간을 연결하는 전용 회선으로, 내선 통화나 광역 네트워크 통신망을 구축할 수 있다.&lt;/li&gt;
&lt;li&gt;컴퓨터 네트워크용으로 제공하는 전용선 서비스는 주로 LAN 사이를 연결하는 WAN을 구축하는데 사용되며, 회선 방식은 디지털 회선을 사용하는 것이 일반적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;VPN&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;346&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEioWI/btrXGm5dTEJ/IRapHAOWH3fp62YNzXVUf0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEioWI/btrXGm5dTEJ/IRapHAOWH3fp62YNzXVUf0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEioWI/btrXGm5dTEJ/IRapHAOWH3fp62YNzXVUf0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEioWI%2FbtrXGm5dTEJ%2FIRapHAOWH3fp62YNzXVUf0%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;300&quot; height=&quot;229&quot; data-origin-width=&quot;454&quot; data-origin-height=&quot;346&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Virtual Private Network&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;네트워크에&lt;b&gt; 가상 전용선 공간&lt;/b&gt;을 만들어 거점 사이를 연결&lt;/li&gt;
&lt;li&gt;저렴&lt;/li&gt;
&lt;li&gt;인터넷 회선을 이용하는 &lt;b&gt;인터넷 VPN&lt;/b&gt;, 통신 사업자의 폐쇄된 통신망을 사용하는 &lt;b&gt;IP-VPN&lt;/b&gt;, &lt;b&gt;광역 이더넷&lt;/b&gt;으로 나뉜다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  인터넷 VPN&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cgxbPh/btrXFtQXIO3/obQvYuT3fudlcsJALxUxNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgxbPh/btrXFtQXIO3/obQvYuT3fudlcsJALxUxNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgxbPh/btrXFtQXIO3/obQvYuT3fudlcsJALxUxNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgxbPh%2FbtrXFtQXIO3%2FobQvYuT3fudlcsJALxUxNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;103&quot; data-origin-width=&quot;774&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;228&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFvjeJ/btrXBADSWmN/4A2MY8uHx6xdxzokDlHuKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFvjeJ/btrXBADSWmN/4A2MY8uHx6xdxzokDlHuKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFvjeJ/btrXBADSWmN/4A2MY8uHx6xdxzokDlHuKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFvjeJ%2FbtrXBADSWmN%2F4A2MY8uHx6xdxzokDlHuKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;228&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;228&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인터넷 VPN을 사용하려면 &lt;b&gt;서로 연결되는 부분에 VPN 기능을 가진 기기를 설치&lt;/b&gt;해야 한다.&lt;/li&gt;
&lt;li&gt;VPN 장치가&amp;nbsp;&lt;b&gt;통신 데이터를 암호화&lt;/b&gt;한 후 인터넷에 전송하며, 수신하는 쪽에서 암호를 해독해 내부 네트워크에 전송한다.&lt;/li&gt;
&lt;li&gt;전송 경로인 인터넷 상에서는 데이터를 해독할 수 없기 때문에 정보 누설이나 변조의 위험없이 데이터를 안전하게 지킬 수 있다.&lt;/li&gt;
&lt;li&gt;VPN 장치가 서로 호환되는 암호화 방법을 사용하지 않으면 데이터 해독이 불가능하다.&lt;br /&gt;&amp;rarr; 현재는 IPSec라는 VPN 표준 프로토콜을 정의해, 이 프로토콜을 지원하는 기기라면 제조사가 달라도 통신이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  IP-VPN, 광역 이더넷&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;통신 사업자가 제공하는 서비스&lt;/li&gt;
&lt;li&gt;폐쇄된 통신망을 VPN 기술을 통해 여러 사용자가 공유하는 형태&lt;/li&gt;
&lt;li&gt;인터넷 VPN보다 비싸지만 인터넷과 격리되어 있어 보안 면에서 유리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;디지털 통신 기술&lt;/b&gt;&lt;/h2&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ISDN&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;242&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1EefR/btrXCHCqmAa/CpGP9tuctbqpl5FkqUqyw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1EefR/btrXCHCqmAa/CpGP9tuctbqpl5FkqUqyw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1EefR/btrXCHCqmAa/CpGP9tuctbqpl5FkqUqyw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1EefR%2FbtrXCHCqmAa%2FCpGP9tuctbqpl5FkqUqyw0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;124&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;242&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Integrated Services Digital Network&lt;/span&gt; (통합 디지털 통신망)&lt;/li&gt;
&lt;li&gt;전화나 팩스, 데이터 통신을 통합해 취급할 수 있는 &lt;b&gt;디지털 통신망&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;아날로그 회선에 비해 고속으로 안정적인 통신이 가능하다.&lt;/li&gt;
&lt;li&gt;디지털 회선 안쪽은 채널이라는 개념으로 세 개의 가상 회선으로 나뉘어져 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;xDSL&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;698&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFhLS7/btrXN2FIuOz/HDmE7DiPvafZXmq1MCF5SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFhLS7/btrXN2FIuOz/HDmE7DiPvafZXmq1MCF5SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFhLS7/btrXN2FIuOz/HDmE7DiPvafZXmq1MCF5SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFhLS7%2FbtrXN2FIuOz%2FHDmE7DiPvafZXmq1MCF5SK%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;250&quot; height=&quot;219&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;698&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전화국과 가입자 사이에 아날로그 전화용으로 설치되어 있는 기존 구리선으로 수 Mbps의 &lt;b&gt;고속 디지털 통신&lt;/b&gt;을 구현하는 기술이다.&lt;/li&gt;
&lt;li&gt;용도와 속도에 따라 다양한 종류가 있는데, 이를 총칭하여 &lt;b&gt;xDSL&lt;/b&gt;(x Digital Subscriber Line)이라 한다.&lt;/li&gt;
&lt;li&gt;아날로그 전화는 구리선이 전송할 수 있는 주파수 대역의 겨우 몇 %밖에 사용하지 않으며,&amp;nbsp; xDSL은 이 외의 주파수를 사용해 고속 통신을 수행한다. &amp;rarr; 높은 주파수 대역 사용&lt;/li&gt;
&lt;li&gt;그러나 전화용 케이블을 사용하기 때문에 거리가 멀어질수록 고주파 신호가 감쇠한다. 따라서 전화국에서 단거리가 아니면 사용할 수 없다.&lt;/li&gt;
&lt;li&gt;xDSL로 통신하는 케이블의 양쪽 끝에 &lt;b&gt;스플리터&lt;/b&gt;라는 기기를 설치하며, 이 기기가 주파수 대역에 따라 아날로그 통화와 데이터 통신 신호를 분리하기 때문에 &lt;b&gt;음성 통화와 데이터 통신&lt;/b&gt;을&lt;b&gt; 서로 간섭없이 동시에&lt;/b&gt; 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;418&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eFeonJ/btrXHYrApTt/w5zzCu0yerMdbOR4DG7it1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eFeonJ/btrXHYrApTt/w5zzCu0yerMdbOR4DG7it1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eFeonJ/btrXHYrApTt/w5zzCu0yerMdbOR4DG7it1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeFeonJ%2FbtrXHYrApTt%2Fw5zzCu0yerMdbOR4DG7it1%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;450&quot; height=&quot;131&quot; data-origin-width=&quot;1434&quot; data-origin-height=&quot;418&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;ADSL&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cKL3S9/btrXOksGkW1/3JmFsYv8pSu256Ldb3Z2Xk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cKL3S9/btrXOksGkW1/3JmFsYv8pSu256Ldb3Z2Xk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cKL3S9/btrXOksGkW1/3JmFsYv8pSu256Ldb3Z2Xk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcKL3S9%2FbtrXOksGkW1%2F3JmFsYv8pSu256Ldb3Z2Xk%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;300&quot; height=&quot;268&quot; data-origin-width=&quot;826&quot; data-origin-height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Asymmetric Digital Subscriber Line&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;xDSL의 한 종류&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;비대칭(asymmetric)이라는 말 그대로 전화국 &amp;rarr; 가입자(다운링크)와 가입자 &amp;rarr; 전화국(업링크)의 통신 속도가 각각 다르다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;다운링크&lt;/b&gt;(다운로드) : 1.5 ~ 50Mbps, &lt;b&gt;빠름&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;업링크&lt;/b&gt;(업로드) : 512kbps ~ 5Mbps, &lt;b&gt;느림&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;데이터 통신을&lt;b&gt; 스플리터&lt;/b&gt;로 구분되어 통신 사업자의 전화 교환기를 통하지 않고 인터넷에 연결되기 때문에 이용 시간에 관계없이 정액요금으로 서비스를 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;현재 광케이블과 함께 일반적으로 보급되고 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;광케이블&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMINJp/btrXOs0o95z/zzDz76ZcuTszTB5pso3V01/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMINJp/btrXOs0o95z/zzDz76ZcuTszTB5pso3V01/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMINJp/btrXOs0o95z/zzDz76ZcuTszTB5pso3V01/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMINJp%2FbtrXOs0o95z%2FzzDz76ZcuTszTB5pso3V01%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;178&quot; data-origin-width=&quot;1422&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;현재 전화국과 가입자 사이를 연결하는 아날로그 전화용 구리선을 광섬유로 대체해 더 빠르고 품질 높은 디지털 통신 가능&lt;/li&gt;
&lt;li&gt;통신 속도 : 10Mbps ~ 2Gbps, &lt;b&gt;매우 빠름&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;속도가 빠르기 때문에 음악이나 동영상 같은 멀티미디어 콘텐츠도 전송이 가능하다.&lt;/li&gt;
&lt;li&gt;광케이블 연결은 서비스 요금이 비싸기 때문에, 저렴한 ADSL 서비스와 비교해서 사용자에게 더 적합한 서비스를 형태로 정착 중이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  정리&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;764&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ciNA4G/btrXVfY9AfM/shdbtn4BkbO7Pk1SQm0UA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ciNA4G/btrXVfY9AfM/shdbtn4BkbO7Pk1SQm0UA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ciNA4G/btrXVfY9AfM/shdbtn4BkbO7Pk1SQm0UA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FciNA4G%2FbtrXVfY9AfM%2Fshdbtn4BkbO7Pk1SQm0UA1%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;450&quot; height=&quot;239&quot; data-origin-width=&quot;1436&quot; data-origin-height=&quot;764&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;WiMAX&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;568&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMVOE4/btrXOSra96a/jICKNHtU8z6EUg9a7I9950/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMVOE4/btrXOSra96a/jICKNHtU8z6EUg9a7I9950/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMVOE4/btrXOSra96a/jICKNHtU8z6EUg9a7I9950/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMVOE4%2FbtrXOSra96a%2FjICKNHtU8z6EUg9a7I9950%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;255&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;568&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Worldwide Interoperability for Microwave Access&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;수십 km라는 &lt;b&gt;중장거리 범위&lt;/b&gt;에 대해 &lt;b&gt;무선&lt;/b&gt;으로 통신하는 것을 목적으로 하는 &lt;b&gt;통신 규약&lt;/b&gt;이다.&lt;br /&gt;&amp;rarr; 최대 50km의 전송거리, 25Mbps의 전송 속도&lt;/li&gt;
&lt;li&gt;WirelessMAN이라 불리는 IEEE 802.16 무선 통신 표준을 기반으로 한다.&lt;/li&gt;
&lt;li&gt;고정형 WiMAX, 이동형 WiMAX 존재&lt;/li&gt;
&lt;li&gt;통상적으로는 브로드밴드 서비스는 광케이블이나 ADSL로 제공하는 것이 일반적이지만, 시골 같은 과소 지역은 회선을 구축하려 해도 기지국과 너무 멀어 많은 비용을 감당할 수 없다. 이런 경우 중장거리 범위를 아우르는 WiMAX를 사용하면 무선으로 통신할 수 있으므로 각 집에 회선을 설치하는 비용을 고려하지 않고 서비스를 제공할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;IP 전화&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;전화망의 일부를 인터넷을 경유하도록 대체한 전화 서비스, 즉 인터넷을 통한 음성 전화를 말한다.&lt;/li&gt;
&lt;li&gt;ex) 카카오톡 음성통화&lt;/li&gt;
&lt;li&gt;VoIP(Voice over IP)라는 IP 네트워크상에서 음성통화를 구현하는 기술에 대해 표준 규격이 정해져 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;음성은 VoIP 기능을 가진 라우터에 의해 패킷으로 변환되어 상대방에게 전달된다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;338&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n2tNh/btrX02tTfHe/lct9P8oMULLPNJATAnO2vK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n2tNh/btrX02tTfHe/lct9P8oMULLPNJATAnO2vK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n2tNh/btrX02tTfHe/lct9P8oMULLPNJATAnO2vK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn2tNh%2FbtrX02tTfHe%2Flct9P8oMULLPNJATAnO2vK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;141&quot; data-origin-width=&quot;1440&quot; data-origin-height=&quot;338&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;356&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mktAy/btrX2oI6qqL/OLMHoPwzHcjan8RkaGhS80/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mktAy/btrX2oI6qqL/OLMHoPwzHcjan8RkaGhS80/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mktAy/btrX2oI6qqL/OLMHoPwzHcjan8RkaGhS80/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmktAy%2FbtrX2oI6qqL%2FOLMHoPwzHcjan8RkaGhS80%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;150&quot; data-origin-width=&quot;948&quot; data-origin-height=&quot;356&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <category>WAN</category>
      <category>광역 통신망</category>
      <category>네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/252</guid>
      <comments>https://jollyn.tistory.com/252#entry252comment</comments>
      <pubDate>Sat, 28 Jan 2023 11:16:10 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] Servlet Container와 Servlet, Tomcat</title>
      <link>https://jollyn.tistory.com/248</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서블릿&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자바에서 동적인 웹 페이지를 개발하기 위한 기술&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;톰캣 서버&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서블릿을 실행시켜주는 역할&lt;/li&gt;
&lt;li&gt;사용자 요청을 받아 경로(Path)를 추출하고, 경로에 해당하는 서블릿을 찾아서 서블릿에게 사용자 요청을 위임하고, 서블릿에서 작업을 마치면 응답을 받아 클라이언트에게 전달하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;톰캣 서버를 총칭하여 &lt;b&gt;WAS&lt;/b&gt;(Web Application Server) 또는 &lt;b&gt;서블릿 컨테이너&lt;/b&gt;(Servlet Container)라고 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=aP4Lw3SfffQ&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[YouTube] Servlet Container와 Servlet의 관계 - 박재성&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@jihoson94/Servlet-Container-%EC%A0%95%EB%A6%AC&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Servet Container 정리&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Spring/Core</category>
      <category>서블릿</category>
      <category>서블릿 컨테이너</category>
      <category>톰캣</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/248</guid>
      <comments>https://jollyn.tistory.com/248#entry248comment</comments>
      <pubDate>Wed, 25 Jan 2023 23:43:26 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 근거리 통신망</title>
      <link>https://jollyn.tistory.com/247</link>
      <description>&lt;h2 id=&quot;1. LAN&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;LAN&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Local Area Networt&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(근거리 통신망)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;좁은&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;범위(회사나 건물) 내의 컴퓨터를 전용 케이블로 연결해 구성한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가정에서 이러한 네트워크를 구성한다면 &quot;가정용 LAN&quot; 혹은 &quot;홈 네트워크&quot;라 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;LAN이 구축되지 않은 환경에서는 컴퓨터 간 직접 데이터를 주고 받을 수 없다.&lt;/li&gt;
&lt;li&gt;LAN을 통해 컴퓨터의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;전자 데이터를 서로 주고받을 수 있으며&lt;/b&gt;, 프린터 같은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주변 기기&lt;/b&gt;도 네트워크를 통해 다른 컴퓨터가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;사용&lt;/b&gt;할 수 있게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;634&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MKGNy/btrWDcjHmaC/AEVyhDkn42wbYmRoMT9ask/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MKGNy/btrWDcjHmaC/AEVyhDkn42wbYmRoMT9ask/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MKGNy/btrWDcjHmaC/AEVyhDkn42wbYmRoMT9ask/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMKGNy%2FbtrWDcjHmaC%2FAEVyhDkn42wbYmRoMT9ask%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;362&quot; height=&quot;634&quot; data-origin-width=&quot;670&quot; data-origin-height=&quot;634&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  LAN의 연결 형태 (토폴로지)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스타형&lt;/li&gt;
&lt;li&gt;버스형&lt;/li&gt;
&lt;li&gt;링형 : 모든 컴퓨터가 링 모양으로 연결된 형태, 토큰 링에서 사용&lt;/li&gt;
&lt;li&gt;계층형&lt;/li&gt;
&lt;li&gt;메쉬형&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;b&gt;네트워크 토폴로지&lt;br /&gt;&lt;/b&gt;&amp;bull; 네트워크를 구성하는 컴퓨터간 연결된 형태&lt;br /&gt;&amp;bull; 통신망 구조라고 생각하면 된다!&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;1.1. 스타형 LAN&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;스타형 LAN&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;322&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xFBsN/btrWFJANwxT/aFIdvKXaUepwYKykLeYDwk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xFBsN/btrWFJANwxT/aFIdvKXaUepwYKykLeYDwk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xFBsN/btrWFJANwxT/aFIdvKXaUepwYKykLeYDwk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxFBsN%2FbtrWFJANwxT%2FaFIdvKXaUepwYKykLeYDwk%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;250&quot; height=&quot;322&quot; data-filename=&quot;edited_blob&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;322&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;허브&lt;/b&gt;라는 집선 장치를 중심으로 각 컴퓨터가 연결된 형태&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이더넷 10BASE-T나 100BASE-TX, 1000BASE-T에 자주 사용되며, 현재 스타 LAN 방식이 주류를 이루고 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;허브가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;통신 중개&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;역할을 하기 때문에 네트워크에 접속된 컴퓨터가 고장나도 다른 컴퓨터에 영향을 미치지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;하지만&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;허브가 고장&lt;/b&gt;나면 통신 경로가 차단되어 네트워크 전체가&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;통신 불능&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;상태가 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;배선의 자유도가 높고, 허브끼리 서로 연결해 네트워크 전체를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;계층 구조&lt;/b&gt;로 관리 할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HJx9z/btrWDQHjs0O/KnewpQc92GPxQzQedgLzm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HJx9z/btrWDQHjs0O/KnewpQc92GPxQzQedgLzm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HJx9z/btrWDQHjs0O/KnewpQc92GPxQzQedgLzm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHJx9z%2FbtrWDQHjs0O%2FKnewpQc92GPxQzQedgLzm1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;289&quot; data-origin-width=&quot;788&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;1.2. 버스형 LAN&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;버스형 LAN&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;302&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvnJ9o/btrWCFGFHJo/D6EAPah6aodDN5qFOXBq6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvnJ9o/btrWCFGFHJo/D6EAPah6aodDN5qFOXBq6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvnJ9o/btrWCFGFHJo/D6EAPah6aodDN5qFOXBq6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvnJ9o%2FbtrWCFGFHJo%2FD6EAPah6aodDN5qFOXBq6k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;159&quot; data-origin-width=&quot;664&quot; data-origin-height=&quot;302&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;한 개의 케이블&lt;/b&gt;에 각 컴퓨터가 연결된 형태&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이더넷 10BASE-2나 10BASE-5에서 사용된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;케이블 양쪽 끝에는 신호의 반사를 방지하기 위한&amp;nbsp;&lt;b&gt;터미네이터&lt;/b&gt;라는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;종단 장치&lt;/b&gt;가 연결되어 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;케이블에 흐르는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패킷이 모든 컴퓨터에 전달&lt;/b&gt;되며,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;수신지 이외&lt;/b&gt;의 컴퓨터에서는 전달된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패킷을 파기&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;케이블에 연결된 컴퓨터가 고장나도 다른 컴퓨터에 영향을 미치지 않는다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;접속된 컴퓨터의 수가 많으면 통신량이 증가해 패킷 충돌이 발생한다.&lt;br /&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;이더넷에서는 적절한 시간을 두고 패킷을 전송하지만, 패킷 충돌(콜리전)이 많이 발생할 경우 네트워크 효율이 너무 떨어져 사용하기 어렵다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;1.3. 링형 LAN&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;링형 LAN&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;360&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZ9tIq/btrWCz7D1wk/FSnD5rEcYuLbCs0MRYv8nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZ9tIq/btrWCz7D1wk/FSnD5rEcYuLbCs0MRYv8nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZ9tIq/btrWCz7D1wk/FSnD5rEcYuLbCs0MRYv8nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZ9tIq%2FbtrWCz7D1wk%2FFSnD5rEcYuLbCs0MRYv8nK%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;300&quot; height=&quot;208&quot; data-origin-width=&quot;520&quot; data-origin-height=&quot;360&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;링 형태의 케이블&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;하나에 컴퓨터가 접속하는 형태&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;한 개의 케이블에 연결되어 있다는 점이 버스형 LAN과 같지만, 케이블이 링 모양이므로 링형 LAN이라 표현하며&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;버스형 LAN과 달리 양 끝에 터미네이터가 필요 없는 형태&lt;/b&gt;이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;토큰링, FDDI에서 사용된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;다른 방식에 비해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;케이블의 총 거리를 길게&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;잡을 수 있다. 따라서 WAN 같이 넓은 지역의 네트워크에서 링형을 채택하기도 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;패킷은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한 방향&lt;/b&gt;으로만 흐르고 컴퓨터는 패킷을 수시로 확인하여 자신이 수신인인지 판단한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자신이 수신인이면 패킷을 수신&lt;/b&gt;하고&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;아니면 다음 컴퓨터로 보낸다&lt;/b&gt;. &amp;rarr; 마치 물통 릴레이같이 패킷 전송&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서 링형에 접속 된 컴퓨터 중&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;한 대라도 고장하면 전송이 멈춰 통신 장애&lt;/b&gt;가 발생한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;796&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ur59g/btrWDEmG1PM/6toPGnI4K8HbIkybkpFAjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ur59g/btrWDEmG1PM/6toPGnI4K8HbIkybkpFAjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ur59g/btrWDEmG1PM/6toPGnI4K8HbIkybkpFAjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fur59g%2FbtrWDEmG1PM%2F6toPGnI4K8HbIkybkpFAjk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;334&quot; data-origin-width=&quot;796&quot; data-origin-height=&quot;334&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;네트워크 규격&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 id=&quot;2. 이더넷&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;이더넷&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;CSMA/CD&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;방식을 사용해 통신을 수행하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 규격&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;현재 대부분의 LAN 환경에서는 이더넷을 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이더넷의 연결 형태는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;버스형&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;스타형이&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;있으며, 스타형의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;1000BASE-T&lt;/b&gt;가 널리 이용되고 있다.&amp;nbsp;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;버스형 : 10BASE-2, 10BASSE-5&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;스타형 : 10BASE-T, 100BASE-TX, 1000BASE-T&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;  CSMA/CD 방식&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bsQyqV/btrWDENL1wg/vdX1pppD22kYWpkxVTtRzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bsQyqV/btrWDENL1wg/vdX1pppD22kYWpkxVTtRzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bsQyqV/btrWDENL1wg/vdX1pppD22kYWpkxVTtRzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbsQyqV%2FbtrWDENL1wg%2FvdX1pppD22kYWpkxVTtRzK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;296&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;316&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bckBaC/btrWH1A5gE6/hFmb7kwlFkpDvWLSuvQt50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bckBaC/btrWH1A5gE6/hFmb7kwlFkpDvWLSuvQt50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bckBaC/btrWH1A5gE6/hFmb7kwlFkpDvWLSuvQt50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbckBaC%2FbtrWH1A5gE6%2FhFmb7kwlFkpDvWLSuvQt50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;316&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;316&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더넷에서는 네트워크 통신 상태를 감시하여,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;다른 사람이 송신하지 않을 경우&lt;/b&gt;에만 데이터를 전송하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;캐리어센스&lt;/b&gt;(Carier Sense, 매체 사용 감지)라는 구조와, 동시에 전송하여&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패킷 충돌(신호 충돌)이 발생&lt;/b&gt;하면 임의의 시간을 대기한 뒤&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;재전송&lt;/b&gt;하는&amp;nbsp;구조에 의해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;통신제어를 실시&lt;/b&gt;한다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;이러한 제어 방법을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;CSMA/CD&lt;/b&gt;(Carrier Sense Multiple Access/Collision Detection) 방식이라 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 방법으로 통신을 수행하기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;케이블 하나를 여러 대의 컴퓨터가 공유&lt;/b&gt;할 수 있는 것이다. &amp;rarr; Multiple Access&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;토큰 링&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9wBSW/btrWQc95Irm/yhj4w65RdkK5UptQ95kzFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9wBSW/btrWQc95Irm/yhj4w65RdkK5UptQ95kzFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9wBSW/btrWQc95Irm/yhj4w65RdkK5UptQ95kzFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9wBSW%2FbtrWQc95Irm%2Fyhj4w65RdkK5UptQ95kzFK%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;300&quot; height=&quot;239&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;토큰&lt;/b&gt;이라는 송신 권리를 나타내는 데이터를 물통 릴레이처럼 전달하는 &lt;b&gt;토큰 패싱 방식&lt;/b&gt;을 사용해 통신하는 네트워크 규격&lt;/li&gt;
&lt;li&gt;4Mbps, 16Mbps 두가지 통신 속도가 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;링형 LAN&lt;/b&gt;에 속한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  토큰 패싱 형식&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;토큰&lt;/b&gt;(Token) : 네트워크 상에서 &lt;b&gt;송신할 권리&lt;/b&gt;를 나타내는 데이터&lt;br /&gt;&amp;rarr; &lt;span&gt;&lt;b&gt;토큰을 가진 컴퓨터&lt;/b&gt;만 &lt;b&gt;데이터를 전송&lt;/b&gt;할 수 있기 때문에 &lt;/span&gt;&lt;b&gt;신호 충돌(콜리전)이 발생하지 않음&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;토큰 패싱 형식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;네트워크에 전송 할 &lt;b&gt;데이터가 없을 때&lt;/b&gt;는 &lt;b&gt;토큰만 전송&lt;/b&gt;한다.&lt;br /&gt;&lt;img style=&quot;caret-color: transparent; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/EszGY/btrWQdVt5IK/chTWhkRESGsvBW7WY2pCVk/img.png&quot; width=&quot;350&quot; height=&quot;72&quot; data-origin-width=&quot;654&quot; data-origin-height=&quot;134&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;li&gt;데이터를 전송하고 싶은 컴퓨터는 토큰이 자신에게 수신될 때까지 기다렸다가, 토큰을 받아 데이터를 추가한 뒤 전송한다.&lt;br /&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RnEzt/btrWN0DZdQl/Pk6WbirCJLFKGv4wEDtZH0/img.png&quot; width=&quot;350&quot; height=&quot;80&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;148&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;li&gt;이후 토큰을 받은 컴퓨터는 데이터가 자신에게 온 것인지 확인하고, &lt;b&gt;자신에게 온 것이라면 데이터를 추출&lt;/b&gt;하고 토큰만 다음 컴퓨터에게 전송한다.&lt;br /&gt;&lt;img style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dn/bmUJhR/btrWPnZfiOx/0d8KKkjskCgomr104GWJh1/img.png&quot; width=&quot;350&quot; data-origin-width=&quot;666&quot; data-origin-height=&quot;144&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;통신 기술&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;무선 LAN&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;364&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NkiMv/btrWPdP6eye/TBPj1a6nzVpxm03biG6hy1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NkiMv/btrWPdP6eye/TBPj1a6nzVpxm03biG6hy1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NkiMv/btrWPdP6eye/TBPj1a6nzVpxm03biG6hy1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNkiMv%2FbtrWPdP6eye%2FTBPj1a6nzVpxm03biG6hy1%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;300&quot; height=&quot;260&quot; data-origin-width=&quot;420&quot; data-origin-height=&quot;364&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;케이블을 사용하지 않고 &lt;b&gt;전파&lt;/b&gt; 등을 사용해 통신하는 LAN&lt;/li&gt;
&lt;li&gt;무선 LAN을 이용하려면 대상 컴퓨터에 무선 LAN 어댑터 기능이 내장되어 있거나 USB 어댑터 등이 장착되어 있어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  무선 LAN 접속 방법&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kwYLX/btrWN0cUYVf/hqtwq649FYNJzpxsYYy1LK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kwYLX/btrWN0cUYVf/hqtwq649FYNJzpxsYYy1LK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kwYLX/btrWN0cUYVf/hqtwq649FYNJzpxsYYy1LK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkwYLX%2FbtrWN0cUYVf%2Fhqtwq649FYNJzpxsYYy1LK%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;450&quot; height=&quot;162&quot; data-origin-width=&quot;780&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;애드훅 모드 &lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무선 LAN 어댑터끼리 직접 통신하는 방법, 많이 쓰이진 X&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인프라 모드 &lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;액세스 포인트&lt;/b&gt;(AP)라는 기지국을 사용하는 방법으로, 개별 컴퓨터는 무선 LAN 어댑터 기능을 통해 기지국에 무선으로 접속한다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(엑세스 포인트 = 유선 LAN의 허브와 같은 역할을 담당)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;PLC&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cyHYfT/btrXamdwD0x/NPWwhlJZjMueDukITkDr10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cyHYfT/btrXamdwD0x/NPWwhlJZjMueDukITkDr10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cyHYfT/btrXamdwD0x/NPWwhlJZjMueDukITkDr10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcyHYfT%2FbtrXamdwD0x%2FNPWwhlJZjMueDukITkDr10%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;300&quot; height=&quot;223&quot; data-origin-width=&quot;482&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Power Line Communication, 전력선 통신&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전기 배선을&lt;/b&gt; 사용해 데이터를 고주파 신호에 실어 통신하는 기술&lt;/li&gt;
&lt;li&gt;콘센트에 두개 이상의 PLC 어댑터를 연결하고 어댑터 사이의 전기 배선을 통해 데이터를 송수신하는 구조이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;블루투스&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8QZ1M/btrW6qui4K0/VNL1wi2eT00MDhrWaJAbaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8QZ1M/btrW6qui4K0/VNL1wi2eT00MDhrWaJAbaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8QZ1M/btrW6qui4K0/VNL1wi2eT00MDhrWaJAbaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8QZ1M%2FbtrW6qui4K0%2FVNL1wi2eT00MDhrWaJAbaK%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;300&quot; height=&quot;244&quot; data-origin-width=&quot;440&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;휴대용 정보 기기를 대상으로 하는 &lt;b&gt;무선 통신 기술&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2.4GHz&lt;/b&gt; 대역을 사용해 &lt;b&gt;케이블을 사용하지 않고 다양한 기기와 접속&lt;/b&gt; 할 수 있으며, 한 대의 마스터 기기에 대해 슬레이브로 일곱 대까지 기기를 연결할 수 있다. &lt;span style=&quot;color: #9d9d9d;&quot;&gt;(마스터: 메인 기기, 슬레이브: 연결 대상 기기)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;적외선 통신과 달리 기기 사이에 장애물이 있어도 영향을 받지 않는다.&lt;/li&gt;
&lt;li&gt;블루투스는 네트워크를 구축하기 위한 규격이 아니라 기기 상호 간을 무선으로 연결하기 위한 규격으로 무선 LAN과는 용도가 다르다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;&lt;b&gt;IP 주소&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;공인 IP 주소&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;814&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IX8kZ/btrXhncyVJt/tDu5DxUCq7oFLXykA8SD9k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IX8kZ/btrXhncyVJt/tDu5DxUCq7oFLXykA8SD9k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IX8kZ/btrXhncyVJt/tDu5DxUCq7oFLXykA8SD9k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIX8kZ%2FbtrXhncyVJt%2FtDu5DxUCq7oFLXykA8SD9k%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;450&quot; height=&quot;471&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;814&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;public IP address&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;전 세계에서 유일한 번호라는 것을 보장하는 IP 주소&lt;/li&gt;
&lt;li&gt;공인 IP 주소는 개인이 마음대로 할당할 수 없으며, 나라마다 전문기관이 존재하고 기관의 관리하에 할당받도록 되어있다.&lt;br /&gt;&amp;rarr; 한국의 공인 IP 주소는 한국인터넷정보센터에서 할당&lt;/li&gt;
&lt;li&gt;IANA&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(Internat Assigned Numbers Authority)&lt;/span&gt;를 정점으로 하는 계층 구조로, 지역 별로 할당되어 관리된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;사설 IP 주소&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHX8kV/btrXgZC0xyT/YIcrG0O6a3rCTOSwhKtXG0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHX8kV/btrXgZC0xyT/YIcrG0O6a3rCTOSwhKtXG0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHX8kV/btrXgZC0xyT/YIcrG0O6a3rCTOSwhKtXG0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHX8kV%2FbtrXgZC0xyT%2FYIcrG0O6a3rCTOSwhKtXG0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;588&quot; data-origin-width=&quot;1054&quot; data-origin-height=&quot;588&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;private IP Address&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;제한된 범위 안에서만 유효&lt;/b&gt;한 개인적인 IP 주소&lt;/li&gt;
&lt;li&gt;사설 IP 주소는 관리자가 자유롭게 할당할 수 있다.&lt;/li&gt;
&lt;li&gt;32비트 정수로 표현하는 IP 주소는 그 수가 한정되어 있기 때문에 네트워크에서 모든 컴퓨터에게 개별 IP 주소를 할당하는 것은 불가능하다. 따라서 LAN처럼 제한된 작은 범위의 네트워크에서는 사설 IP 주소를 할당한다.&lt;/li&gt;
&lt;li&gt;사설 IP 주소는 개인적인 공간 안에서만 통용되는 목적지이므로 &lt;b&gt;외부와는 통신할 수 없다&lt;/b&gt;.&lt;br /&gt;&amp;rarr; 사설 IP 주소로 외부와 통신하려면 NAT나 IP 마스커레이드 같은 수단을 사용해 주소 변환 필요&lt;/li&gt;
&lt;li&gt;네트워크 규격에 의해 세 클래스로 나뉜다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;268&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dpP8yf/btrXbsGK6x9/xA0Tp87cr1dCkFROPhlnW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dpP8yf/btrXbsGK6x9/xA0Tp87cr1dCkFROPhlnW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dpP8yf/btrXbsGK6x9/xA0Tp87cr1dCkFROPhlnW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdpP8yf%2FbtrXbsGK6x9%2FxA0Tp87cr1dCkFROPhlnW1%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;450&quot; height=&quot;117&quot; data-origin-width=&quot;1030&quot; data-origin-height=&quot;268&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&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;&lt;b&gt;네트워크 관리 방법&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;워크 그룹 네트워크&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;540&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/boS2Il/btrXl09JYZH/HhIOl3si6pN7oE7BLupcbk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/boS2Il/btrXl09JYZH/HhIOl3si6pN7oE7BLupcbk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/boS2Il/btrXl09JYZH/HhIOl3si6pN7oE7BLupcbk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FboS2Il%2FbtrXl09JYZH%2FHhIOl3si6pN7oE7BLupcbk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;295&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;540&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클라이언트 컴퓨터끼리 자원을 공유하는 분산 관리형(Peer-to-Peear) 네트워크 관리 방법&lt;/li&gt;
&lt;li&gt;네트워크 상의 컴퓨터는 워크 그룹이라는 단위로 그룹화된다.&lt;/li&gt;
&lt;li&gt;각 컴퓨터가 속하는 워크 그룹은 스스로 이름을 입력하여 설정한다.&lt;/li&gt;
&lt;li&gt;각 클라이언트 컴퓨터가 자유롭게 파일이나 프린터 공유를 설정할 수 있으므로 간편하다는 장점이 있지만, 보안적인 면에서 매우 취약해 사용자나 네트워크 자원의 집중 관리를 할 수 없다는 단점이 있다.&lt;/li&gt;
&lt;li&gt;마이크로소프트사의 윈도 OS는  기본적인 네트워크 관리 수단으로 워크 그룹 네트워크를 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;도메인 네트워크&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bplRZh/btrXliJyUwZ/2uC0WvjScbc410armAtWq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bplRZh/btrXliJyUwZ/2uC0WvjScbc410armAtWq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bplRZh/btrXliJyUwZ/2uC0WvjScbc410armAtWq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbplRZh%2FbtrXliJyUwZ%2F2uC0WvjScbc410armAtWq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;227&quot; data-origin-width=&quot;898&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;원도 서버에 의해 네트워크상의 컴퓨터를 &lt;b&gt;도메인&lt;/b&gt;이라는 단위로 집중 관리하는 네트워크 관리 방법&lt;/li&gt;
&lt;li&gt;도메인에 참가하는 사용자는 서버에 의해 중앙 관리된다. 이 서버를 &lt;b&gt;도메인 컨트롤러&lt;/b&gt;라고 한다.&lt;/li&gt;
&lt;li&gt;도메인에는 반드시 &lt;b&gt;한개 이상&lt;/b&gt;의 도메인 컨트롤러가 설치되어 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인 컨트롤러가 단 한개라면, 서버에 장애 발생 시 네트워크 전체 장애로 직결되기 때문에 이를 방지하기 위해 여러 개의 도메인 컨트롤러를 설치해 문제 발생 시 나머지 컨트롤러로 대체될 수 있도록 운영한다.&lt;/li&gt;
&lt;li&gt;설치된 도메인 컨트롤러는 서로의 관리 정보를 공유한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hihack.tistory.com/entry/%EC%9D%B4%EB%8D%94%EB%84%B7Ethernet%EA%B3%BC-%ED%86%A0%ED%81%B0%EB%A7%81Token-ring&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span&gt;이더넷(Ethernet)과 토큰링(Token ring)&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <category>LAN</category>
      <category>근거리 통신망</category>
      <category>네트워크</category>
      <category>토폴로지</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/247</guid>
      <comments>https://jollyn.tistory.com/247#entry247comment</comments>
      <pubDate>Tue, 17 Jan 2023 11:16:24 +0900</pubDate>
    </item>
    <item>
      <title>[Network] OSI 참조 모델, TCP/IP</title>
      <link>https://jollyn.tistory.com/245</link>
      <description>&lt;h2 id=&quot;1. 네트워크 프로토콜&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;네트워크 프로토콜&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;326&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cxYX9n/btrYquI49hk/WqjXEOyCjW0LP9StGOckyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cxYX9n/btrYquI49hk/WqjXEOyCjW0LP9StGOckyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cxYX9n/btrYquI49hk/WqjXEOyCjW0LP9StGOckyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcxYX9n%2FbtrYquI49hk%2FWqjXEOyCjW0LP9StGOckyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;186&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;네트워크를 통해 컴퓨터끼리 정보를 주고받기 위한 통신 규약&lt;/b&gt;을 의미한다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;rarr; 어떤 방법으로, 어떤 절차를 거쳐서, 어떤 언어로 정보를 보낼지 등&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;방법, 절차, 언어라는 역할마다&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;계층 구조로 구분&lt;/b&gt;된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;2. OSI 참조 모델&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;OSI 참조 모델&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크의 기본 구조는 상호 호환성과 확장성을 제공하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;7개의 층&lt;/b&gt;으로 나누어 관리되는데,&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이러한 계층 구조를&amp;nbsp;&lt;b&gt;OSI 참조 모델&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;OSI 계층 모델&lt;/b&gt;이라고 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;송신하는 곳은 물리 계층에서 응용계층까지 순서대로 데이터를 가공해 보내고, 수신하는 곳은 받은 데이터를 역순으로 가공해 복원한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;706&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xO23J/btrYquPOr1d/W9E9YoR8zeOIlkbn60U7hk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xO23J/btrYquPOr1d/W9E9YoR8zeOIlkbn60U7hk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xO23J/btrYquPOr1d/W9E9YoR8zeOIlkbn60U7hk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxO23J%2FbtrYquPOr1d%2FW9E9YoR8zeOIlkbn60U7hk%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;450&quot; height=&quot;406&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;706&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;3. TCP/IP&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TCP/IP&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;TCP/IP&lt;/b&gt;는 인터넷에서 표준으로 사용되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 프로토콜&lt;/b&gt;이며, IP를 비롯한 여러 프로토콜의 집합체를 총칭하여 부른다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;예를 들어 인터넷의 대표적인 서비스인 www, http 등이 이 프로토콜을 기반으로 움직인다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;TCP/IP 프로토콜을 사용해 전송되는 데이터는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패킷&lt;/b&gt;이라는 단위로 나눠진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;IP&lt;/b&gt;는 네트워크 각 기기의 주소를 할당하거나 해당 주소를 기반으로 패킷을 전송하는 역할을 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;TCP&lt;/b&gt;는 패킷의 수신 확인을 하고 올바른 순서로 패킷이 전달되도록 보장한다. 때문에 신뢰성이 높고 정확도가 높다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;4. IP&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;IP&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Internet Protocol&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;OSI 참조 모델의&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;3계층인 네트워크 계층에서 사용&lt;/b&gt;되는 네트워크 프로토콜이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;네트워크상의 기기에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;주소를 할당&lt;/b&gt;하고 경로를 선택해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;해당 주소로 패킷을 전송&lt;/b&gt;하는 역할을 수행한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;패킷을 상위 계층(TCP, UDP)에서 수신한 뒤,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;IP 헤더 정보&lt;/b&gt;(송신지와 수신지의 IP 주소 등)를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;추가&lt;/b&gt;해 네트워크에 전송한다.&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;예를 들어 우편물에 붙어있는 송장처럼 패킷에는 IP 헤더라는 꼬리표가 붙어 이 꼬리표를 가지고 목적지로 운반된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;경로 선택 방법이 정의되어 있어 IP를 통해 여러 개의 네트워크를 넘나드는 통신이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cdtTaZ/btrYpmRYfMI/vsYmzW0H6uKn8PZ4JTkOo1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cdtTaZ/btrYpmRYfMI/vsYmzW0H6uKn8PZ4JTkOo1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cdtTaZ/btrYpmRYfMI/vsYmzW0H6uKn8PZ4JTkOo1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcdtTaZ%2FbtrYpmRYfMI%2FvsYmzW0H6uKn8PZ4JTkOo1%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;430&quot; height=&quot;224&quot; data-origin-width=&quot;708&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;5. TCP&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TCP&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Transmission Control Protocol&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;OSI 참조 모델의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4계층인 전송 계층에서 사용&lt;/b&gt;되는 네트워크 프로토콜이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;연결 지향 방식&lt;/b&gt;의 통신 기능을 제공한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;데이터 손실 없는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;신뢰성 높은 데이터 통신을 보장&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;5계층(세션 계층) 이상의 프로토콜에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;통신 데이터를 수신해 패킷으로 분할&lt;/b&gt;하고,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;IP에 전달&lt;/b&gt;하여 목적지로 전송한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실제로 패킷을 전송하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;IP는 전송 순서를 보장하지 않기&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;때문에 따라서 패킷의 손실이나 순서가 뒤바뀌는 일이 발생할 수 있다. 따라서 TCP는 신뢰성 있는 통신을 위해 다음과 같은 방법을 이용한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;통신 데이터를 패킷으로 분할할 때&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;분할한 순서대로 시퀀스 번호를 부여&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;수신 측에서 시퀀스 번호를 확인해 필요에 따라 순서를 정렬해 패킷 순서가 올바른지 확인한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;수신 측에서 수신완료를 알리는 패킷(ACK 패킷)을 송신 측에 전송한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;송신 측에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;전송한 패킷이 도착했는지에 대한 여부를 판단&lt;/b&gt;할 수 있으며, 대답이 없는 경우 패킷을 다시 전송해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;손실을 방지&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b5OMAO/btrYlzqRXoi/WXnKtNncKW4P1qLGMhoYF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b5OMAO/btrYlzqRXoi/WXnKtNncKW4P1qLGMhoYF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b5OMAO/btrYlzqRXoi/WXnKtNncKW4P1qLGMhoYF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb5OMAO%2FbtrYlzqRXoi%2FWXnKtNncKW4P1qLGMhoYF0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;304&quot; data-origin-width=&quot;502&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;6. UDP&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;UDP&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;187&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bz6xbO/btrYqKSnojp/roKz0FFg77ASKGowCAkS51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bz6xbO/btrYqKSnojp/roKz0FFg77ASKGowCAkS51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bz6xbO/btrYqKSnojp/roKz0FFg77ASKGowCAkS51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbz6xbO%2FbtrYqKSnojp%2FroKz0FFg77ASKGowCAkS51%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;550&quot; height=&quot;158&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;187&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;User Datagram Protocol&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;OSI 참조 모델의&amp;nbsp;&lt;b&gt;4계층인 전송 계층에서 사용&lt;/b&gt;되는 네트워크 프로토콜이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;비연결 방식&lt;/b&gt;의 통신 기능을 제공한다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(이때 연결이 없다는 것은 송신 측에서 수신 측의 수신 여부와 상관없이 일방적으로 데이터를 보내고 끝내는 전송 방법을 의미)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;상위 계층에서 수신한&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;데이터를 패킷으로 분할해 IP를 통해 전송&lt;/b&gt;만 할 뿐, TCP처럼&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;수신 확인은 하지 않는다&lt;/b&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;rarr; 수신 측은 데이터가 정확한지 알 수 없고, 순서도 보장할 수 없으며, 분실되어도 알 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서 통신의&amp;nbsp;&lt;b&gt;신뢰성은 낮지만&lt;/b&gt;, TCP보다&amp;nbsp;&lt;b&gt;가볍고 속도가 빠르다&lt;/b&gt;는 특징이 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;주로 실시간성이 중요하거나 데이터의 신뢰성이 굳이 보장되지 않아도 되는 응용프로그램에서 UDP를 사용한다.&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;예) 시간적 연속성이 중요한 응용프로그램 : 동영상, 음성 전송&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deLyHx/btrYrjtdg7v/RzVh4SymoUOy29zXkXOKK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deLyHx/btrYrjtdg7v/RzVh4SymoUOy29zXkXOKK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deLyHx/btrYrjtdg7v/RzVh4SymoUOy29zXkXOKK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeLyHx%2FbtrYrjtdg7v%2FRzVh4SymoUOy29zXkXOKK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;500&quot; height=&quot;164&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;224&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;7. 패킷&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;패킷&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/osEom/btrYqSo509E/kfanCWC2LMTaFLkXGnaNR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/osEom/btrYqSo509E/kfanCWC2LMTaFLkXGnaNR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/osEom/btrYqSo509E/kfanCWC2LMTaFLkXGnaNR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FosEom%2FbtrYqSo509E%2FkfanCWC2LMTaFLkXGnaNR0%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;300&quot; height=&quot;188&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;3계층에서 만들어지는 통신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터의 단위&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;통신 데이터를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패킷이라는 단위로 작게 분할하여 송수신&lt;/b&gt;하는 통신을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패킷 통신&lt;/b&gt;이라 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;패킷에는 여러 정보가 포함되는데, 이 정보는 소포에 붙이는 꼬리표 같은 것이다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;송신지와 수신지의 주소 같은 속성 정보 포함 &amp;rarr; 이 정보를 가지고 네트워크를 통해 패킷이 올바른 목적지에 전달&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;패킷이 사용하는 네트워크 프로토콜에 대한 정보 포함 &amp;rarr; 이 정보를 가지고 여러 네트워크 프로토콜이 동일한 네트워크 회선상에 혼재가 된 상태에서도 이용 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;정리하자면, 고객(응용프로그램)이 보내고 싶은 물건(통신 데이터)은 작은 소포(패킷)으로 분할되고 분실되지 않도록 소포에 꼬리표를 붙인다. 이때 꼬리표는 소포의 배송을 담당하는 업체(네트워크 프로토콜)가 지정한 것을 사용한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span&gt;&lt;b&gt;데이터 단위&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;세그먼트&lt;/b&gt;(Segment) :&amp;nbsp;데이터를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;일정한 길이로 분할&lt;/b&gt;한 덩어리로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;4&lt;/b&gt;계층(TCP, UDP)에서 만들어짐&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;패킷&lt;/b&gt;(Packet) : 세그먼트를 목적지로 전달하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;IP 주소를 포함한 헤더&lt;/b&gt;가 붙은 형태로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;3&lt;/b&gt;계층(IP)에서 만들어짐&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;bull;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프레임&lt;/b&gt;(Frame) : 패킷을 목적지로 전달하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;MAC 주소를 포함한 헤더&lt;/b&gt;가 붙은 형태로, 2계층에서 만들어짐&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;8. 노드&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;노드&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zFpmJ/btrYj1g8vKd/IySoMCNXk39ZcVekXfYvoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zFpmJ/btrYj1g8vKd/IySoMCNXk39ZcVekXfYvoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zFpmJ/btrYj1g8vKd/IySoMCNXk39ZcVekXfYvoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzFpmJ%2FbtrYj1g8vKd%2FIySoMCNXk39ZcVekXfYvoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;291&quot; data-origin-width=&quot;578&quot; data-origin-height=&quot;480&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;네트워크에 연결되어 있는 네트워크 기기&lt;/b&gt;나 네트워크의 연결 지점을 말한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;10 노드 = &quot;네트워크에 10대의 기기가 연결되어 있다&quot;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;9. IP 주소&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;IP 주소&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;컴퓨터 네트워크에서 장치들이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서로를 인식하고 통신&lt;/b&gt;을 하기 위해서 사용하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;식별 번호&lt;/b&gt;이다.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202122;&quot;&gt;IP 주소를 이용하여 수신자를 향해 예정된 목적지로 데이터가 전달된다.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;(쉽게 말해 집 주소를 컴퓨터 용으로 디지털 숫자로 나타낸 네트워크 주소라고 생각하면 된다.)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;현재 IP 주소는 32비트 숫자로 표현하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;IPv4&lt;/b&gt;가 일반적이지만, 이 주소가 부족해짐에 따라 128비트 숫자로 표현하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;IPv6&lt;/b&gt;로의 이전이 진행되고 있다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;예) 192.168.0.1 - IPv4&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;IP 주소의 내용&lt;/span&gt;&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;네트워크 별로 나뉘는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;네트워크 주소&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;해당 네트워크 내에서 컴퓨터를 식별하기 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;호스트 주소&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b05mRv/btrYpnKcDJb/tyjEv9d5E3AEcuNoSJe3d0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b05mRv/btrYpnKcDJb/tyjEv9d5E3AEcuNoSJe3d0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b05mRv/btrYpnKcDJb/tyjEv9d5E3AEcuNoSJe3d0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb05mRv%2FbtrYpnKcDJb%2FtyjEv9d5E3AEcuNoSJe3d0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;174&quot; data-origin-width=&quot;890&quot; data-origin-height=&quot;388&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;h2 id=&quot;10. 서브넷 마스크&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서브넷 마스크&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;362&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cMORxg/btrYqLReuJ8/48u6OFMramSrxbKbGjkpS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cMORxg/btrYqLReuJ8/48u6OFMramSrxbKbGjkpS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cMORxg/btrYqLReuJ8/48u6OFMramSrxbKbGjkpS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcMORxg%2FbtrYqLReuJ8%2F48u6OFMramSrxbKbGjkpS0%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;450&quot; height=&quot;225&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;362&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;원래 하나의 네트워크가 작은 조각으로 쪼개져 있는 경우,&lt;b&gt;&amp;nbsp;작은 네트워크 조각&lt;/b&gt;을&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서브넷&lt;/b&gt;(subnet)이라 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;서브넷 마스크&lt;/b&gt;(subnet mask)는 이러한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서브넷을 표현하기 위한 값&lt;/b&gt;이다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;32비트 숫자로 1의 비트는 네트워크 부분을, 0의 비트는 호스트 부분을 나타낸다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;IP 주소는 네트워크 부분과 호스트 부분으로 나뉘는데, 앞에서부터 몇 비트까지 네트워크 주소로 사용할지 정의하기 위해 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;서브넷 마스크에 의해 호스트 주소 부분 중 몇 개의 비트를 네트워크 주소 부분으로 재정의하여, 단일 네트워크를 서브넷으로 구분할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkqtrU/btrYqMbw4fY/17g5yzKUgh0E9v8pMCewA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkqtrU/btrYqMbw4fY/17g5yzKUgh0E9v8pMCewA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkqtrU/btrYqMbw4fY/17g5yzKUgh0E9v8pMCewA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkqtrU%2FbtrYqMbw4fY%2F17g5yzKUgh0E9v8pMCewA0%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;450&quot; height=&quot;262&quot; data-origin-width=&quot;784&quot; data-origin-height=&quot;456&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;h2 id=&quot;11. 포트 번호&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;포트 번호&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;프로그램이 통신하는 번호, 쉽게 말해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;프로그램의 연결 장소&lt;/b&gt;이다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;네트워크의 어느 곳에 존재하는 컴퓨터인지? &amp;rarr; IP 주소&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;그 컴퓨터의 어느 프로그램에 전달할 패킷인가? &amp;rarr; Port 주소&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;프로그램이 네트워크에서 통신할 경우 접속 장소로 포트를 열고, 상대방의 IP 주소의 포트로 패킷을 송신하거나 수신한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;TCP/IP에 프로그램(서비스)별로 기본 포트가 정해져 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mmDUM/btrYpncgLtO/sRwR8nou86noLczrn4pJ4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mmDUM/btrYpncgLtO/sRwR8nou86noLczrn4pJ4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mmDUM/btrYpncgLtO/sRwR8nou86noLczrn4pJ4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmmDUM%2FbtrYpncgLtO%2FsRwR8nou86noLczrn4pJ4k%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;450&quot; height=&quot;435&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;752&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;h2 id=&quot;12. 도메인&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;도메인&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;인터넷에 연결된 컴퓨터를 사람이 쉽게 기억할 수 있도록&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문자로 표현한 인터넷 주소&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;네트워크 주소인 IP 주소는 아무런 의미가 없는 숫자 배열로 되어있어 사람이 기억하기가 어렵다. 이를 위해 각 IP 주소에&amp;nbsp;&lt;b&gt;사람이 기억하기 쉬운 문자열로 표현&lt;/b&gt;한 이름을 부여할 수 있는데, 이것이&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;도메인&lt;/b&gt;이다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;IP 주소 : 49.236.150.128&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;도메인 이름 : www.gitbut.co.kr&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;도메인 이름은 실제 주소와 비슷한 계층 구조를 가진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;456&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZSZlc/btrYq3c2yAd/5ZDpM4WMT5JkiaGg06WY0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZSZlc/btrYq3c2yAd/5ZDpM4WMT5JkiaGg06WY0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZSZlc/btrYq3c2yAd/5ZDpM4WMT5JkiaGg06WY0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZSZlc%2FbtrYq3c2yAd%2F5ZDpM4WMT5JkiaGg06WY0k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;350&quot; height=&quot;302&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;456&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;h2 id=&quot;13. IPv6&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;IPv6&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;218&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NJvLu/btrYqMo4Jlu/4GqvDomlO9okOANh7KzJy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NJvLu/btrYqMo4Jlu/4GqvDomlO9okOANh7KzJy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NJvLu/btrYqMo4Jlu/4GqvDomlO9okOANh7KzJy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNJvLu%2FbtrYqMo4Jlu%2F4GqvDomlO9okOANh7KzJy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;600&quot; height=&quot;167&quot; data-origin-width=&quot;782&quot; data-origin-height=&quot;218&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Internet Protocol version 6&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;TCP/IP 네트워크에서 사용되고 있는 3계층(네트워크 계층) 프로토콜인 IP의 차세대 규격&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;기존&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;32&lt;/b&gt;비트의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;IPv4&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;주소가 고갈되는 문제를 해결하기 위해 개발된 새로운&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;128&lt;/b&gt;비트 체계의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;무제한 인터넷 프로토콜 주소&lt;/b&gt;이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;16비트 단위로 구분하며, 각 단위는 16진수로 변환되어 콜론(:)으로 구분하여 표기한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://wormwlrm.github.io/2021/09/23/Overview-of-TCP-and-UDP.html&quot;&gt;10분 만에 훑어보는 TCP와 UDP&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=p6ASAAMwgd8&amp;amp;list=PLXvgR_grOs1BFH-TuqFsfHqbh-gpMbFoy&amp;amp;index=7&quot;&gt;네트워크 데이터 단위 정리&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <category>네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/245</guid>
      <comments>https://jollyn.tistory.com/245#entry245comment</comments>
      <pubDate>Fri, 6 Jan 2023 15:22:44 +0900</pubDate>
    </item>
    <item>
      <title>[Network] 네트워크 개론</title>
      <link>https://jollyn.tistory.com/244</link>
      <description>&lt;h2 id=&quot;1. LAN &amp;amp; WAN&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;LAN &amp;amp; WAN&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크란 정보가 전송되는 경로를 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;컴퓨터가 연결된 네트워크는 &lt;b&gt;규모에 따라&lt;/b&gt; LAN과 WAN이 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;1.1. LAN&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;LAN&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(근거리 통신망, Local Area Network)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;LAN은&amp;nbsp;사무실이나 빌딩 내부처럼 비교적&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;좁은 범위의 네트워크&lt;/b&gt;를 말한다. LAN을 통해 한정된 지역에서 컴퓨터를 기본으로 하는 여러가지 전자기기 사이의 정보교환이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이더넷, 와이파이가 바로 이 근거리 통신망에서 사용하기 위해 쓰이는 기술이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;건물 내부와 같이 제한된 곳에서 컴퓨터나 프린트를 연결할 수 있는 네트워크가 LAN이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;1.2. WAN&amp;nbsp;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;WAN&amp;nbsp;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;광역 통신망, Wide AreaNetwork)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;WAN은 멀리 떨어져 있는 LAN 사이를 전용선 등으로 연결한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;광역 네트워크&lt;/b&gt;를 말한다. 아무래도 멀리 떨어져 있기 때문에 LAN보다 속도가 많이 느리다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인터넷도 넓은 의미에서 WAN의 한 종류이다.&amp;nbsp;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2. 클라이언트 &amp;amp; 서버&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;클라이언트 &amp;amp; 서버&lt;/b&gt;&lt;/h2&gt;
&lt;h3 id=&quot;2.1. 클라이언트&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;클라이언트&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스를 요구&lt;/b&gt;하는 쪽 컴퓨터를 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;클라이언트란 네트워크에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;손님&lt;/b&gt;의 역할이라고 생각하면 된다. 예를 들어 레스토랑에서 자리를 안내받아 주문하거나 다양한 요구를 하는 역할인 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;2.2. 서버&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서버&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;서비스를 제공&lt;/b&gt;하는 쪽 컴퓨터를 말한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버란 네트워크에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;지배인&lt;/b&gt;의 역할이라고 생각하면 된다. 예를 들어 레스토랑에서 자리를 안내해주거나 메뉴를 가져다 주거나 모르는 것을 알려주는 역할인 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크에서 서버는 보조 역할이며, 무엇이 하고 싶은지 능동적으로 요청하는 것은 클라이언트의 일이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 네트워크에서는 서버와 클라이언트가 서로 상호작용하면서 정보가 오가게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span&gt;&lt;b&gt;Peer-to-Peer형&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;컴퓨터가 5~6대 정도의 소규모 LAN의 경우 서버용 컴퓨터를 따로 두지 않고 Peer-to-Peer 형태의 네트워크를 사용한다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;네트워크의 클라이언트가 서로 파일이나 프린터 등의 자원을 공유하는 형태이다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;각 컴퓨터가 경우에 따라 서버, 클라이언트가 되며 상황에 따라 역할이 바뀐다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;각 컴퓨터가 동등한 권리를 가지며 독립되어 있어 네트워크에 컴퓨터를 추가하거나 끊을 때 누군가의 허락이 필요 없이 자유롭기 때문에 쉽게 사용할 수 있다는 장점이 있다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span&gt;&lt;b&gt;클라이언트 서버형&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;서버용으로 전용 컴퓨터를 설치해 네트워크를 관리한다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;네트워크의 지배인이 따로 있기 때문에 컴퓨터가 네트워크에 접속하는 순간부터 서버의 허락이 필요하다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;서버가 일괄적으로 관리하기 때문에 보안상 제한이 가능하고 관리에 큰 노력이 들지 않는다는 장점이 있다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;3. 네트워크 구성 장비&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;네트워크 구성 장비&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크를 물리적으로 연결하는 방법의 규칙을 통일하므로써 컴퓨터의 종류에 관계없이 정보를 주고받을 수 있게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;LAN의 표준으로 많이 사용하는 이더넷에서 네트워크를 구성하는 대표적인 기기는 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2IvE8/btrYq3xjHAc/tKu1NlOJ2oJ0KxTdQEotL1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2IvE8/btrYq3xjHAc/tKu1NlOJ2oJ0KxTdQEotL1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2IvE8/btrYq3xjHAc/tKu1NlOJ2oJ0KxTdQEotL1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2IvE8%2FbtrYq3xjHAc%2FtKu1NlOJ2oJ0KxTdQEotL1%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;450&quot; height=&quot;870&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;870&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;라우터&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;서로 다른 네트워크를 연결하기 위한 기기&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;통신 데이터가 어떤 네트워크에 전송되어야 하는지 분별한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;허브&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;허브는 LAN 케이블을 연결하기 위한 포트를 여러개 가지고 있어 여러 대의 컴퓨터를 연결할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;허브에 연결된 컴퓨터는 서로 LAN 케이블로 연결된 상태가 된다. 따라서 여러 대의 컴퓨터끼리 서로 정보를 주고 받을 수 있는 환경이 구성된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;LAN&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;케이블&lt;/b&gt;&amp;nbsp;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;컴퓨터를 물리적으로 연결하기 위한 케이블&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;케이블을 NIC 포트에 꼽아 컴퓨터끼리 연결하면 데이터를 보내기 위한 경로가 만들어진다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;NIC&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Network Interface Card&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;컴퓨터를 네트워크에 연결하는 확장 포트&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;LAN 케이블을 연결하기 위한 포트(연결부)가 있어 컴퓨터의 데이터를 전기 신호로 변환해 이 포트를 통해 전송한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;한마디로 NIC는 네트워크와 컴퓨터 사이에서 중간 역할을 하는 번역기인 것이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;4. 네트워크 서비스&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;네트워크 서비스&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;네트워크 서비스란 서버가 네트워크에서 제공하는 기능이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서버는 서비스를 제공하는 측의 컴퓨터를 가리키므로 어떠한 서비스를 네트워크에 제공하는 것은 모두 서버의 역할이기 때문에 서비스 = 서버 기능이라 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;서비스의 종류에는 여러가지가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;882&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dM8sfG/btrYkLkI3WQ/4p2fRHKe17j419SqEhF6c1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dM8sfG/btrYkLkI3WQ/4p2fRHKe17j419SqEhF6c1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dM8sfG/btrYkLkI3WQ/4p2fRHKe17j419SqEhF6c1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdM8sfG%2FbtrYkLkI3WQ%2F4p2fRHKe17j419SqEhF6c1%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;450&quot; height=&quot;882&quot; data-origin-width=&quot;760&quot; data-origin-height=&quot;882&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;파일 및 프린터 공유 서비스&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;DHCP&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Dynamic Host Configuration Protocol&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;클라이언트에 대한 네트워크 설정 및 IP 주소 할당을 자동화하는 서비스&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;DNS&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Domain Name System&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;IP 주소 및 컴퓨터 이름을 관리하는 서비스, DNS 서비스를 통해 컴퓨터 이름으로 IP 주소를 알아낼 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;NTP&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Network Time Protocol&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;서비스가 실행되고 있는 컴퓨터의 시간으로 모든 컴퓨터의 시간을 동기화시키는 서비스&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;게이트&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;웨이&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;다른 네트워크로 들어가는 문의 역할을 하는 네트워크 포인트, 게이트 웨이가 없다면 자신의 로컬 네트워크 안에서만 통신이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span&gt;&lt;b&gt;라우터와 게이트 웨이의 차이점?&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&amp;bull; 라우터는 하나의 프로토콜 사용, 게이트 웨이는 하나 이상의 프로토콜 사용&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&lt;span&gt;&lt;b&gt;게이트 웨이 쉽게 이해하기&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;게이트 웨이는 한마디로 다른 네트워크로 들어가는 문이다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;나의 집을 하나의 네트워크라 했을 때, 옆집 철수의 집은 다른 네트워크일 것이다.&lt;/span&gt;&lt;br /&gt;&lt;span&gt;이때 우리 집에서 철수 집으로 가기 위해서는 우리집 대문을 통과해야 한다. 이때 우리집 대문이 게이트 웨이라 할 수 있다.&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;5. 인터넷 기술&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;인터넷 기술&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;928&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bdHsqk/btrYroOKsps/Bdz8GQntdyx2IshquXGen1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bdHsqk/btrYroOKsps/Bdz8GQntdyx2IshquXGen1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bdHsqk/btrYroOKsps/Bdz8GQntdyx2IshquXGen1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbdHsqk%2FbtrYroOKsps%2FBdz8GQntdyx2IshquXGen1%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;450&quot; height=&quot;541&quot; data-origin-width=&quot;772&quot; data-origin-height=&quot;928&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;인터넷&lt;/b&gt;&amp;nbsp;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;세계적인 규모의 네트워크이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;TCP/IP&lt;/b&gt;라는 네트워크 프로토콜을 기반으로 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;IP(Internet Protocol)는 데이터 전송을 담당하며, 네트워크 상 각 컴퓨터는 고유한 IP 주소(IP Address, 인터넷 규약 주소)를 갖는다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;라우터&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;LAN - LAN을 연결&lt;/b&gt;하는 역할을 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;라우터가 경로를 선택하면 데이터를 목적지인 네트워크로 전송한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;www&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;인터넷에서 표준으로 사용되는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;문서 시스템&lt;/b&gt;이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;문서는 HTML이라는 언어를 사용해 작성된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;URL&lt;/b&gt;이라는 형식의 주소를 지정해 어디서나 열람할 수 있게 된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;VPN&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;Virtual Private Network&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;인터넷에 가장 전용선 공간을 구축해 거점 사이를 안전하게 연결하는 기술이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;암호화 기술이며, 가상 전용선 공간은 암호화된 통신 데이터를 주고 받을 수 있도록 구축되어 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;이메일&lt;/b&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;컴퓨터 네트워크상에서 주고 받는 편지라고 생각하면 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;글 뿐만 아니라 다양한 데이터를 주고 받을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기타미 류지 ⌜그림으로 이해하는 네트워크 용어⌟&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://ja-gamma.tistory.com/entry/%EA%B2%8C%EC%9D%B4%ED%8A%B8%EC%9B%A8%EC%9D%B4%EB%9E%80&quot;&gt;게이트웨이란?&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Computer Science/네트워크</category>
      <category>네트워크</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/244</guid>
      <comments>https://jollyn.tistory.com/244#entry244comment</comments>
      <pubDate>Wed, 4 Jan 2023 14:41:31 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] OSIV</title>
      <link>https://jollyn.tistory.com/243</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;OSIV란?&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Open Session In View&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트를 뷰까지 열어두는 기능이다.&lt;/li&gt;
&lt;li&gt;클라이언트 요청이 들어올 때 영속성 컨텍스트를 생성해서 요청이 끝날 때까지 같은 영속성 컨텍스를 유지한다. 하여 한 번 조회된 엔티티는 요청이 끝날 때까지 영속 상태를 유지한다.&lt;/li&gt;
&lt;li&gt;뷰까지 영속성 컨텍스트가 살아있음에 따라 컨트롤러나 뷰에서도 지연 로딩을 사용할 수 있게 된다.&lt;/li&gt;
&lt;li&gt;Spring Boot JPA 의존성을 주입 받아 애플리케이션을 구성할 경우 기본적으로 OSIV가 적용된다. (default:&amp;nbsp; true)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;OSIV ON&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;528&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bGqFhD/btrWv7QPFln/Ix1JZIZeEgoxTL4aGYhCBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bGqFhD/btrWv7QPFln/Ix1JZIZeEgoxTL4aGYhCBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bGqFhD/btrWv7QPFln/Ix1JZIZeEgoxTL4aGYhCBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbGqFhD%2FbtrWv7QPFln%2FIx1JZIZeEgoxTL4aGYhCBK%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;800&quot; height=&quot;320&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;528&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;spring.jpa.open-in-view: true&lt;/li&gt;
&lt;li&gt;트랜잭션 시작 시점에 영속성 컨텍스트가 데이터베이스 커넥션을 가져오며, 트랜잭션 종료 시점이 아닌 API 응답이 끝날 때까지 영속성 컨텍스트와 데이터베이스 커넥션을 끝까지 유지한다.&lt;/li&gt;
&lt;li&gt;지연 로딩은 영속성 컨텍스트가 살아있어야 가능하다. 따라서 OSIV 사용시 영속성 컨텍스트가 컨트롤러와 뷰까지 유지되므로 지연 로딩을 더욱 유연하게 활용할 수 있다.&lt;/li&gt;
&lt;li&gt;하지만 너무 오랜시간동안 데이터베이스 커넥션 리소스를 사용하기 때문에 실시간 트래픽이 중요한 애플리케이션에서는 커넥션이 모자랄 수 있다. (&quot;커넥션이 마른다&quot;고 표현)&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;OSIV OFF&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;584&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ceLWCR/btrUKl3wzkZ/8Pkykw20lzntNoNXShArk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ceLWCR/btrUKl3wzkZ/8Pkykw20lzntNoNXShArk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ceLWCR/btrUKl3wzkZ/8Pkykw20lzntNoNXShArk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FceLWCR%2FbtrUKl3wzkZ%2F8Pkykw20lzntNoNXShArk0%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;800&quot; height=&quot;317&quot; data-origin-width=&quot;1472&quot; data-origin-height=&quot;584&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;spring.jpa.open-in-view: false&lt;/li&gt;
&lt;li&gt;트랜잭션 종료 시점에 영속성 컨텍스트를 닫고, 데이터베이스 커넥션도 반환한다.&lt;/li&gt;
&lt;li&gt;따라서 커넥션 리소스를 낭비하지 않는다는 장점이 있다.&lt;/li&gt;
&lt;li&gt;하지만 지연 로딩을 트랜잭션 안에서 모두 처리해야 한다는 단점이 있다. 결론적으로 트랜잭션이 끝나기 전에 지연 로딩을 강제로 호출해 두어야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;커멘드와 쿼리 분리&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;성능을 생각한다면 OSIV를 마냥 켜둘 수만은 없다.&lt;/li&gt;
&lt;li&gt;실무에서 OSIV를 끈 상태로 복잡성을 관리하기 위해 Command와 Query를 분리하는 방법을 사용한다.&lt;/li&gt;
&lt;li&gt;비즈니스 로직은 특정 엔티티 몇 개를 등록, 수정하는 것이기 때문에 성능이 크게 문제되지 않는다.&lt;/li&gt;
&lt;li&gt;하지만 복잡한 화면을 출력하기 위한 쿼리는 화면에 맞춰 성능을 최적화하는 것이 중요하다.&lt;/li&gt;
&lt;li&gt;따라서 이 둘의 관심사를 명확하게 분리하는 것은 유지보수 측면에서 의미있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 주문 서비스에 대해 커멘드와 쿼리를 분리한다면 다음과 같이 구성할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OrderService : 핵심 비즈니스 로직&lt;/li&gt;
&lt;li&gt;OrderQueryService : 화면이나 API에 맞춘 서비스 (주로 읽기 전용 트랜잭션(read only) 사용)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/Jpa</category>
      <category>JPA</category>
      <category>open in session view</category>
      <category>OSIV</category>
      <category>영속성 컨텍스트 범위</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/243</guid>
      <comments>https://jollyn.tistory.com/243#entry243comment</comments>
      <pubDate>Tue, 27 Dec 2022 20:33:48 +0900</pubDate>
    </item>
    <item>
      <title>[Intellij] 드래그 영역 색상 설정</title>
      <link>https://jollyn.tistory.com/241</link>
      <description>&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2090&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qz4KG/btrTPMHveXU/fvpx2jaOwgfprck73BS4h0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qz4KG/btrTPMHveXU/fvpx2jaOwgfprck73BS4h0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qz4KG/btrTPMHveXU/fvpx2jaOwgfprck73BS4h0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqz4KG%2FbtrTPMHveXU%2Ffvpx2jaOwgfprck73BS4h0%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;2090&quot; height=&quot;812&quot; data-origin-width=&quot;2090&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인텔리제이 설정창에서 &lt;b&gt;Editor&lt;/b&gt; - &lt;b&gt;Color&lt;/b&gt; &lt;b&gt;Scheme&lt;/b&gt; - &lt;b&gt;General&lt;/b&gt; 에 들어가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Editor&lt;/b&gt; - &lt;b&gt;Guides&lt;/b&gt; - &lt;b&gt;Selection&lt;/b&gt; &lt;b&gt;background&lt;/b&gt; 색상을 눈에 잘 띄는 색상으로 변경해주면 끝이다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;672&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/clguEY/btrTPtnUh1g/DxrKvRgxQsuCdKGLTXQq71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/clguEY/btrTPtnUh1g/DxrKvRgxQsuCdKGLTXQq71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/clguEY/btrTPtnUh1g/DxrKvRgxQsuCdKGLTXQq71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FclguEY%2FbtrTPtnUh1g%2FDxrKvRgxQsuCdKGLTXQq71%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;1906&quot; height=&quot;672&quot; data-origin-width=&quot;1906&quot; data-origin-height=&quot;672&quot;/&gt;&lt;/span&gt;&lt;/figure&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;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/개발환경</category>
      <category>IntelliJ</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/241</guid>
      <comments>https://jollyn.tistory.com/241#entry241comment</comments>
      <pubDate>Fri, 16 Dec 2022 15:51:38 +0900</pubDate>
    </item>
    <item>
      <title>[Git] 커밋 이력 변경하기</title>
      <link>https://jollyn.tistory.com/240</link>
      <description>&lt;h2 id=&quot;1-최근-커밋-날짜를-현재-날짜로-변경&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;가장 최근 커밋 변경&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1670416999904&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 최근 커밋 변경하기
git commit --amend

# 최근 커밋을 현재 시간으로 변경하기
git commit --amend --no-edit --date &quot;$(date)&quot;

# 최근 커밋을 어제의 현재 시간으로 변경하기
git commit --amend --no-edit --date &quot;1 day ago&quot;

# 최근 커밋을 특정 날짜, 시간으로 변경하기
git commit --amend --no-edit --date &quot;Thu 30 Mar 2023 10:10:00 KST&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1671688810204&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GIT_COMMITTER_DATE=&quot;Wed 14 Dec 2022 17:54:10 KST&quot; git commit --amend --date &quot;Wed 14 Dec 2022 17:54:10 KST&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;가장 최근 커밋보다 이전 커밋 변경&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;  rebase를 진행할 커밋 지정&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;shell&quot; data-ke-language=&quot;shell&quot;&gt;&lt;code&gt;git rebase -i HEAD~2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;  수정할 커밋 지정&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1670417178914&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pick fc27d76 Commit Message
edit fc27d76 Commit Message&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;수정할 커밋을 pick에서 edit으로 변경한 뒤 :wq으로 빠져나온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;  커밋 및 작성 시간 변경&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1670417315041&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;GIT_COMMITTER_DATE=&quot;Wed 14 Dec 2022 17:54:10 KST&quot; git commit --amend --date &quot;Wed 14 Dec 2022 17:54:10 KST&quot;
GIT_AUTHOR_DATE=&quot;Wed 14 Dec 2022 17:54:10 KST&quot; git commit --amend --date &quot;Wed 14 Dec 2022 17:54:10 KST&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;  변경 내역 저장 및 rebase 종료&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1670417394908&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git rebase --continue&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;저장이 아닌 취소를 원한다면 --abort 옵션을 사용하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;변경 확인하기&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1671688864369&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git log --pretty=fuller&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hirlawldo.tistory.com/156&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Git commit 이력 변경&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/Git &amp;amp; Github</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/240</guid>
      <comments>https://jollyn.tistory.com/240#entry240comment</comments>
      <pubDate>Wed, 7 Dec 2022 21:50:59 +0900</pubDate>
    </item>
    <item>
      <title>.gitignore 양식</title>
      <link>https://jollyn.tistory.com/237</link>
      <description>&lt;pre id=&quot;code_1669787833221&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;### Maven ###
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### Gradle ###
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**
!**/src/test/**

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### macOS ###
.DS_Store&lt;/code&gt;&lt;/pre&gt;</description>
      <category> ️ Programming/Code Guide</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/237</guid>
      <comments>https://jollyn.tistory.com/237#entry237comment</comments>
      <pubDate>Wed, 30 Nov 2022 14:58:01 +0900</pubDate>
    </item>
    <item>
      <title>MVC를 지키면서 코딩하는 방법</title>
      <link>https://jollyn.tistory.com/236</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Model은 Controller와 View에 의존하지 않아야 한다.&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이말은 즉, 모델 내부에 컨트롤러와 뷰에 관련된 코드가 있으면 안된다는 것이다.&lt;/li&gt;
&lt;li&gt;이를 확인하는 쉬운 방법은 모델에서 컨트롤러와 뷰 클래스를 import해서 사용하는지 확인하는 것이다.&lt;/li&gt;
&lt;li&gt;모델은 데이터가 관련된 부분이다 보니 언제든 깔끔하고 정제된 데이터를 꺼내 쓸 수 있도록 뷰나 컨트롤러 코드를 섞지 않는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1668480546895&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Friend {
    private String name;
    private int age;
    
    pubic Friend(String name, int age) {
    	this.name = name;
        this.age = age;
    }
    
    public String getName() {
    	return name;
    }
    
    public int getAge() {
    	return age;
    }
}&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;&lt;b&gt;View는 Model에만 의존해야 하고, Controller에는 의존하면 안된다.&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, 뷰 내부에 모델의 코드만 있을 수 있고 컨트롤러의 코드가 있으면 안된다는 것이다.&lt;/li&gt;
&lt;li&gt;뷰가 모델로부터 데이터를 받을 때는 사용자마다 다르게 보여줘야 하는 데이터에 대해서만 받아야 한다.&lt;br /&gt;(공통적으로 보여줘야 하는 정보는 모델로부터 전달받는 것이 아닌 뷰가 자체적으로 가지고 있어야 한다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1668485338291&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class OutputView {
	public void printProfile(Person person) {
    	System.out.println(&quot;이름은 &quot; + person.getName() + &quot; 입니다.&quot;);
        System.out.println(&quot;나이는 &quot; + person.getAge() + &quot; 입니다.&quot;);
    }
}&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;&lt;b&gt;Controller는 Model과 View에 의존해도 된다.&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;즉, 컨트롤러 내부에는 모델과 뷰의 코드가 있을 수 있다.&lt;/li&gt;
&lt;li&gt;뷰가 모델로부터 데이터를 받을 때는 반드시 컨트롤러를 통해 전달 받아야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1668485601280&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Controller {
	pubic static void main(Stirng[] args) {
    	Person person = new Person(&quot;jolly&quot;, 20);
        OutputView.printProfile(person);
    }
}&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ogaXW6KPc8I&amp;amp;t=10s&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[10분 테코톡] 제리의 MVC 패턴&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/개발상식</category>
      <category>MVC 규칙</category>
      <category>MVC 패턴</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/236</guid>
      <comments>https://jollyn.tistory.com/236#entry236comment</comments>
      <pubDate>Tue, 15 Nov 2022 13:15:31 +0900</pubDate>
    </item>
    <item>
      <title>[Mac] 사용법 간단 정리</title>
      <link>https://jollyn.tistory.com/234</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;파인더 경로 막대 열기&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;54&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xrn17/btrSHUHxf8D/A98S08im4KpFuDewZ2Jrkk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xrn17/btrSHUHxf8D/A98S08im4KpFuDewZ2Jrkk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xrn17/btrSHUHxf8D/A98S08im4KpFuDewZ2Jrkk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fxrn17%2FbtrSHUHxf8D%2FA98S08im4KpFuDewZ2Jrkk%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;362&quot; height=&quot;28&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;54&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;command&amp;nbsp;+&amp;nbsp;option&amp;nbsp;+&amp;nbsp;p&amp;nbsp;키를 누르면 파인더 아래에 현재 열어둔 폴더의 경로가 나타난다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;계속 열어두지 않고 필요할 때만 경로를 확인하고 싶다면 위 옵션을 끄고, option키를 길게 누르면 일시적으로 폴더 경로가 나타난다.&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; 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;&lt;b&gt;숨겨진 폴더 보기&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;command(&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;⌘&lt;/span&gt;) + shift(&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;&amp;uarr;)&lt;/span&gt; + . 키를 누르면 숨겨진 폴더 보이기/가리기 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;배터리 충전 관리하기&lt;/b&gt;&lt;/h2&gt;
&lt;figure id=&quot;og_1670061090343&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;AppHouseKitchen &amp;ndash; Mac Software for the Gourmet&quot; data-og-description=&quot;Sailing Mode Normally, your MacBooks battery will always charge and discharge slightly to stay at a desired SoC, even when the Charge Limiter is activated. With Sailing Mode, it is possible to set a &amp;quot;sailing&amp;quot; range in which the battery will stay. Example: &quot; data-og-host=&quot;apphousekitchen.com&quot; data-og-source-url=&quot;https://apphousekitchen.com/&quot; data-og-url=&quot;https://apphousekitchen.com/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/U1OBE/hyQL9rG7Pg/1kr2SKZYMQEdHWQnLkuCAk/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024,https://scrap.kakaocdn.net/dn/ds9PUS/hyQMq0I1Ed/1SPp0iQinYeembxUz4jSG0/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024,https://scrap.kakaocdn.net/dn/OYfM9/hyQMvucc0h/WZmnRuZgw6oTKaiQq5hX91/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024&quot;&gt;&lt;a href=&quot;https://apphousekitchen.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://apphousekitchen.com/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/U1OBE/hyQL9rG7Pg/1kr2SKZYMQEdHWQnLkuCAk/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024,https://scrap.kakaocdn.net/dn/ds9PUS/hyQMq0I1Ed/1SPp0iQinYeembxUz4jSG0/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024,https://scrap.kakaocdn.net/dn/OYfM9/hyQMvucc0h/WZmnRuZgw6oTKaiQq5hX91/img.png?width=1024&amp;amp;height=1024&amp;amp;face=0_0_1024_1024');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;AppHouseKitchen &amp;ndash; Mac Software for the Gourmet&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Sailing Mode Normally, your MacBooks battery will always charge and discharge slightly to stay at a desired SoC, even when the Charge Limiter is activated. With Sailing Mode, it is possible to set a &quot;sailing&quot; range in which the battery will stay. Example:&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;apphousekitchen.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Iterm 꾸미기&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1675832863468&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 커스텀 초기화 명령어
p10k configure&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://ooeunz.tistory.com/21&quot;&gt;https://ooeunz.tistory.com/21&lt;/a&gt;&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;&lt;b&gt;자바 버전 관리하기&lt;/b&gt;&lt;/h2&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;사용중인 쉘이 무엇인지 확인하기&lt;/blockquote&gt;
&lt;pre id=&quot;code_1681538052755&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;echo $SHELL&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;bash 쉘을 사용하는 경우 ~/.bash_profile&lt;/li&gt;
&lt;li&gt;zsh 쉘을 사용하는 경우 ~/.zshrc&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;수정창 열기&lt;/blockquote&gt;
&lt;pre id=&quot;code_1681537800440&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;vi ~/.zshrc&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;환경변수 설정&lt;/blockquote&gt;
&lt;pre id=&quot;code_1681537846773&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;### Java Paths
# 방법1
export JAVA_HOME_11=$(/usr/libexec/java_home -v11)
export JAVA_HOME_14=$(/usr/libexec/java_home -v14)

# 방법2
export JAVA_HOME_11=/Library/Java/JavaVirtualMachines/jdk-11.0.17.jdk/Contents/Home
export JAVA_HOME_17=/Library/Java/JavaVirtualMachines/jdk-17.jdk/Contents/Home

### Java 11
export JAVA_HOME=$JAVA_HOME_11

### Java 14
# 14버전을 사용하고자 하는 경우 아래 주석(#)을 해제하고 위에 11버전을 주석처리 하면된다.
# export JAVA_HOME=$JAVA_HOME_14

export PATH=${PATH}:$JAVA_HOME/bin&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;11버전(JAVA_HOME_11)과 17버전(JAVA_HOME_17)을 변수로 만들어두고&lt;/li&gt;
&lt;li&gt;JAVA_HOME으로 사용할 버전을 설정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;변경사항 반영&lt;/blockquote&gt;
&lt;pre id=&quot;code_1681537971340&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;source ~/.zshrc&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://llighter.github.io/install-java-on-mac/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;맥에서 Brew로 자바 설치하기(feat. 자바버전 바꾸기)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.devkuma.com/docs/mac-os/java-version/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mac OS Java(JDK) Version 변경 방법&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Etc</category>
      <category>Mac</category>
      <category>맥 사용법</category>
      <category>맥 파일 경로 보이기</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/234</guid>
      <comments>https://jollyn.tistory.com/234#entry234comment</comments>
      <pubDate>Fri, 11 Nov 2022 00:56:02 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Stream 중복 제거하기 - distinct()</title>
      <link>https://jollyn.tistory.com/233</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Stream 클래스에서 제공하는 distinct() 메소드를 활용해 중복을 제거하는 방법에 대해 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;1. distinct()&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;distinct()&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Stream 클래스 제공하는 메소드로,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중복 요소를 제거&lt;/b&gt;하고 고유한 요소로 구성된&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;새로운 Stream을 반환&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;중복된 요소를 확인하기 위해 equals(), hascode() 메서드를 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;중복된 요소가 존재하는 경우 첫번째 위치의 요소를 반환하기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;정렬 순서를 보장&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;108&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSuhke/btrR8a5uHGm/Z4qMm2jqlBJk7v88gy5Ib0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSuhke/btrR8a5uHGm/Z4qMm2jqlBJk7v88gy5Ib0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSuhke/btrR8a5uHGm/Z4qMm2jqlBJk7v88gy5Ib0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSuhke%2FbtrR8a5uHGm%2FZ4qMm2jqlBJk7v88gy5Ib0%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;2138&quot; height=&quot;108&quot; data-origin-width=&quot;2138&quot; data-origin-height=&quot;108&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예제) List&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1669389283260&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Integer&amp;gt; intList = Arrays.asList(1, 3, 2, 3, 5, 5, 7, 6);

List&amp;lt;Integer&amp;gt; intStreamToList = intList.stream()
                                       .distinct() // 중복 제거, 순서 보장o
                                       .collect(Collectors.toList());

System.out.println(&quot;intList = &quot; + intList);
System.out.println(&quot;intStreamToList = &quot; + intStreamToList);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1669391274491&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;intList = [1, 3, 2, 3, 5, 5, 7, 6]
intListStream = [1, 3, 2, 5, 7, 6]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;distint() 메서드 반환 결과를 Stream이 아닌 List로 반환받기 위해 collect() 메서드를 호출해주었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;중복이 제거되면서, 순서가 보장된 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;1.2. 예제) 사용자가 정의한 클래스&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;예제) 사용자가 정의한 클래스&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1669390504362&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return &quot;Person{&quot; +
                &quot;name='&quot; + name + '\'' +
                &quot;, age='&quot; + age + '\'' +
                '}';
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;위와 같이 사용자가 정의한 클래스의 경우 distinct() 메소드는 어떻게 중복을 제거할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1669390676507&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Person&amp;gt; personList = Arrays.asList(
                                new Person(&quot;짱구&quot;, 7),
                                new Person(&quot;짱구&quot;, 7),
                                new Person(&quot;철수&quot;, 7),
                                new Person(&quot;철수&quot;, 7)
                          );

List&amp;lt;Person&amp;gt; personListStream = personList.stream()
                                          .distinct()
                                          .collect(Collectors.toList());

personListStream.forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1669390685241&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Person{name='짱구', age='7'}
Person{name='짱구', age='7'}
Person{name='철수', age='7'}
Person{name='철수', age='7'}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실행 결과 의도한 대로 중복이 제거되지 않을 것을 확인할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 List의 각 요소는 실제 데이터 값이 아닌 참조값을 갖게 된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 기본 타입이 아닌 참조 타입인 경우 hashCode()와 equals() 메서드를 재정의해줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1669390804583&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Person {
    ...
    // equals, haschCode 재정의
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Person person = (Person) o;
        return age == person.age &amp;amp;&amp;amp; Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1669391015953&quot; class=&quot;gradle&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Person&amp;gt; personList = Arrays.asList(
                                new Person(&quot;짱구&quot;, 7),
                                new Person(&quot;짱구&quot;, 7),
                                new Person(&quot;철수&quot;, 7),
                                new Person(&quot;철수&quot;, 7)
                          );

List&amp;lt;Person&amp;gt; personListStream = personList.stream()
                                          .distinct()
                                          .collect(Collectors.toList());

personListStream.forEach(System.out::println);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1669391021244&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Person{name='짱구', age='7'}
Person{name='철수', age='7'}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;재정의 해준 뒤 중복 제거가 잘 된 것을 확인 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>☕ Java/API</category>
      <category>DISTINCT</category>
      <category>Stream</category>
      <category>Stream 메서드</category>
      <category>Stream 중복 제거하기</category>
      <category>중복제거</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/233</guid>
      <comments>https://jollyn.tistory.com/233#entry233comment</comments>
      <pubDate>Thu, 10 Nov 2022 21:08:17 +0900</pubDate>
    </item>
    <item>
      <title>[Intellij] 코드 포맷팅 설정하기</title>
      <link>https://jollyn.tistory.com/224</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;인텔리제이 설정의 Code Style에서 외부 코드 포맷을 등록해서 사용할 수 있다.&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;Import Scheme를 클릭한 뒤 본인이 다운받은 xml 파일을 등록해 사용하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2140&quot; data-origin-height=&quot;1416&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ZAjF5/btrQlH3w9Cf/swiXDTEFeyw5JfHqXNRZK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ZAjF5/btrQlH3w9Cf/swiXDTEFeyw5JfHqXNRZK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ZAjF5/btrQlH3w9Cf/swiXDTEFeyw5JfHqXNRZK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZAjF5%2FbtrQlH3w9Cf%2FswiXDTEFeyw5JfHqXNRZK1%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;800&quot; height=&quot;529&quot; data-origin-width=&quot;2140&quot; data-origin-height=&quot;1416&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;외부 코드 포맷 다운로드&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 화면이 나오면 우클릭 후 다른 이름으로 저장한다. (이때 확장자가 xml인지 확인!)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1730&quot; data-origin-height=&quot;1130&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BIGgK/btrQPDzsLBe/mtYOrurkOE9UAmeqBKHSyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BIGgK/btrQPDzsLBe/mtYOrurkOE9UAmeqBKHSyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BIGgK/btrQPDzsLBe/mtYOrurkOE9UAmeqBKHSyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBIGgK%2FbtrQPDzsLBe%2FmtYOrurkOE9UAmeqBKHSyK%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;800&quot; height=&quot;1130&quot; data-origin-width=&quot;1730&quot; data-origin-height=&quot;1130&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  참고 포맷 링크&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/naver/hackday-conventions-java/blob/master/rule-config/naver-intellij-formatter.xml&quot;&gt;네이버 포맷&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/google/styleguide/blob/gh-pages/intellij-java-google-style.xml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;구글 포맷&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;Reference&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bestinu.tistory.com/64&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://bestinu.tistory.com/64&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/개발환경</category>
      <category>인텔리제이</category>
      <category>코드 포맷팅 설정</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/224</guid>
      <comments>https://jollyn.tistory.com/224#entry224comment</comments>
      <pubDate>Thu, 3 Nov 2022 23:38:30 +0900</pubDate>
    </item>
    <item>
      <title>[Git] 커밋 메세지 컨벤션</title>
      <link>https://jollyn.tistory.com/222</link>
      <description>&lt;h2 id=&quot;1. 커밋 메세지 타입&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;커밋 메세지 타입&lt;/b&gt;&lt;/h2&gt;
&lt;table style=&quot;border-collapse: collapse; width: 70.1162%; height: 209px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Feat&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;새로운 기능 추가 및 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Fix&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;버그 또는 에러 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Hotfix&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;급하게 치명적인 버그 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Style&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;스타일 수정 (포맷팅, 세미콜론 누락, 오타, 함수명 수정 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Refactor&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;코드 리팩토링 (똑같은 기능인데 코드만 개선)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Test&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;테스트 코드 추가 및 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Chore&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;빌드 수정, 패키지 추가, gitignore, 자잘한 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Docs&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;문서 수정 (readme 등)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;Comment&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;주석 수정 및 삭제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center; height: 19px;&quot;&gt;File&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center; height: 19px;&quot;&gt;파일 이동 또는 삭제, 파일명 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 15.0215%; text-align: center;&quot;&gt;Design&lt;/td&gt;
&lt;td style=&quot;width: 51.5423%; text-align: center;&quot;&gt;디자인 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;&lt;span&gt;Reference&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hyeo-noo.tistory.com/394&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;의미있는 commit 메세지와 깔끔한 history&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://velog.io/@shin6403/Git-git-%EC%BB%A4%EB%B0%8B-%EC%BB%A8%EB%B2%A4%EC%85%98-%EC%84%A4%EC%A0%95%ED%95%98%EA%B8%B0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;커밋 컨벤션 설정하기&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bangu4.tistory.com/376&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git 컨벤션 commit, branch 전략&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://insight.infograb.net/blog/2023/04/21/why-commit-convention-is-important/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;git 커밋 메세지는 왜 중요할까?&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category> ️ Programming/Git &amp;amp; Github</category>
      <category>commit</category>
      <category>git</category>
      <category>커밋 메세지 전략</category>
      <category>커밋 전략</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/222</guid>
      <comments>https://jollyn.tistory.com/222#entry222comment</comments>
      <pubDate>Sun, 30 Oct 2022 23:33:45 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] #16 JPQL : 기본 문법</title>
      <link>https://jollyn.tistory.com/220</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은&amp;nbsp;&lt;a href=&quot;https://www.inflearn.com/course/ORM-JPA-Basic/dashboard&quot;&gt;인프런 - 자바 ORM 표준 JPA 프로그래밍 (기본편)&lt;/a&gt; 을 강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JPQL이란?&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;객체지향 쿼리 언어&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;테이블을 대상으로 쿼리하는 것이 아닌 엔티티 객체를 대상으로 쿼리한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JPQL은 SQL을 추상화해서 특정 데이터베이스 SQL에 의존하지 않는다는 장점이 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JPQL도 결국 SQL로 변환되어 실행된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JPQL 기본 문법&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;select, update, delete&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;930&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KMLYx/btsmlTZj7Qj/jeGTKmoflI3yx8w7Dcldp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KMLYx/btsmlTZj7Qj/jeGTKmoflI3yx8w7Dcldp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KMLYx/btsmlTZj7Qj/jeGTKmoflI3yx8w7Dcldp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKMLYx%2FbtsmlTZj7Qj%2FjeGTKmoflI3yx8w7Dcldp1%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;300&quot; height=&quot;247&quot; data-origin-width=&quot;1128&quot; data-origin-height=&quot;930&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1667140093144&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select m from Member as m where m.age &amp;gt; 18&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;SQL 문법과 동일하다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;엔티티, 속성은 대소문자를 구분한다. (Member, age)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JPQL 키워드는 대소문자를 구분하지 않는다. (SELECT, FROM, WHERE)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;테이블 이름이 아닌&amp;nbsp;&lt;b&gt;엔티티 이름을 사용&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;별칭&lt;/b&gt;을 필수로 사용한다. (m) (as 생략 가능)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;집합과 정렬&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1688391287761&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;select
    count(m),   -- 회원수
    sum(m.age), -- 나이합
    avg(m.age), -- 평균 나이
    max(m.age), -- 최대 나이
    min(m.age)  -- 최소 나이
from Member m&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;group by, having, order by 모두 동일하게 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;TypeQuery, Query&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1688391476251&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;TypedQuery&amp;lt;Member&amp;gt; query = em.createQuery(&quot;select m from Member m&quot;, Member.class); // 두번째 인자로 타입 지정
Query query = em.createQuery(&quot;select m.username, m.age from Member m&quot;); // String, int 둘 중 어떤 타입으로 지정 불가능&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;TypeQuery&lt;/b&gt; : 반환 타입이 명확할 때 사용&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Query&lt;/b&gt; : 반환 타입이 명확하지 않을 때 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;결과 조회 API&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1688391941584&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; result = em.createQuery(&quot;select m from Member m&quot;, Member.class)
                        .getResultList();

Member result = em.createQuery(&quot;select m from Member m where m.id=1&quot;, Member.class)
                  .getSingleResult();&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;query.&lt;b&gt;getResultList&lt;/b&gt;()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과가 1개 이상일 때 사용&lt;/li&gt;
&lt;li&gt;리스트 반환&lt;/li&gt;
&lt;li&gt;결과가 없으면 빈 리스트를 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;query.&lt;b&gt;getSingleResult&lt;/b&gt;()
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과가 정확히 1개일 때 사용&lt;/li&gt;
&lt;li&gt;단일 객체 반환&lt;/li&gt;
&lt;li&gt;결과가 없으면 javax.persistence.NoResultException&lt;/li&gt;
&lt;li&gt;결과가 둘 이상이면 javax.persistence.NonUniqueResultException&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;파라미터 바인딩&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1688392133940&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Member result = em.createQuery(&quot;select m from Member m where m.username = :username&quot;, Member.class)
                  .setParameter(&quot;username&quot;, &quot;member1&quot;)
                  .getSingleResult();&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;query.setParameter() : &quot;:parameter&quot;로 기준을 지정한뒤, setParameter() 메서드 체이닝으로 값을 지정&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;여러 값 조회&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1688398395979&quot; class=&quot;dart&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 방법1
List result = em.createQuery(&quot;select m.username, m.age from Member m&quot;)
                .getResultList();
Object o = result.get(0);
Object[] ol = (Object[]) o;

// 방법2
List&amp;lt;Object[]&amp;gt; result = em.createQuery(&quot;select m.username, m.age from Member m&quot;)
                          .getResultList();
Object[] ol = result.get(0);

// 방법3
List&amp;lt;MemberDto&amp;gt; result = em.createQuery(&quot;select new jpql.MemberDto(m.username, m.age) from Member m&quot;, MemberDto.class)
                           .getResultList();

public class MemberDto {
	private String username;
    private int age;
    
    public MemberDto(String username, int age) {
    	this.username = username;
        this.age = age;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Query&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입으로 조회&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Query[]&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;타입으로 조회&lt;/li&gt;
&lt;li&gt;&lt;b&gt;new&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;명령어로 조회
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;단순 값을 DTO로 바로 조회&lt;/li&gt;
&lt;li&gt;ex) select new jpa.book.jpql.UserDto(m.username, m.age) from Member m&lt;/li&gt;
&lt;li&gt;패키지 명을 포함한 전체 클래스명을 입력해줘야 한다.&lt;/li&gt;
&lt;li&gt;순서와 타입이 일치하는 생성자가 필요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;프로젝션&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1688393749520&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 엔티티 프로젝션
select m from Member m
select m.team from Member m

-- 임베디드 타입 프로젝션
select m.address form member m

-- 스칼라 타입 프로젝션
select distinct m.username, m.age from Member m&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝션은 SELECT 절에서 &lt;b&gt;조회할 대상을 지정&lt;/b&gt;하는 것을 말한다.&lt;/li&gt;
&lt;li&gt;프로젝션의 대상 : 엔티티, 임베디드 타입, 스칼라 타입(숫자, 문자 등 기본 데이터 타입)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DISTINCT&lt;/b&gt;로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중복을 제거&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;li&gt;엔티티 프로젝션으로 조회된 모든 엔티티는 영속성 컨텍스트로 관리된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;조건식 (CASE 식)&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1688398705799&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/* 기본 CASE 식 */
select
    case when m.age &amp;lt;= 10 then '학생요금'
         when m.age &amp;gt;= 60 then '경로요금'
         else '일반요금'
    end
from Member m

/* 단순 CASE 식 */
select
    case t.name
         when '팀A' then '인센티브110%'
         when '팀B' then '인센티브120%'
         else '인센티브105%'
    end
from Team t&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;페이징&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA는 다음 두 API를 사용해 페이징 처리를 할 수 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 68.6036%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 39.2589%; text-align: center;&quot;&gt;&lt;b&gt;setFirstResult&lt;/b&gt;(int startPosition)&lt;/td&gt;
&lt;td style=&quot;width: 26.4783%; text-align: center;&quot;&gt;조회&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;시작 위치&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 39.2589%; text-align: center;&quot;&gt;&lt;b&gt;setMaxResults&lt;/b&gt;(int maxResult)&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 26.4783%; text-align: center;&quot;&gt;조회 할&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터의 수&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거두절미하고 바로 코드로 알아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1749794181495&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; result = em.createQuery(&quot;select m from Member m order by m.age desc&quot;, Member.class)
                        .setFirstResult(1) // 1번째 부터
                        .setMaxResults(10) // 10개를 가져오겠다
                        .getResultList();

System.out.println(&quot;result.size = &quot; + result.size());
for (Member member : result) {
    System.out.println(&quot;member = &quot; member);
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;order by&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;m.age&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;desc&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 데이터를 나이 내림차순으로 정렬한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;setFirstResult&lt;/b&gt;(1) : 1번째 데이터부터 조회해온다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;setMaxReuslt&lt;/b&gt;(10) : 10개의 데이터를 조회해온다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1749794181496&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;Hibernate: 
    /* select
        m 
    from
        Member m 
    order by
        m.age desc */ select
            ... 생략
        from
            Member member0_ 
        order by
            member0_.age desc limit ? offset ?
            
result.size() = 10
Member{id=51, username='member50', age=50}
Member{id=50, username='member49', age=49}
Member{id=49, username='member48', age=48}
Member{id=48, username='member47', age=47}
Member{id=47, username='member46', age=46}
Member{id=46, username='member45', age=45}
Member{id=45, username='member44', age=44}
Member{id=44, username='member43', age=43}
Member{id=43, username='member42', age=42}
Member{id=42, username='member41', age=41}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력을 보면 나이 내림차순으로 조회하고, 0번째 데이터부터 10개의 데이터를 정상적으로 가져온 것을 확인할 수 있다.&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;쿼리문을 보면 현재 DB를 H2로 설정했기 때문에 H2에 맞는 SQL로 작성되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 다른 DB를 사용하고 싶다면 방언을 변경 해주면 된다.&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;b&gt;  방언 변경방법&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  META-INF/persistance.xml&lt;/p&gt;
&lt;pre id=&quot;code_1749794181500&quot; class=&quot;qml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// H2 설정
&amp;lt;property name=&quot;hibernate.dialect&quot; value=&quot;org.hibernate.dialect.H2Dialect&quot;/&amp;gt;

// Oracle 설정
&amp;lt;property name=&quot;hibernate.dialect&quot; value=&quot;org.hibernate.dialect.Oracle8iDialect&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;dialect 설정만 변경해주면 JPA가 알아서 설정해준 DB에 맞는 SQL을 날려준다.&lt;/li&gt;
&lt;li&gt;ex) Oracle&lt;br /&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;426&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byZDVN/btsOzPwfEkH/ADGeV5nBTRF20NABwuvzK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byZDVN/btsOzPwfEkH/ADGeV5nBTRF20NABwuvzK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byZDVN/btsOzPwfEkH/ADGeV5nBTRF20NABwuvzK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyZDVN%2FbtsOzPwfEkH%2FADGeV5nBTRF20NABwuvzK0%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;300&quot; height=&quot;426&quot; data-origin-width=&quot;572&quot; data-origin-height=&quot;426&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;조인&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;pre id=&quot;code_1749794312717&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;// 내부 조인
SELECT m FROM Member m [INNER] JOIN m.team t

// 외부 조인
SELECT m FROM Member m LEFT [OUTER] JOIN m.team t

// 세타 조인
SELECT count(m) FROM Member m, Team t WHERE m.username=t.name&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;내부 조인 : 조인 대상(team)이 없으면 데이터(member)를 출력하지 않는다.&lt;/li&gt;
&lt;li&gt;외부 조인 : 조인 대상(team)이 없어도 데이터(member)를 출력한다.&lt;/li&gt;
&lt;li&gt;세타 조인 : 막 쿼리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;내부(이너) 조인&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1749794312718&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;Member member = new Member();
member.setUsername(&quot;member1&quot;);
member.setAge(10);

em.persist(member);

Team team = new Team();
team.setName(&quot;teamA&quot;);
team.addMember(member); // 연관관계 편의 메서드 호출

em.persist(team);

em.flush();
em.clear();

String query = &quot;select m from Member m inner join m.team t&quot;;
List&amp;lt;Member&amp;gt; result = em.createQuery(query, Member.class)
                        .getResultList();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1749794312719&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;Hibernate: 
    /* select
        m 
    from
        Member m 
    inner join
        m.team t */ select
            ... 생략 
        from
            Member member0_ 
        inner join
            Team team1_ 
                on member0_.team_id=team1_.team_id limit ?
Hibernate: 
    select
        ... 생략
    from
        Team team0_ 
    where
        team0_.team_id=?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행해보니 사용하지도 않았는데 team을 조회하는 쿼리가 하나 더 나간 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 이유 때문에 @ManyToOne은 항상 Lazy(지연로딩)로 설정해줘야 한다는 주의점이 있다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1749794312720&quot; class=&quot;less&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = &quot;team_id&quot;)
private Team team;&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;inner 키워드는 생략이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1749794312720&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String query = &quot;select m from Member m join m.team t&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;외부 조인&lt;/b&gt;&lt;/h3&gt;
&lt;pre class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String query = &quot;select m from Member m left outer join m.team t&quot;;
List&amp;lt;Member&amp;gt; result = em.createQuery(query, Member.class)
                        .getResultList();&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1749794312721&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;/* select
    m 
from
    Member m 
left join
    m.team t */ select
        ... 생략
    from
        Member member0_ 
    left outer join
        Team team1_ 
            on member0_.team_id=team1_.team_id limit ?&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;left outer join된 것을 확인할 수 있다.&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;outer 키워드는 생략이 가능하다.&lt;/p&gt;
&lt;pre id=&quot;code_1749794312722&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String query = &quot;select m from Member m left join m.team t&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;세터 조인&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1749794312722&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;String query = &quot;select m from Member m, Team t where m.username = t.name&quot;;
List&amp;lt;Member&amp;gt; result = em.createQuery(query, Member.class)
                        .getResultList();&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1749794312722&quot; class=&quot;q&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;/* select
    m 
from
    Member m,
    Team t 
where
    m.username = t.name */ select
        ... 생략
    from
        Member member0_ cross 
    join
        Team team1_ 
    where
        member0_.username=team1_.name&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cross join 된 것을 확인할 수 있다.&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;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;조인 - ON절&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA는 ON절을 활용한 조인을 지원한다.&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(JPA 2.1부터 지원)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;ON절을 이용해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;조인 대상을 필터링&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;li&gt;ON절을 이용해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;연관관계가 없는&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;엔티티를 외부 조인할 수 있다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(하이버네이트 5.1부터 지원)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  조인 대상 필터링&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 회원과 팀을 조인하는데, 팀 이름이 A인 팀만 조인하려는 경우&lt;/p&gt;
&lt;pre id=&quot;code_1749794312724&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;select m, t from Member m left join m.team t on t.name = 'A'&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;ex) 회원의 이름과 팀의 의름이 같은 대상을 외부 조인하려는 경우&lt;/p&gt;
&lt;pre id=&quot;code_1749794312724&quot; class=&quot;sql&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;select m, t from Member m left join Team t on m.username = t.name&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;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;서브 쿼리&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPQL도 SQL처럼 서브 쿼리를 지원한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서브 쿼리는 쿼리 안에서 또 다른 쿼리를 말한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 서브 쿼리를 사용한 예시이다.&lt;/p&gt;
&lt;pre id=&quot;code_1749794393413&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;/* 나이가 평균보다 많은 회원을 조회 */
select m from Member m 
	where m.age &amp;gt; (select avg(m2.age) from Memver m2)&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;메인 쿼리에서는 m을 사용하지만, 서브 쿼리에서는 m2로 따로 정의해서 둘이 전혀 연관이 없도록 작성되어 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 서브 쿼리를 짜야 성능이 잘 나온다.&lt;/p&gt;
&lt;pre id=&quot;code_1749794393414&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;/* 한 건이라도 주문한 고객을 조회 */
select m from Member m
	where (select count(o) from Order o where m = o.member) &amp;gt; o&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 예제에서는 서브 쿼리에서 메인 쿼리에서 사용하는 m을 끌고와 사용하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇다면 성능 문제가 있을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;서브 쿼리 지원 함수&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 61.6278%; height: 86px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 20.2501%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;함수&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1063%; height: 18px; text-align: center;&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;설명&lt;/span&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.2501%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;EXISTS&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1063%; height: 17px; text-align: center;&quot;&gt;서브 쿼리에 결과가 존재하면 참&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.2501%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;ALL&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1063%; height: 17px; text-align: center;&quot;&gt;모두 만족하면 참&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.2501%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;ANY&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SOME&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1063%; height: 17px; text-align: center;&quot;&gt;조건을 하나라도 만족하면 참&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 20.2501%; height: 17px; text-align: center;&quot;&gt;&lt;b&gt;IN&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 39.1063%; height: 17px; text-align: center;&quot;&gt;서브 쿼리의 결과 중 하나라도 같은 것이 있으면 참&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예제를 통해 서브 쿼리 지원 함수 사용법을 알아보자.&lt;/p&gt;
&lt;pre id=&quot;code_1749794393416&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;/* 팀A 소속인 회원 조회 */
select m form Member m
	where EXISTS (select t from m.team t where t.name = 'A')
    
/* 전체 상품 각각의 재고보다 주문량이 많은 주문들 */
select o form Order o
	where o.orderAmount &amp;gt; ALL (select p.stockAmount from Product p)
    
/* 어떤 팀이든 팀에 소속된 회원 */
select m from Member m
	where m.team = ANY (select t from Team t)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JPA 서브 쿼리의 한계점&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA의 서브 쿼리는 SQL의 서브 쿼리와 똑같지만 다음과 같은 한계점이 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA 표준 스펙에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;WHERE&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;HAVING&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;절&lt;/b&gt;에서만 서브 쿼리 사용이 가능하다.&lt;/li&gt;
&lt;li&gt;JPA 구현체중 하이버네이트에서는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SELECT절&lt;/b&gt;에서도 서브 쿼리 사용을 지원한다.&lt;br /&gt;&amp;rarr; 따라서 사용할 구현체의 스펙을 잘 알아보고 사용해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;FROM 절의 서브 쿼리는 현재 JPQL에서 불가능하다.&lt;/b&gt;&lt;br /&gt;&amp;rarr; 조인으로 풀 수 있으면 조인으로 풀어서 해결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1749794393418&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;/* select절에 서브 쿼리
 * 하이버네이트에서만 사용 가능
 */
select (select avg(m1.age) from Member m1) as avgAge 
	from Member m&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1749794393418&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;sql&quot;&gt;&lt;code&gt;/* from절에 서브쿼리
 * JPQL에서 불가능
 */
select mm.username, mm.age 
	from (select m.username, m.age from Member m) as mm&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/Jpa</category>
      <category>getResultList</category>
      <category>getSingleResult</category>
      <category>JPA</category>
      <category>JPQL</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/220</guid>
      <comments>https://jollyn.tistory.com/220#entry220comment</comments>
      <pubDate>Sat, 29 Oct 2022 17:52:47 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] #15 JPA가 지원하는 쿼리 방법 (JPQL, Criteria, QueryDsl)</title>
      <link>https://jollyn.tistory.com/219</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은&amp;nbsp;&lt;a href=&quot;https://www.inflearn.com/course/ORM-JPA-Basic/dashboard&quot;&gt;인프런 - 자바 ORM 표준 JPA 프로그래밍 (기본편)&lt;/a&gt;&amp;nbsp;을 강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p id=&quot;1. JPA가 지원하는 쿼리 방법&quot; data-ke-size=&quot;size16&quot;&gt;JPA는 매우 다양한 쿼리 방법을 지원한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;JPQL&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JPA Criteria&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;QueryDsl&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;네이티브 SQL&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JDBC API 직접 사용, MyBatis, SpringJdbcTemplate 함께 사용&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&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;h2 id=&quot;2. JPQL&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JPQL&lt;/b&gt;&lt;/h2&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;&lt;span&gt;JPA를 사용하면 엔티티 객체를 중심으로 개발해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문제는 검색 쿼리인데, 테이블이 아닌 엔티티 객체를 대상으로 검색하기 때문에 모든 DB 데이터를 객체로 변환해 검색하는 것은 불가능하다. 따라서 검색 조건이 포함된 SQL을 통해 필요한 최소한의 데이터만 DB에서 불러와야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;JPA는 이러한 문제를 위해 &lt;b&gt;JPQL&lt;/b&gt;을&amp;nbsp;제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL을 추상화한 객체 지향 쿼리 언어&lt;/li&gt;
&lt;li&gt;SQL과 문법과 유사 (SELECT, FROM, WHERE, GROUP BY, HAVING, JOIN 지원)&lt;/li&gt;
&lt;li&gt;JPQL로 쿼리를 짜면 SQL로 번역되어 실행된다.&lt;/li&gt;
&lt;li&gt;JPQL vs SQL 차이
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;JPQL :&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;엔티티 객체를 대상&lt;/b&gt;으로 쿼리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;SQL :&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;데이터베이스 테이블을 대상&lt;/b&gt;으로 쿼리&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;즉, JPQL은 테이블이 아닌 객체를 대상으로 검색하는 객체 지향 SQL이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;단점 : 동적 쿼리 짜기가 힘들다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1667022039225&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// JPQL
String jpql = &quot;select m from Member as m where m.username like '%kim'&quot;;
List&amp;lt;Member&amp;gt; result = em.createQuery(jpql, Member.class).getResultList();&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1667022276041&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 실행 된 SQL
select
    m.id as id
    m.age as age,
    m.user_name ans user_name,
    m,team_id as team_id
from
	Member m
where
	m.age&amp;gt;18&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;h2 id=&quot;3. Criteria&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;Criteria&lt;/b&gt;&lt;/h2&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;&lt;span&gt;JPQL의 동적 쿼리 문제의 대안으로 Criteria를 제공한다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;JPA의 공식 기능, JPQL 빌더 역할을 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;장점 : 문자가 아닌&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;자바코드로 JPQL을 작성&lt;/b&gt;할 수 있다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;문법 오류 체크&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;동적 쿼리 용이&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;단점 :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;너무 복잡하고 실용성이 없다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서, 실무에서는 Criteria를 쓰지 않고&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;QueryDSL 사용을 권장&lt;/b&gt;한다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1667022473089&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Criteria 사용 준비
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery&amp;lt;Member&amp;gt; query = cb.createQuery(Member.class);

// 루트 클래스(조회를 시작할 클래스)
Root&amp;lt;Member&amp;gt; m = query.from(Member.class);

// 자바코드로 쿼리 작성
CriteriaQuery&amp;lt;Member&amp;gt; cq = query.select(m).where(cb.equal(m.get(&quot;username&quot;), &quot;kim&quot;));

// 동적 쿼리 추가
String username = &quot;abs&quot;;
if (username != null) {
    cq.where(cb.equal(m.get(&quot;username&quot;), &quot;kim&quot;));
}

List&amp;lt;Member&amp;gt; result = em.createQuery(cq).getResultList();&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;h2 id=&quot;4. QueryDSL&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;QueryDSL&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;a href=&quot;http://querydsl.com/index.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;오픈소스&lt;/a&gt;, JPQL 빌더 역할을 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;장점 : 문자가 아닌 &lt;b&gt;자바코드로 JPQL을 작성&lt;/b&gt;할 수 있다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;컴파일 시점에 문법 오류를 찾을 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;동적 쿼리 작성이 매우 편리&lt;/b&gt;하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;단순하고 쉽다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;실무에서 사용을 적극 권장한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1667022867006&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// JPQL
// select m from Member m where m.age &amp;gt; 18
JPAFactoryQuery query = new JPAQueryFactory(em);
QMember m = QMember.member;

List&amp;lt;Member&amp;gt; list =
	query.selectFrom(m)
    	 .where(m.age.gt(18))
         .orderBy(m.name.desc())
         .fetch();&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;h2 id=&quot;5. 네이티브&amp;nbsp; SQL&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;네이티브&amp;nbsp; SQL&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;JPA가 제공하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;SQL을 직접 사용&lt;/b&gt;하는 기능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;JPQL로 해결할 수 없는&lt;/b&gt; 특정 데이터베이스에 의존적인 기능을 사용할 때 쓴다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;예) 오라클의 CONNECT BY, 특정 DB만 사용하는 SQL 힌트&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1667015985522&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Native SQL
String sql = &quot;select member_id, city, street, zipcode, user_name from Member&quot;;
List&amp;lt;Member&amp;gt; result = em.createNativeQuery(sql,Member.class).getResultList();&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1667015965361&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hibernate: 
    /* dynamic native SQL query */ select
        member_id,
        city,
        street,
        zipcode,
        user_name 
    from
        Member&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;h2 id=&quot;6. JDBC 직접 사용, SpringJdbcTemplate&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JDBC 직접 사용&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;JPA를 사용하면서 JDBC 커넥션을 직접 사용하거나, 스프링 JdbcTemplate, 마이바티스 등을 함께 조합해서 사용할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;단, 영속성 컨텍스트를 적절한 시점에 &lt;b&gt;강제로 플러시&lt;/b&gt;해줘야 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;예) JPA를 우회해서 SQL을 실행하기 직전에 영속성 컨텍스트 수동 플러시&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1688373629332&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Member member = new Member();
member.setUsernae(&quot;이름&quot;);
em.persist(member);

// flush 호출 시점 -&amp;gt; commit, query
em.flush(); // 강제 플러쉬&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/Jpa</category>
      <category>criteria</category>
      <category>JPA</category>
      <category>JPQL</category>
      <category>QueryDSL</category>
      <category>네이티브 SQL</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/219</guid>
      <comments>https://jollyn.tistory.com/219#entry219comment</comments>
      <pubDate>Sat, 29 Oct 2022 15:19:44 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 문자열 치환하기 - replace() &amp;amp; replaceAll() &amp;amp; replaceFirst()</title>
      <link>https://jollyn.tistory.com/217</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅에서는 Java에서 특정 문자열을 원하는 문자열로 치환하는 방법을 소개한다.&lt;br /&gt;1️⃣ replace()&lt;br /&gt;2️⃣ replaceAll()&lt;br /&gt;3️⃣ replaceFirst()&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;1. replace()&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;replace()&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cs1rAz/btrPI8aPRqE/X1gXhCF1g37Zr3FxUk7rL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cs1rAz/btrPI8aPRqE/X1gXhCF1g37Zr3FxUk7rL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cs1rAz/btrPI8aPRqE/X1gXhCF1g37Zr3FxUk7rL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcs1rAz%2FbtrPI8aPRqE%2FX1gXhCF1g37Zr3FxUk7rL0%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;778&quot; height=&quot;148&quot; data-origin-width=&quot;778&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;첫번째 인자값 : 변환하고자 하는 대상이 되는 문자열&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;두번째 인자값 : 변환할 문자 값&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666924514379&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;가나다라마바사&quot;;
str.replace(&quot;나다라&quot;, &quot;아자차&quot;); // 가아자차마바사&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot;나다라&quot;라는 문자를 &quot;아자차&quot;로 치환한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666924598556&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;가가가가가&quot;;
str2.replace(&quot;가&quot;, &quot;나&quot;); // 나나나나나&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&quot;가&quot;라는 문자를 순차적으로 &quot;나&quot;로 치환한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;replaceAll()&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;73&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dQYQG5/btrPIZee1Sj/zTtH5ZRFfxslLHJYLSdVmk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dQYQG5/btrPIZee1Sj/zTtH5ZRFfxslLHJYLSdVmk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dQYQG5/btrPIZee1Sj/zTtH5ZRFfxslLHJYLSdVmk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdQYQG5%2FbtrPIZee1Sj%2FzTtH5ZRFfxslLHJYLSdVmk%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;777&quot; height=&quot;73&quot; data-origin-width=&quot;777&quot; data-origin-height=&quot;73&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;첫번째 인자값 : 변환하고자 하는 대상이 되는 문자열&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;두번째 인자값 : 변환할 문자 값&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;replace()와 동일한 동작을 하지만, &lt;/span&gt;&lt;span&gt;replaceAll()의 인자 타입은 String으로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;background-color: #f6e199; color: #f89009;&quot;&gt;&lt;b&gt;정규표현식(regular expression)을 인자 값으로 사용할 수 있다&lt;/b&gt;&lt;/span&gt;는 차이가 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666924973660&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;124578&quot;;
str.replaceAll(&quot;[369]&quot;, &quot;&quot;); // 124578&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;&quot;[369]&quot;라는 정규표현식은 &quot;3&quot;, &quot;6&quot;, &quot;9&quot;라는 모든 문자를 &quot;&quot;로 치환하겠다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666925289597&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;123456789&quot;;
str.replaceAll(&quot;[^369]&quot;, &quot;&quot;); // 369&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;동일 문자열을 대상으로 replaceAll을 하는데 이번에는 정규표현식에 ^를 추가했다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이는 &quot;3&quot;, &quot;6&quot;, &quot;9&quot;를 제외한 모든 문자를 &quot;&quot;로 치환하겠다는 의미이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;3. replaceFirst()&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;replaceFirst()&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;74&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnFMyR/btrPKZ4MYHf/jKZzsO4uayYFWY88kAhhn1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnFMyR/btrPKZ4MYHf/jKZzsO4uayYFWY88kAhhn1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnFMyR/btrPKZ4MYHf/jKZzsO4uayYFWY88kAhhn1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnFMyR%2FbtrPKZ4MYHf%2FjKZzsO4uayYFWY88kAhhn1%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;775&quot; height=&quot;74&quot; data-origin-width=&quot;775&quot; data-origin-height=&quot;74&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;첫번째 인자값 : 변환하고자 하는 대상이 되는 문자열&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;두번째 인자값 : 변환할 문자 값&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;인자 타입이 String으로 정규표현식 사용이 가능하며 &lt;/span&gt;&lt;span&gt;첫번째로 만난 문자열만 치환하고, 나머지는 치환하지 않는다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666925889975&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;String str = &quot;121314&quot;;
str.replaceFirst(&quot;[1]&quot;, &quot;_&quot;); // _21314&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;첫번째로 만난 &quot;1&quot;만 &quot;_&quot;로 치환하고 이후 값은 치환하지 않음을 알 수 있다.&lt;/span&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;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1666924159645&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Java Platform SE 8&quot; data-og-description=&quot;&quot; data-og-host=&quot;docs.oracle.com&quot; data-og-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/&quot; data-og-url=&quot;https://docs.oracle.com/javase/8/docs/api/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.oracle.com/javase/8/docs/api/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Java Platform SE 8&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.oracle.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>☕ Java/API</category>
      <category>java</category>
      <category>replace</category>
      <category>replaceall</category>
      <category>replaceFirst</category>
      <category>문자열 치환</category>
      <category>자바 문자열 바꾸기</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/217</guid>
      <comments>https://jollyn.tistory.com/217#entry217comment</comments>
      <pubDate>Fri, 28 Oct 2022 12:02:42 +0900</pubDate>
    </item>
    <item>
      <title>아스키 코드표 (ASCII TABLE)</title>
      <link>https://jollyn.tistory.com/216</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock widthContent&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;596&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rIaDk/btrPIXFH7yJ/hZYXkmy3Lsb3DxTK5HADgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rIaDk/btrPIXFH7yJ/hZYXkmy3Lsb3DxTK5HADgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rIaDk/btrPIXFH7yJ/hZYXkmy3Lsb3DxTK5HADgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrIaDk%2FbtrPIXFH7yJ%2FhZYXkmy3Lsb3DxTK5HADgk%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;883&quot; height=&quot;596&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;596&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;</description>
      <category> ️ Programming/Code Guide</category>
      <category>ASCII Table</category>
      <category>아스키 코드</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/216</guid>
      <comments>https://jollyn.tistory.com/216#entry216comment</comments>
      <pubDate>Thu, 27 Oct 2022 14:23:13 +0900</pubDate>
    </item>
    <item>
      <title>[Window] 윈도우 단축키로 마우스 벗어나기</title>
      <link>https://jollyn.tistory.com/215</link>
      <description>&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 style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;단축키&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;b&gt;설명&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;ctrl + w&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;1개씩 창 닫기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;alt + F4&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;실행 중인 창 전체 닫기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;span&gt;alt + Esc&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;연 순서대로 항목을 순환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;window + D&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;모든 창 최소화 / 모든 창 활성화&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;window + E&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;파일 탐색기 창 열기&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;F2&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;폴더, 파일 이름 변경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;window + ctrl + D&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;가상 데스크톱 추가&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  Etc</category>
      <category>단축키</category>
      <category>윈도우</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/215</guid>
      <comments>https://jollyn.tistory.com/215#entry215comment</comments>
      <pubDate>Tue, 25 Oct 2022 21:56:04 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] #14 값 타입</title>
      <link>https://jollyn.tistory.com/214</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은&amp;nbsp;&lt;a href=&quot;https://www.inflearn.com/course/ORM-JPA-Basic/dashboard&quot;&gt;인프런 - 자바 ORM 표준 JPA 프로그래밍 (기본편)&lt;/a&gt;&amp;nbsp;을 강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;JPA의 데이터 타입 종류&lt;/b&gt;&lt;/h2&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;&lt;b&gt;  엔티티 타입&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;@Entity로 정의하는 객체&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;데이터가 변해도 식별자로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;추적 가능&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;ex) 회원 엔티티의 키나 나이 값을 변경해도 식별자로 인식 가능&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;  값 타입&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;식별자가 없고 값만 있어 변경 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;추적 불가능&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;ex) 숫자 10을 20으로 변경하면 완전히 다른 값으로 대체&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;값 타입의 종류
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;기본값 타입&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;임베디드 타입&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;컬렉션 값 타입&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;값 타입&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;기본값 타입&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;ex) String name, int age&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;생명주기를 엔티티에 의존한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;회원 삭제 시 이름, 나이 필드도 함께 삭제&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;값 타입은 공유하면 안된다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;Side Effect : 회원 이름 변경 시 다른 회원의 이름까지 함께 변경되선 안된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;참고로 자바의 기본 타입은 절대 공유되지 않는다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;int, double 같은 기본 타입(primitive type)은 절대 공유되지 않는다. &amp;rarr;&amp;nbsp;기본 타입은 항상 값을 복사&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Integer같은 래퍼 클래스나 String 같은 특수한 클래스는 참조 값으로 공유 가능한 객체이지만 변경 할 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666159789809&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int a = 10;
int b = a; // 값 복사

a = 20;

System.out.println(&quot;a = &quot; + a); // a = 20
System.out.println(&quot;b = &quot; + b); // b = 10&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;임베디드 타입&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;새로운 값 타입을 직접 정의할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;JPA는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;임베디드 타입&lt;/b&gt;(embedded type)이라 하며, &lt;/span&gt;&lt;span&gt;주로 기본 값 타입을 모아서 만들기 때문에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;복합 값 타입&lt;/b&gt;이라고도 한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;임베디드 타입도 int, String과 같은 값 타입이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;3.1. 임베디드 타입 사용법&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;임베디드 타입 사용법&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;@Embeddable&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 값 타입을 정의하는 곳에 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;@Embedded&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 값 타입을 사용하는 곳에 표시&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;기본 생성자가 필수&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;임베디드 타입 사용 전&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666317664630&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Member {
    ...

    private LocalDateTime startDate;
    private LocalDateTime endDate;

    private String street;
    private String zipcode;
    private String city;
}&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;pre id=&quot;code_1666317336678&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Embeddable
public class Period {
    private LocalDateTime startDate;
    private LocalDateTime endDate;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666317321068&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Embeddable
public class Address {
    private String street;
    private String zipcode;
    private String city;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666317359910&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    ...

    @Embedded
    private Period period;

    @Embedded
    private Address address;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;3.2. 임베디드 타입 장점&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;임베디드 타입 장점&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;재사용이 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;높은 응집도&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Period.isWork()처럼 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;임베디드 타입을 포함한 모든 값 타입은, 값 타입을 소유한 엔티티 생명주기를 의존하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;3.3. 임베디드 타입과 테이블 매핑&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;임베디드 타입과 테이블 매핑&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;임베디드 타입은 엔티티의 값일 뿐이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;임베디드 타입을 사용하기 전과 후에&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;매핑하는 테이블은 같다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;임베디드 타입을 사용하면 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능해진다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;잘 설계한 ORM 어플리케이션은 매핑한 테이블의 수보다 클래스의 수가 더 많다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;497&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bT02hN/btrPaNDS59G/SNKiIXrKPToA41excSsxY0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bT02hN/btrPaNDS59G/SNKiIXrKPToA41excSsxY0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bT02hN/btrPaNDS59G/SNKiIXrKPToA41excSsxY0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbT02hN%2FbtrPaNDS59G%2FSNKiIXrKPToA41excSsxY0%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;450&quot; height=&quot;362&quot; data-origin-width=&quot;617&quot; data-origin-height=&quot;497&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 id=&quot;3.4. 같은 임베디드 타입 사용하기 : @AttributeOverride&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;같은 임베디드 타입 사용하기 : @AttributeOverride&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;한 엔티티에서 다음과 같이 같은 값 타입을 사용하면 어떻게 될까?&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666318692253&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    ...

    @Embedded
    private Address homeAddress;

    @Embedded
    private Address workAddress;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666319131576&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Embeddable
public class Address {
    private String street;
    private String zipcode;
    private String city;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;@Embedded를 사용하는 경우 객체 이름이 아닌 해당 객체 안에 작성된 필드 이름(street, zipcode, city)을 컬럼 명으로 사용하기 때문에 homeAddress와 workAddress의 컬럼 명이 중복되어 다음과 같은 오류가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1666318729820&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: hellojpa.Member column: city (should be mapped with insert=&quot;false&quot; update=&quot;false&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;이러한 중복을 해결하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;@AttrebuteOverride를 사용해 객체 안의 컬럼 명을 재정의&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;해줘야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666319225792&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
    ...

    @Embedded
    @AttributeOverride(name = &quot;street&quot;, column = @Column(name = &quot;home_street&quot;))
    @AttributeOverride(name = &quot;zipcode&quot;, column = @Column(name = &quot;home_zipcode&quot;))
    @AttributeOverride(name = &quot;city&quot;, column = @Column(name = &quot;home_city&quot;))
    private Address homeAddress;

    @Embedded
    @AttributeOverride(name = &quot;street&quot;, column = @Column(name = &quot;work_street&quot;))
    @AttributeOverride(name = &quot;zipcode&quot;, column = @Column(name = &quot;work_zipcode&quot;))
    @AttributeOverride(name = &quot;city&quot;, column = @Column(name = &quot;work_city&quot;))
    private Address workAddress;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;44&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Kjgrj/btrPaj4ApNF/62YKeOioxG9pP1v18J5nW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Kjgrj/btrPaj4ApNF/62YKeOioxG9pP1v18J5nW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Kjgrj/btrPaj4ApNF/62YKeOioxG9pP1v18J5nW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKjgrj%2FbtrPaj4ApNF%2F62YKeOioxG9pP1v18J5nW1%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;800&quot; height=&quot;44&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;44&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 DB에 재정의 해준 컬럼명으로 저장된다.&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;h2 id=&quot;4. 값 타입의 공유 참조&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;값 타입의 공유 참조&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 id=&quot;4.1. 공유 참조의 위험성&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;공유 참조의 위험성&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;임베디드 타입 같은 값 타입을 여러 엔티티에서 공유하면 위험하다.&lt;/li&gt;
&lt;li&gt;부수 작용(Side Effect) 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666323428949&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Address address = new Address(&quot;street&quot;, &quot;zipcode&quot;, &quot;city&quot;);

Member member1 = new Member();
member1.setUsername(&quot;member1&quot;);
member1.setAddress(address); // 같은 값 타입 공유
em.persist(member1);

Member member2 = new Member();
member1.setUsername(&quot;member2&quot;);
member2.setAddress(address); // 같은 값 타입 공유
em.persist(member2);

member1.getAddress().setCity(&quot;newCity&quot;); // member2의 city까지 변경되는 side effect 발생&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;262&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/py7jA/btrO9AMQk28/STwwqSdtaFgKFspfURZsAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/py7jA/btrO9AMQk28/STwwqSdtaFgKFspfURZsAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/py7jA/btrO9AMQk28/STwwqSdtaFgKFspfURZsAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fpy7jA%2FbtrO9AMQk28%2FSTwwqSdtaFgKFspfURZsAK%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;250&quot; height=&quot;85&quot; data-origin-width=&quot;262&quot; data-origin-height=&quot;89&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;member1와 member2가 같은 임베디드 타입(Address)를 공유하고 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;member1의 city값만 변경하려고 했지만, member2의 city값도 함께 변경되는 문제가 발생한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;4.2. 해결 : 값 타입 복사&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;해결 : 값 타입 복사&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;문제를 해결 하기 위해서는 &lt;b&gt;같은 값 타입을 공유하지 않고, 복사해서 사용&lt;/b&gt;해야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666324383497&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Address address = new Address(&quot;street&quot;, &quot;zipcode&quot;, &quot;city&quot;);

Member member1 = new Member();
member1.setUsername(&quot;member1&quot;);
member1.setAddress(address);
em.persist(member1);

Address copyAddress = new Address(address.getStreet(), address.getZipcode(), address.getCity());

Member member2 = new Member();
member1.setUsername(&quot;member2&quot;);
member2.setAddress(copyAddress);
em.persist(member2);

member1.getAddress().setCity(&quot;newCity&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;89&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yjbkw/btrPcUW3SRi/TCa4J7THOw32dWKyh5JKOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yjbkw/btrPcUW3SRi/TCa4J7THOw32dWKyh5JKOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yjbkw/btrPcUW3SRi/TCa4J7THOw32dWKyh5JKOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fyjbkw%2FbtrPcUW3SRi%2FTCa4J7THOw32dWKyh5JKOk%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;550&quot; height=&quot;86&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;89&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;4.3. 객체 타입의 한계&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;객체 타입의 한계&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;항상 값을 복사해서 사용하면 공유 참조로 인해 발생하는 부작용을 피할 수는 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;문제는 임베디드 타입처럼 직접 정의한 값 타입은 자바의 기본 타입이 아니라 객체 타입인 것이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;자바 기본 타입에 값을 대입하면 값을 복사한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;객체 타입은 참조 값을 직접 대입하는 것을 막을 방법이 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서 객체의 공유 참조는 피할 수 없다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;자바 기본 타입&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666325285183&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int a = 10;
int b = a; // 기본 타입은 값을 복사
b = 4;

// a = 10
// b = 4&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;pre id=&quot;code_1666325330774&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Address a = new Address(&quot;old&quot;);
Address b = a; // 객체 타입은 참조를 복사
b.setCity(&quot;new&quot;);

// a.getCity() -&amp;gt; new
// b.getCity() -&amp;gt; new&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;4.4. 해결 : 불변 객체 설계&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;해결 : 불변 객체 설계&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;객체 타입을 수정할 수 없게 만들어&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;부작용을 원천 차단&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;값 타입은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;불변 객체(immutable object)로 설계&lt;/b&gt;해야 한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;불변 객체란 생성 시점 이후 절대 값을 변경할 수 없는 객체를 말한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;생성자로만 값을 설정하고, 수정자(Setter)를 만들지 않으면 된다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;참고 : Integer, String은 자바가 제공하는 대표적인 불변 객체이다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;5. 값 타입의 비교&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;값 타입의 비교&lt;/b&gt;&lt;/h2&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;&lt;span&gt;값 타입은 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666663462910&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// primitive type 비교
int a = 10;
int b = 10;

System.out.println(&quot;a == b : &quot; + (a == b)); // true&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666663475303&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 임베디드 타입 비교
Address address1 = new Address(&quot;street&quot;, &quot;zipcode&quot;, &quot;city&quot;);
Address address2 = new Address(&quot;street&quot;, &quot;zipcode&quot;, &quot;city&quot;);

System.out.println(&quot;address1 == address2 : &quot; + (address1 == address2)); // false&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;하지만, 임베디드 타입의 == 비교는 false가 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;== 비교는 인스턴스의 참조 값을 비교하기 때문이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그럼 값 타입은 어떻게 비교해야 할까?&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;동일성&lt;/b&gt;(identity) 비교 : 인스턴스의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;참조 값&lt;/b&gt;을 비교,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;==&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;동등성&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;비교 : 인스턴스의&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;값&lt;/b&gt;을 비교,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;equals()&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;값 타입은&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c1bef9; color: #5733b1;&quot;&gt;a.equals(b)를 사용해서 동등성 비교를 해야한다.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;값 타입의 equals() 메소드를 적절하게 재정의해서 사용하자 (주로 모든 필드 사용)&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666663960217&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Address address = (Address) o;
    return Objects.equals(street, address.street) &amp;amp;&amp;amp; 
    Objects.equals(zipcode, address.zipcode) &amp;amp;&amp;amp; 
    Objects.equals(city, address.city);
}

@Override
public int hashCode() {
    return Objects.hash(street, zipcode, city);&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666663994321&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Address address1 = new Address(&quot;street&quot;, &quot;zipcode&quot;, &quot;city&quot;);
Address address2 = new Address(&quot;street&quot;, &quot;zipcode&quot;, &quot;city&quot;);

System.out.println(&quot;address1 equals address2 : &quot; + (address1.equals(address2))); // true&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;equals() 메소드를 재정의 후 비교 시 인스턴스가 달라도 그 안에 값이 같을 경우 true가 나온다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;6. 값 타입 컬렉션&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;값 타입 컬렉션&lt;/b&gt;&lt;/h2&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;&lt;span&gt;값 타입을 하나 이상 저정할 때 컬렉션에 넣어서 사용할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;그럼 값 타입 컬렉션을 데이터베이스에 넣으려면 어떻게 해야할까?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기본적으로 데이터베이스는 내부적으로 컬렉션을 담을 수 있는 구조가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 컬렉션을 저장하기 위한&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;별도의 테이블을 만들어야 한다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;149&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWIIwj/btrPuJgYEs1/z9eDCC0RkkjhZHAAtHPdv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWIIwj/btrPuJgYEs1/z9eDCC0RkkjhZHAAtHPdv1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWIIwj/btrPuJgYEs1/z9eDCC0RkkjhZHAAtHPdv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWIIwj%2FbtrPuJgYEs1%2Fz9eDCC0RkkjhZHAAtHPdv1%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;250&quot; height=&quot;104&quot; data-origin-width=&quot;359&quot; data-origin-height=&quot;149&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;279&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh75DQ/btrPwAw2NS1/hGy8oa4h3O6A57OaqOO27k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh75DQ/btrPwAw2NS1/hGy8oa4h3O6A57OaqOO27k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh75DQ/btrPwAw2NS1/hGy8oa4h3O6A57OaqOO27k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh75DQ%2FbtrPwAw2NS1%2FhGy8oa4h3O6A57OaqOO27k%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;450&quot; height=&quot;215&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;279&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;6.1. 값 타입 컬렉션 매핑 :&amp;nbsp;@ElementCollection, @CollectionTable&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;값 타입 컬렉션 매핑 :&amp;nbsp;@ElementCollection, @CollectionTable&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값 타입 컬렉션은 @ElementCollection, @CollectionTable을 사용해 매핑한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666666982221&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@ElementCollection
@CollectionTable(name = &quot;favorite_foods&quot;, joinColumns =
@JoinColumn(name = &quot;member_id &quot;)
)
@Column(name = &quot;food_name&quot;)
private Set&amp;lt;String&amp;gt; favoriteFoods = new HashSet&amp;lt;&amp;gt;();

@ElementCollection
@CollectionTable(name = &quot;address_history&quot;, joinColumns =
@JoinColumn(name = &quot;member_id&quot;)
)
private List&amp;lt;Address&amp;gt; addressHistory = new ArrayList&amp;lt;&amp;gt;();&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;6.2. 값 타입 컬렉션 사용&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;값 타입 컬렉션 사용&lt;/b&gt;&lt;/h3&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;span&gt;값 타입 컬렉션의 생명주기는 엔티티에 의존한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;따라서 값 타입 컬렉션은 따로 persist 해 줄 필요가 없으며, 엔티티가 변하면 자동으로 업데이트 된다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666676449314&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Member member = new Member();
member.setUsername(&quot;member&quot;);
member.setAddress(new Address(&quot;street&quot;, &quot;zipcode&quot;, &quot;city&quot;));

member.getFavoriteFoods().add(&quot;치킨&quot;);
member.getFavoriteFoods().add(&quot;피자&quot;);

em.persist(member);&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;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;값 타입 컬렉션도&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;지연로딩&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #373c46;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;전략을 사용한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666668007692&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Member findMember = em.find(Member.class, member.getId());

Set&amp;lt;String&amp;gt; favoriteFoods = findMember.getFavoriteFoods(); 
System.out.println(favoriteFoods); // 실제 사용 시점에 select 쿼리 실행&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666676583531&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hibernate: 
    select
        member0_.member_id as member_i1_6_0_,
        member0_.city as city2_6_0_,
        member0_.street as street3_6_0_,
        member0_.zipcode as zipcode4_6_0_,
        member0_.user_name as user_nam5_6_0_,
    from
        Member member0_ 
    where
        member0_.member_id=?
        
Hibernate: 
    select
        favoritefo0_.member_id as member_i1_4_0_,
        favoritefo0_.food_name as food_nam2_4_0_ 
    from
        favorite_foods favoritefo0_ 
    where
        favoritefo0_.member_id=?
[치킨, 피자]&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;pre id=&quot;code_1666676913697&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Member findMember = em.find(Member.class, member.getId());

findMember.getFavoriteFoods().remove(&quot;치킨&quot;);
findMember.getFavoriteFoods().add(&quot;양념치킨&quot;);

findMember.getAddressHistory().remove(new Address(&quot;street1&quot;, &quot;zipcode1&quot;, &quot;city1&quot;));
findMember.getAddressHistory().add(new Address(&quot;newStreet&quot;, &quot;newZipcode&quot;, &quot;newCity&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값 타입 컬렉션은 생명주기를 엔티티에 의존한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값 타입 컬렉션에 변경이 있을 경우 기존 데이터만 삭제하고 신규 데이터를 추가하는 것이 아닌 값 타입 컬렉션 데이터 전체가 갈아끼워진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값 타입 컬렉션은 &lt;b&gt;영속성 전이(Cascade)&lt;/b&gt;와 &lt;b&gt;고아 객체 제거 기능&lt;/b&gt;을 필수로 가진다고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;6.3. 제약사항&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;제약사항&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;값 타입은 엔티티와 다르게&lt;b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;식별자 개념이 없다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;따라서 변경하면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;추적이 어렵다.&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;값 타입 컬렉션에 변경 사항이 발생하면, 주인 엔티티와 연관된 모든 데이터를 삭제하고, 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;값 타입 컬렉션을 매핑하는 테이블은 모든 컬럼을 묶어서 기본 키를 구성해야 한다. &lt;/span&gt;&lt;span&gt;&amp;rarr;&lt;b&gt;&amp;nbsp;null 입력 X&lt;/b&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;중복 저장 X&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;이러한 이유로 실무에선 사용하지 않는 것을 추천한다.&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;실무에서는 상황에 따라 값 타입 컬렉션 대신&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c1bef9; color: #5733b1;&quot;&gt;일대다 관계를 고려&lt;/span&gt;&lt;/b&gt;한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;일대다 관계를 위한 엔티티를 만들고, 여기에서 값 타입을 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;영속성 전이 + 고아 객체 제거를 사용해서 값 타입 컬렉션처럼 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;즉, 값 타입을 엔티티로 승급해서 사용하는 방법을 많이 사용한다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1666677458195&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Member {
   ...

    @OneToMany(cascade = ALL, orphanRemoval = true)
    @JoinColumn(name = &quot;member_id&quot;)
    private List&amp;lt;AddressEntity&amp;gt; addressHistory = new ArrayList&amp;lt;&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666677431643&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class AddressEntity {
    @Id
    @GeneratedValue
    private Long id;

    private Address address;
}&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;h2 id=&quot;7. 정리&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h2&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;&lt;span&gt;&lt;b&gt;✅ 엔티티 타입의 특징&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;식별자가 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;생명 주기 관리할 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;공유 가능하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;b&gt;✅ 값 타입의 특징&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;식별자가 없다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;생명 주기를 엔티티에 의존하다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;공유하지 않는 것이 안전하다 (복사해서 사용)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;불변 객체로 만드는 것이 안전하다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;값 타입은 정말 값 타입이라 판단될 때만 사용하는 것이며, &lt;/span&gt;&lt;span&gt;엔티티와 값 타입을 혼동해서 엔티티를 값 타입으로 만들면 안된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;식별자가 필요하고 지속해서 값을 추적, 변경해야 한다면 그것은 값 타입이 아닌 엔티티로 만들어야 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;span&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://galid1.tistory.com/592&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;JPA - Entity의 가독성을 높이자(@Embedded, @Embeddable, @AttributeOverride 사용법)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/Jpa</category>
      <category>@AttributeOverride</category>
      <category>@Embeddable</category>
      <category>@Embedded</category>
      <category>JPA</category>
      <category>JPA 데이터타입</category>
      <category>값타입</category>
      <category>기본 값타입</category>
      <category>임베디드 타입</category>
      <category>컬렉션 값타입</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/214</guid>
      <comments>https://jollyn.tistory.com/214#entry214comment</comments>
      <pubDate>Wed, 19 Oct 2022 15:44:10 +0900</pubDate>
    </item>
    <item>
      <title>[JPA] #13 영속성 전이(CASECADE)와 고아 객체</title>
      <link>https://jollyn.tistory.com/213</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;본 포스팅은&amp;nbsp;&lt;a href=&quot;https://www.inflearn.com/course/ORM-JPA-Basic/dashboard&quot;&gt;인프런 - 자바 ORM 표준 JPA 프로그래밍 (기본편)&lt;/a&gt;&amp;nbsp;을 강의를 바탕으로 공부하고 정리한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;1. 영속성 전이 (CASECADE)&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;영속성 전이 (CASECADE)&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;특정 엔티티를 영속 상태로 만들 때 그와 연관된 엔티티도 함께 영속 상태로 만드는 기능이다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;예) 부모 엔티티 저장시 자식 엔티티도 함께 저장&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;영속성 전이는 연관관계를 매핑하는 것과 아무 관련 없다. &lt;/span&gt;&lt;span&gt;부모 엔티티를 영속화(persist)할 때, 자식 엔티티도 함께 영속화하는 편리함을 제공해주는 기능일 뿐이다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;부모 엔티티와 자식 엔티티를 저장하는 간단한 예제를 통해 확인해 보자.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;  영속성 전이 적용 전&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666070735600&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Parent {
    ...
    
    @OneToMany(mappedBy = &quot;parent&quot;)
    private List&amp;lt;Child&amp;gt; childList = new ArrayList&amp;lt;&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666070754116&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Child {
    ...

    @ManyToOne
    @JoinColumn(name = &quot;parent_id&quot;)
    private Parent parent;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666070880055&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Parent parent = new Parent();
Child child1 = new Child();
Child child2 = new Child();

parent.addChild(child1);
parent.addChild(child2);

em.persist(parent); // 부모 저장
em.persist(child1); // 자식1 저장
em.persist(child2); // 자식2 저장&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;엔티티를 저장하기 위해 연관된 모든 엔티티가 영속상태여야 하므로, 부모 엔티티와 연관된 자식 엔티티를 각각 영속상태로 만들어줘야 한다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이때 CASECADE 옵션을 사용해 이러한 번거로움을 덜 수 있다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span&gt;  영속성 전이 적용 후&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666071037236&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Parent {
    ...

    @OneToMany(mappedBy = &quot;parent&quot;, cascade = CascadeType.ALL)
    private List&amp;lt;Child&amp;gt; childList = new ArrayList&amp;lt;&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666071049491&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Child child1 = new Child();
Child child2 = new Child();

Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);

em.persist(parent); // 영속성 전이를 적용해 parent를 저장할 때 child도 함께 저장&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;CasecadeType.ALL을 지정하면 부모 엔티티를 영속화할 때 &lt;b&gt;자식 엔티티도 함께 영속화&lt;/b&gt;시켜준다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 id=&quot;1.1. CASECADE 종류&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CASECADE 종류&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;ALL : 모두 적용&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;PERSIST : 영속&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;b&gt;REMOVE : 삭제&lt;/b&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;MERGE : 병합&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;REFRESH : 새로고침&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;DETACH :&amp;nbsp; 분리&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;CASECADE 주의사항&lt;/b&gt;&lt;/h3&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 다음과 같은 경우에 영속성 전이를 사용하자.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Parent와 Child의 라이프 사이클이 동일할 때&lt;/li&gt;
&lt;li&gt;특정 엔티티가 개인 소유 할 때(Child가 하나의 Parent에 완전히 종속적)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;2. 고아 객체 (ORPHAN)&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;고아 객체 (ORPHAN)&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span&gt;JPA에서 부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 고아 객체 제거 기능이다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;orphanRemoval = true&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;고아 객체도 간단한 부모, 자식 엔티티를 삭제하는 예제를 통해 확인해보도록 하자.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1666072305930&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
public class Parent {
    ...

    @OneToMany(mappedBy = &quot;parent&quot;, cascade = CascadeType.ALL, orphanRemoval = true)
    private List&amp;lt;Child&amp;gt; childList = new ArrayList&amp;lt;&amp;gt;();
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666072311950&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Child child1 = new Child();
Child child2 = new Child();

Parent parent = new Parent();
parent.addChild(child1);
parent.addChild(child2);

em.persist(parent);

em.flush();
em.clear();

Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildList().remove(0); // 자식 참조 제거&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1666072359499&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Hibernate: 
    /* delete hellojpa.Child */ delete 
        from
            Child 
        where
            child_id=?&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;span&gt;단,&amp;nbsp;&lt;b&gt;참조하는 객체가 여러 개라면 문제가 발생&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;할 수 있기 때문에 @OneToOne, @OneToMany에서만 사용이 가능하다.&lt;/span&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;만약 부모를 제거하면 자식은 고아가 된다. &lt;br /&gt;따라서 orpahRemoval 기능을 활성화 하면, 부모를 제거할 때 자식도 함께 제거가 된다. &lt;br /&gt;이것은 CasecadeType.REMOVE를 설정한 것과 동일하게 동작한다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;3. 영속성 전이 + 고아 객체, 생명주기&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;영속성 전이 + 고아 객체, 생명주기&lt;/b&gt;&lt;/h2&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;cacade = CascadeType.ALL + orphanRemovel = true&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;스스로 생명주기를 관리하는 엔티티는 em.persist()로 영속화하며, em.remove()로 제거한다.&lt;/li&gt;
&lt;li&gt;두 옵션을 모두 활성화 하면 &lt;b&gt;부모 엔티티를 통해서 자식의 생명주기를 관리&lt;/b&gt;할 수 있다.&lt;/li&gt;
&lt;li&gt;도메인 주도 설계(DDD)의 Aggregate Root개념을 구현할 때 유용하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>  RoadMap/Jpa</category>
      <category>casecade</category>
      <category>CaseCadeType.ALL</category>
      <category>JPA</category>
      <category>orphanRemovel</category>
      <category>고아객체</category>
      <category>영속성 전이</category>
      <author>an2z</author>
      <guid isPermaLink="true">https://jollyn.tistory.com/213</guid>
      <comments>https://jollyn.tistory.com/213#entry213comment</comments>
      <pubDate>Tue, 18 Oct 2022 15:08:57 +0900</pubDate>
    </item>
  </channel>
</rss>