<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Dev99.log</title>
        <link>https://velog.io/</link>
        <description>구구구구구!</description>
        <lastBuildDate>Fri, 05 Dec 2025 12:20:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Dev99.log</title>
            <url>https://velog.velcdn.com/images/new_guy/profile/98c943fa-5dc0-4ba3-a2d9-996cb0d2c5b0/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Dev99.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/new_guy" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[3. 기타 지식]]></title>
            <link>https://velog.io/@new_guy/3.-%EA%B8%B0%ED%83%80-%EC%A7%80%EC%8B%9D</link>
            <guid>https://velog.io/@new_guy/3.-%EA%B8%B0%ED%83%80-%EC%A7%80%EC%8B%9D</guid>
            <pubDate>Fri, 05 Dec 2025 12:20:00 GMT</pubDate>
            <description><![CDATA[<h1 id="1-데몬-vs-백그라운드">1. 데몬 vs. 백그라운드</h1>
<p>둘다 백그라운드에서 사용되는 것은 맞으나, 차이가 있다.</p>
<h2 id="데몬">데몬</h2>
<ul>
<li>init이 부모 프로세스, 쉘에 종속적이지 않다.</li>
<li>TTY에 종속적이지 않다.</li>
</ul>
<h2 id="백그라운드-프로세스">백그라운드 프로세스</h2>
<ul>
<li>쉘에 종속적이다.</li>
<li>TTY에 종속적이다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[0. init 시스템이란?]]></title>
            <link>https://velog.io/@new_guy/0.-init-%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@new_guy/0.-init-%EC%8B%9C%EC%8A%A4%ED%85%9C%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Fri, 05 Dec 2025 12:09:45 GMT</pubDate>
            <description><![CDATA[<h1 id="1-init-시스템이란">1. init 시스템이란?</h1>
<p>: 커널 부팅이후, 실행되는 첫 프로세스.( 커널이 직접 실행시키는 유일한 프로세스. )
init은 부모 프로세스가 없고, init을 제외한 나머지 모든 프로세스의 조상.</p>
<h2 id="init의-역할">init의 역할.</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/1d792e4a-c932-41dd-99f2-8b0d6b1e2535/image.png" alt=""></p>
<p>( <a href="https://www.kernelpanic.kr/16">https://www.kernelpanic.kr/16</a> )</p>
<ul>
<li>여기서, 백그라운드 프로세스는 initrc 하위 기록된 서비스들을 의미한다( 직속 부모 = init ).
&amp;로 실행되는 프로세스는 부모가 쉘이다. 따라서 두개의 의미는 완전히 다르다.</li>
</ul>
<h3 id="이후-실행-과정">이후 실행 과정.</h3>
<pre><code class="language-txt">init실행 -&gt; getty( get tty) : 터미널 준비 -&gt; 사용자 로그인 -&gt; 사용자 쉘 접근.

PID 1: init(systemd)
 └─ getty (콘솔 제공) ,stdin/stdout 설정.
     └─ login (인증)
         └─ bash (쉘)

1개의 getty -&gt; 1개의 login -&gt; 다수의 쉘 가능.</code></pre>
<h1 id="2-대표적인-init-프로세스--systemd">2. 대표적인 init 프로세스 = Systemd.</h1>
<ol>
<li><p>적극적인 병렬처리 기능 ( 그래서 service를 등록할 때, 순서가 중요한 것이었다. )</p>
</li>
<li><p>소켓과 D-Bus 활성화</p>
</li>
<li><p>on-demand 데몬 실행</p>
</li>
<li><p>프로세스 트래킹</p>
</li>
<li><p>파일시스템 마운트 및 마운트 관리</p>
</li>
<li><p>의존성 기반의 서비스 컨트롤 로직</p>
</li>
<li><p>SysV init 스크립트에 대한 호환성</p>
</li>
<li><p>로깅 데몬 제공</p>
</li>
<li><p>기본적인 시스템 설정 컨트롤 유틸리티 제공</p>
</li>
<li><p>다양한 네트워크 관련 데몬</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/new_guy/post/3fec317e-81ba-45b8-acca-14f2999838c2/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/92370664-f8ac-4485-9332-ffe8ad9e6f14/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/8ef51f9d-1b0d-4aa3-b232-c38fbeaf553f/image.png" alt="">
( <a href="https://www.kernelpanic.kr/16">https://www.kernelpanic.kr/16</a> )</p>
<ul>
<li>Systemd에서 사용하는 방식 = 이벤트 방식임( 병렬 실행 ).
( 다른 방식들은 비용이 매우 비싸다. )</li>
<li>ini 방식으로 파일 작성.</li>
</ul>
<h1 id="3-service-관리">3. Service 관리.</h1>
<p>: 실행된 Service는 항상 Init만 부모 프로세스로 가진다. 따라서, init이 서비스의 생명주기 및 모니터링을 관리.</p>
<p>참고로, systemctl이라는 유틸을 통해서 서비스의 상태를 모니터링 및 관리</p>
<h2 id="systemctl-참고-자료">systemctl 참고 자료.</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/e67ff904-67cb-4a82-a58d-a82861a32884/image.png" alt="">
( <a href="https://www.kernelpanic.kr/16">https://www.kernelpanic.kr/16</a> )</p>
<h2 id="systemd가-관리하는-서비스">Systemd가 관리하는 서비스.</h2>
<ul>
<li><p>systemd-network: 네트워크 관리 서비스로, DHCP(동작 IP 할당) 작업, 와이파이 연결, 네트워크 브릿징 등의 다양한 기능을 제공한다.</p>
</li>
<li><p>systemd-udevd: 등록된 디바이스가 연결되면 동적으로 디바이스 노드를 만든다. 예를 들어서 usb를 연결하면 특정 폴더에 마운트 되도록 할 수 있다.</p>
</li>
<li><p>systemd-journald: 시스템 서비스와 커널 로그를 저장한다. 아래 2.5 유틸리티 제공 절에서 보다 상세히 다루었다.</p>
</li>
<li><p>systemd-timesyncd: 시스템 시간을 네트워크 시간과 동일하게 맞춰주는 서비스이다.
번외) dbus: 리눅스 IPC를 돕는 버스 서비스이다. systemd만의 고유한 서비스가 아님에도, freedesktop.org에서 systemd의 장점으로 넣었길래 일단 추가했다. (이유를 안다면 부디 알려주기를 바란다.) dbus는 오늘날 리눅스에서 가장 핵심적인 시스템 서비스 중 하나이기 때문에, 조만간 dbus를 주제로 포스트를 올릴 예정이다.</p>
</li>
</ul>
<h2 id="systemd의-유틸리티">Systemd의 유틸리티</h2>
<ol>
<li>joutnalctl
: 시스템 서비스 및 커널의 로그 확인.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/new_guy/post/556afe7c-c19e-4983-8cdf-4379c32ffc39/image.png" alt=""></p>
<ol start="2">
<li><p>networkctl
: systemd-network 서비스를 사용하는 경우, networkctl을 이용해서 서비스를 모니터링</p>
</li>
<li><p>기타 api</p>
</li>
</ol>
<ul>
<li><p>sd-bus: dbus를 사용하기 위한 api를 제공한다. gdbus와 더불어 가장 많이 사용되는 dbus api 중 하나이다.</p>
</li>
<li><p>sd-event: C언어로 eventloop를 관리하는 것을 돕는 api이다. C로 간단한 event 기반 프로그래밍을 할 때 유용하다.</p>
</li>
<li><p>sd-journal: 시스템 로그 출력을 위한 api이다.</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[1. 부팅 시, 항상 실행되는 프로세스 만들기]]></title>
            <link>https://velog.io/@new_guy/1.-%EB%B6%80%ED%8C%85-%EC%8B%9C-%ED%95%AD%EC%83%81-%EC%8B%A4%ED%96%89%EB%90%98%EB%8A%94-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@new_guy/1.-%EB%B6%80%ED%8C%85-%EC%8B%9C-%ED%95%AD%EC%83%81-%EC%8B%A4%ED%96%89%EB%90%98%EB%8A%94-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Tue, 25 Nov 2025 03:24:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/new_guy/post/862395d8-e6b0-4a31-b3b3-26d99df69206/image.png" alt=""></p>
<p>그리고, systemd는 .service 파일을 백그라운드처럼 실행( 사실은 포그라운드 ) 및 관리를 한다.
또한, 터미널과 분리가 되어 있는 상태이다. 따라서 사용자에 의존하지 않는다.
&amp;로 실행한 프로세스는 특정 사용자 세션(셸)의 child이다.</p>
<p>여기서, 셸이란 사용자와 커널을 이어주는 인터페이스를 의미</p>
<h2 id="-service-파일-작성-방법-">[ Service 파일 작성 방법 ]</h2>
<pre><code class="language-bash">[Unit]
Description=Portforwarding to aws-rds daemon.
After=network.target

[Service]
Type=simple
User=tarto123z
WorkingDirectory=/home/tarto123z
ExecStart=/home/tarto123z/aws_portforwarding.sh
Restart=on-failure

[Install]
WantedBy=multi-user.target</code></pre>
<ul>
<li><p>Description : service 파일 설명</p>
</li>
<li><p>After : network.target 유닛 실행 이후, 현재 service 파일 실행.
( 포트포워딩은 network 연결이 끝이 난 후에 해야 하므로 )</p>
</li>
<li><p>User : 이 service를 실행할 사용자.
( aws 포트포워딩 시, tarto123z라는 User를 사용해야 함. )</p>
</li>
<li><p>WorkingDirectory : serivce가 실행된 디렉토리.
( 이 설정을 하지 않으면, aws profile 관련 오류가 발생함. )</p>
</li>
<li><p>ExecStart : service를 실행할 때, 명령어.</p>
</li>
<li><p>WantedBy : multi-user.target 유닛이 실행될 때, 이 service도 함께 실행.</p>
</li>
</ul>
<h2 id="-사용한-명령어-">[ 사용한 명령어 ]</h2>
<ul>
<li>ss -tulnp | grep 3306 : ss -tulnp의 포트 결과값을 grep을 통해서 3306이 있는지 확인한다.</li>
<li>만약 root 사용자가 아닌, user가 .service 파일을 생성한 경우
w !sudo tee % -&gt; :q!로 파일 저장 및 종료.</li>
<li>aws ... &amp;를 하지 않은 이유 : .sh에서 쉘 스크립트가 aws 포트포워딩 작업보다 먼저 끝이 나서 service가 종료됨.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[HashTable vs. HashMap vs. ConcurrentHashMap]]></title>
            <link>https://velog.io/@new_guy/HashTable-vs.-HashMap-vs.-ConcurrentHashMap-tav90c95</link>
            <guid>https://velog.io/@new_guy/HashTable-vs.-HashMap-vs.-ConcurrentHashMap-tav90c95</guid>
            <pubDate>Sun, 21 Sep 2025 07:51:48 GMT</pubDate>
            <description><![CDATA[<h1 id="1-java의-hashtable">1. Java의 HashTable</h1>
<h2 id="hashtable이란">&lt; HashTable이란? &gt;</h2>
<p>{Key, Value}로 데이터를 저장하는 자료구조.
내부적으로 배열(버킷)을 사용하므로, 빠른 조회가 가능하다.
( 각각의 Key 값에 해시함수 적용 -&gt; 고유한 index 생성 -&gt; 이 index로 검색. )</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/048b32f6-9ac7-4e8d-93e6-8f43ffd97844/image.png" alt=""></p>
<p>해싱 구조로 데이터를 저장하면 1번의 해시 함수 사용으로 O(1)</p>
<h3 id="해시-함수-종류">해시 함수 종류</h3>
<p>: 고유 인덱스를 어떻게 계산을 하느냐가 성능에 중요하다.</p>
<ol>
<li><p>Division Method
: 나눗셈을 이용하는 방법( 주소 = 입력값 % 데이터 테이블의 크기, 2의 제곱수 )</p>
</li>
<li><p>Digit Folding
: 각 Key의 문자열을 ASCII 코드로 변경 -&gt; 값을 합한 데이터를 테이블 내의 주소로 사용.</p>
</li>
<li><p>Multiplication Method</p>
</li>
<li><p>Univieral Hashing.</p>
</li>
</ol>
<h3 id="해시-충돌">해시 충돌</h3>
<p>: 두 변수의 해시값이 동일할 경우 충돌 -&gt; 어떻게 동일한 해시값을 관리하나?</p>
<ol>
<li>분리 연결법
<img src="https://velog.velcdn.com/images/new_guy/post/15dadde0-ad97-40cf-a25a-dd79cc370543/image.png" alt="">
동일한 버킷의 데이터에 대해 자료구조를 활용해 메모리 추가 -&gt; 다음 데이터의 주소를 저장<h4 id="java8의-hash테이블은-self-balancing-binary-search-tree를-이용해-chaining-방식을-구현">Java8의 Hash테이블은 Self-Balancing Binary Search Tree를 이용해 Chaining 방식을 구현.</h4>
</li>
</ol>
<h3 id="그러나-데이터의-수가-많아지면-동일한-버킷에-다량의-데이터가-chaining---조회성능-저하">그러나, 데이터의 수가 많아지면 동일한 버킷에 다량의 데이터가 chaining -&gt; 조회성능 저하.</h3>
<ol start="2">
<li>개방 주소법
<img src="https://velog.velcdn.com/images/new_guy/post/dbe550ad-1c46-47cb-a86d-a3632346ff2f/image.png" alt="">
비어있는 해시 테이블의 공간을 활용하는 방법.
Hash Table 재정리 해주는 작업이 필요.</li>
</ol>
<h2 id="hashtable의-시간복잡도">HashTable의 시간복잡도</h2>
<p>일반적으로 O(1)이나 해시 충돌이 발생할 경우, O(N)임.( 끝까지 조회를 해야하므로. )
테이블이 꽉 차있는 경우라면, 테이블 확장 -&gt; 심각한 성능 저하.
해시 테이블에서 자주 사용하게 되는 데이터 개시 -&gt; 캐시 hit에 의해서 성능 향상.</p>
<h2 id="java의-hashtable-vs-hashmap">Java의 HashTable vs HashMap</h2>
<p>: 동기화 지원 여부의 차이가 있다.</p>
<h2 id="2-java의-hashtable-주요-특징">2. Java의 HashTable 주요 특징</h2>
<ul>
<li><p>동기화(Synchronized): Hashtable의 모든 메서드는 synchronized 키워드를 사용하여 동기화된다. 따라서 여러 스레드가 동시에 Hashtable에 접근하더라도 일관성이 보장된다. (아래 목차에서 메서드를 살펴보면 이해할 수 있다.)</p>
</li>
<li><p>동시성(Concurrency): Hashtable은 여러 스레드에서 동시에 읽기 및 쓰기를 안전하게 수행할 수 있다. 하지만, 모든 메서드가 동기화되어 있기 때문에 많은 스레드가 동시에 Hashtable을 사용하면 성능 저하가 발생할 수 있다.</p>
</li>
</ul>
<ul>
<li>빠른 검색: 해시 테이블을 사용하여 데이터를 저장하므로, 일반적으로 O(1)의 시간 복잡도로 데이터를 검색할 수 있다.</li>
</ul>
<h2 id="잘-사용되지-않는-이유">잘 사용되지 않는 이유</h2>
<ul>
<li><p>성능 문제: 앞서 설명한 것처럼, 모든 메서드가 synchronized로 동기화되어 있는 Hashtable은 동시성 제어를 위해 단일 락을 사용하므로, 성능이 저하될 수 있다. 높은 동시성이 요구되는 환경에서는 ConcurrentHashMap이 훨씬 더 나은 성능을 제공하기 때문에, Hashtable이 자주 사용되지 않는다. (사실 쓰는 걸 못 봤다.)</p>
</li>
<li><p>유연성 부족: Hashtable은 null 키와 값을 허용하지 않는다. 반면 HashMap은 null 키와 값을 허용하며, 일반적인 사용에서 더 유연하다.</p>
</li>
<li><p>Java Collections Framework의 발전: Java 2가 도입되면서 Collections Framework가 추가되었고, HashMap, TreeMap, ConcurrentHashMap과 같은 더 나은 성능과 유연성을 제공하는 컬렉션 클래스들이 등장했다. 이로 인해 Hashtable의 사용은 점차 줄어들었다고 한다.</p>
</li>
<li><p>더 나은 대체재 존재: HashMap과 ConcurrentHashMap은 Hashtable의 기능을 대체할 수 있는 더 나은 선택지다. 따라서, 새로운 프로젝트나 코드에서는 거의 사용되지 않는다.</p>
</li>
</ul>
<h2 id="hashmap의-작동-원리">HashMap의 작동 원리</h2>
<p>하나의 버킷에 들어간 노드 수가 8개가 초과할 경우 자료 구조를 트리(레드 블랙 트리)로의 변경을 시도한다.
하지만 트리로 변경하지 전, HashMap의 전체 크기를 검사하여 64보다 작은 경우 먼저 해시 버킷 배열을 확장(resize)한다
( 버킷이 작으면 잦은 충돌을 발생시키기 때문이다. )</p>
<p>그리고 특정 임계값이 넘어가면, resize를 발동한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[인덱스의 개념과 장단점]]></title>
            <link>https://velog.io/@new_guy/%EC%9D%B8%EB%8D%B1%EC%8A%A4%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%9E%A5%EB%8B%A8%EC%A0%90</link>
            <guid>https://velog.io/@new_guy/%EC%9D%B8%EB%8D%B1%EC%8A%A4%EC%9D%98-%EA%B0%9C%EB%85%90%EA%B3%BC-%EC%9E%A5%EB%8B%A8%EC%A0%90</guid>
            <pubDate>Wed, 17 Sep 2025 02:28:19 GMT</pubDate>
            <description><![CDATA[<h1 id="인덱스">인덱스</h1>
<ul>
<li><p>장점 
: 빠른 조회 ( 목차 )</p>
</li>
<li><p>단점 
: DB 내에서 추가적인 공간이 필요, 초기 생성 시간이 오래 걸림, SELECT가 아닌 INSERT, DELETE,UPDATE가 자주 일어나면 오히려 성능이 저하.</p>
</li>
</ul>
<h2 id="인덱스의-종류">인덱스의 종류</h2>
<ol>
<li>클러스터형 인덱스
: 인덱스 = DB (PK), 영어 사전으로 비유.</li>
</ol>
<p>클러스터형 인덱스는 PK 순으로 자동 정렬이 됨.</p>
<ol start="2">
<li>보조 인덱스
: 인덱스 -&gt; DB (FK)</li>
</ol>
<p>PK와 다르게 데이터 레코드 자체를 정렬하는 것이 아니라, 인덱스를 정렬.</p>
<h1 id="인덱스의-내부-작동-원리">인덱스의 내부 작동 원리.</h1>
<p>인덱스는 B 트리( Balanced Tree )로 정렬을 한다.</p>
<ul>
<li><p>전체 테이블 검색
: 리프 노드 전부를 검색. ( 최악의 성능 )</p>
</li>
<li><p>균형 트리의 페이지 분할
: SELECT는 빠른데, 나머지는 느림.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/9940263c-28d4-4423-bddb-089176f4aad8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/0a93d114-a7b8-4d8e-a0ce-9814562dda40/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/12e02bd0-40fd-4ebe-ab9e-b5d78c513e77/image.png" alt=""></p>
<p>INSERT가 많아질수록 페이지 분할이 많아져 성능상 더 느려진다.</p>
<h3 id="-클러스터형-인덱스-">[ 클러스터형 인덱스 ]</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/8cdfa8c1-d6eb-4f3f-b7c3-d46471b68ff2/image.png" alt=""></p>
<h3 id="-보조-인덱스-">[ 보조 인덱스 ]</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/e0652402-9d4a-42b0-b946-bff7364a98f1/image.png" alt=""></p>
<p>데이터는 입력 순서로 들어가고, 인덱스만 정렬이 된다.</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/0cf0148b-f939-4c33-8be5-6880e061bac3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/245457e0-1bfc-4869-8534-77cd28ecd622/image.png" alt="">
ㄴ</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[가상의 테이블 : 뷰]]></title>
            <link>https://velog.io/@new_guy/%EA%B0%80%EC%83%81%EC%9D%98-%ED%85%8C%EC%9D%B4%EB%B8%94-%EB%B7%B0</link>
            <guid>https://velog.io/@new_guy/%EA%B0%80%EC%83%81%EC%9D%98-%ED%85%8C%EC%9D%B4%EB%B8%94-%EB%B7%B0</guid>
            <pubDate>Wed, 17 Sep 2025 01:49:03 GMT</pubDate>
            <description><![CDATA[<h1 id="뷰">뷰</h1>
<p>: 바로가기 아이콘과 동일함. 뷰는 실체가 없는데, 이를 통해서 테이블의 SELECT 쿼리가 실행.</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/24e69ed2-9065-4b82-ba96-1c19e2cae42a/image.png" alt=""></p>
<ul>
<li><p>보안에 도움이 된다.( 중요한 정보를 제외하고 출력이 가능하다. )</p>
</li>
<li><p>복잡한 SQL을 단순하게 만들 수 있다.</p>
</li>
</ul>
<h2 id="뷰의-실제-작동">뷰의 실제 작동.</h2>
<p>: 뷰를 통해서 데이터 넣는 것은 추천하지 않음.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL 테이블 제약조건]]></title>
            <link>https://velog.io/@new_guy/SQL-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%A0%9C%EC%95%BD%EC%A1%B0%EA%B1%B4</link>
            <guid>https://velog.io/@new_guy/SQL-%ED%85%8C%EC%9D%B4%EB%B8%94-%EC%A0%9C%EC%95%BD%EC%A1%B0%EA%B1%B4</guid>
            <pubDate>Wed, 17 Sep 2025 01:41:11 GMT</pubDate>
            <description><![CDATA[<h2 id="1-기본-키-primary-key">1. 기본 키 (PRIMARY KEY)</h2>
<p>: 중복을 허용하지 않고, NOT NULL. 클러스터형 인덱스로 생성. ( 클러스터형 인덱스 )</p>
<p>기본 키는 1개만 가능하다.</p>
<h2 id="2-외래-키">2. 외래 키</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/ae5eef1e-73ce-4fbe-933e-c4d54f4c022b/image.png" alt=""></p>
<p>: 부모테이블의 PK(UNIQUE KEY)가 반드시 있어야, 자식테이블의 FK가 있다.</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/2c2548eb-c64f-4411-aa33-b983051ffa8a/image.png" alt=""></p>
<p>: 위와 같은 설정을 하면, 부모 키를 수정하면 자동으로 자식도 함께 수정이 된다.</p>
<h2 id="3-고유-키unique-제약조건">3. 고유 키(UNIQUE) 제약조건</h2>
<p>: 중복은 허용하지 않지만, NULL은 허용한다.
( PK와 비슷하지만, 다름. )</p>
<h2 id="4-체크check">4. 체크(CHECK)</h2>
<p>: 입력되는 데이터를 점검하는 기능을 한다.</p>
<h2 id="5-기본값-정의">5. 기본값 정의</h2>
<p>: DEFAULT 값을 정의한다.</p>
<h2 id="6-null-허용not-null">6. NULL 허용.(NOT NULL)</h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[SQL 프로그래밍]]></title>
            <link>https://velog.io/@new_guy/SQL-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</link>
            <guid>https://velog.io/@new_guy/SQL-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D</guid>
            <pubDate>Mon, 15 Sep 2025 10:39:58 GMT</pubDate>
            <description><![CDATA[<pre><code class="language-sql">DELIMITER $$
CREATE PROCEDURE STORED_PROCEDURE()
BEGIN
    ...
END $$
DELIMITER ;

CALL STORED_PROCEDURE();</code></pre>
<h3 id="if">IF</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/69735066-189b-4a6b-b36f-892d8ca88c34/image.png" alt=""></p>
<pre><code class="language-sql">IF &lt;조건식&gt; THEN
    SQL 문장들
END IF;</code></pre>
<h3 id="if--else-문">IF ~ ELSE 문</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/ca0cc14a-3fd4-45cb-8ba1-e1697390544a/image.png" alt=""></p>
<p>스토어드 프로시저 내부에 선언을 할 때는 DECLARE를 쓰고, 외부에 선언을 할 때는 @VAR 형식으로 사용을 한다.</p>
<p>그리고 SET var = some_Value ( 초기화 및 할당 )</p>
<h3 id="case-문">CASE 문</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/5b133043-1f41-466f-a999-7cd6ed73c710/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/67b03877-f6fd-4e93-bfa4-0d6b48e4dba9/image.png" alt=""></p>
<h3 id="while">WHILE</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/a4214cf2-5cbf-4196-9377-debd251af07c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/84e61bae-c2a3-4635-9f03-f956b3152227/image.png" alt=""></p>
<h3 id="iterate-leave">ITERATE, LEAVE</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/d5836946-6fdb-49f1-9253-c20cf7baf0e0/image.png" alt=""></p>
<h3 id="동적-sql">동적 SQL</h3>
<h4 id="prepare와-execute">PREPARE와 EXECUTE</h4>
<p>PREPARE로 준비하고, EXECUTE로 실행을 한다.
그리고 DEALLOCATE로 해제를 한다.</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/c6119e19-4714-4594-b334-1696d0327b3e/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[도커 면접 대비용]]></title>
            <link>https://velog.io/@new_guy/%EB%8F%84%EC%BB%A4-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84%EC%9A%A9</link>
            <guid>https://velog.io/@new_guy/%EB%8F%84%EC%BB%A4-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84%EC%9A%A9</guid>
            <pubDate>Sat, 06 Sep 2025 08:42:46 GMT</pubDate>
            <description><![CDATA[<ol>
<li><p>Docker란 무엇인가?
: 애플리케이션을 컨테이너라는 독립된 환경에 패키징하고 실행할 수 있는 플랫폼. OS 수준의 가상화를 기반으로 하며, VM보다 경량이고 실행 속도가 빠른다.</p>
</li>
<li><p>VM과 Docker의 차이?
: VM은 HOST OS상 가상화를 이용해 다수의 GUEST OS를 만든다. 반면에 Docker는 HOST OS의 커널을 공유하며 리소스 소비가 적고 실행이 빠르다.</p>
</li>
<li><p>Docker 이미지와 컨테이너 차이
: 이미지는 읽기 전용 실행 파일이고, 컨테이너는 이미지 기반으로 실행된 인스턴스(프로세스)</p>
</li>
<li><p>Dockerfile이란?
: 도커 이미지를 만들기 위한 설정 파일로, baseImage, file copy, package install, 실행 명령 등을 정의.</p>
</li>
<li><p>COPY와 ADD 차이
: COPY는 단순한 파일 복사
ADD는 복사 + URL 다운로드 + 압축 해제.
( 일반적으로 COPY를 권장 )</p>
</li>
<li><p>Docker compose란?
: 여러 컨테이너를 하나의 파일에서 정의하고 한 번에 실행할 수 있게 해주는 도구.</p>
</li>
<li><p>Docker Hub와 Registry의 차이
: Docker Hub는 도커의 공식 이미지 저장소,
Registry는 자체적으로 운영 가능한 저장소.</p>
</li>
<li><p>ENTRYPOINT와 CMD의 차이
: ENTRYPOINT는 실행 명령,
CMD는 기본 인자값.</p>
</li>
<li><p>컨테이너 간 통신 방법
: 기본 bridge 네트워크로 통신 가능하며,
Compose에서는 서비스명 기반 DNS로 연결.</p>
</li>
<li><p>컨테이너 상태 확인 명령어
: docker ps (-a), docker inspect</p>
</li>
<li><p>로그 확인 명령어
: docker logs &lt; 컨테이너명 &gt;</p>
</li>
<li><p>컨테이너 접속 방법
: docker exec -it &lt; 컨테이너명 &gt; /bin/bash</p>
</li>
<li><p>Volume과 Bind Mount의 차이
: Volume은 도커가 관리( 운영 )
Bind Mount는 Host 디렉토리와 직접 연결.</p>
</li>
<li><p>멀티스테이지 빌드란?
: 빌드 단계와 실행 단계를 분리 -&gt; 이미지 크기를 줄일 수 있다.</p>
</li>
<li><p>포트 포워딩은 어떻게?
: docker run -dit -p 80:8080 이미지명
( -d(daemon) -it(interact) )</p>
</li>
<li><p>파일 공유 방법은?
:docker run -v /host/path:/container/paht 이미지명</p>
</li>
<li><p>보안 이슈 방법
: 민감 정보를 이미지에 포함하지 않고, 최소 권한 사용자로 실행함.</p>
</li>
<li><p>재시작 정책 설정
: --restart=always 또는 --restart=on-failure</p>
</li>
<li><p>이미지 경량화 방법
: 멀티스테이지, Dockerfile 상 불필요한 파일 제거 및 캐시 최소화, 하나의 RUN 명령어로 레이어 최소화</p>
</li>
<li><p>포트 오픈 여부 확인 방법
: 컨테이너 내부 -&gt; netstat, curl, telnet
컨테이너 외부 -&gt; docker port, nmap, ss</p>
</li>
<li><p>Docker 컨테이너의 격리 수준 정도?
: Host OS, 컨테이너 간 서로 독립적으로 구분.
( 하지만, 커널은 공유 )</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래밍 공통/기타]]></title>
            <link>https://velog.io/@new_guy/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B3%B5%ED%86%B5%EA%B8%B0%ED%83%80</link>
            <guid>https://velog.io/@new_guy/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%EA%B3%B5%ED%86%B5%EA%B8%B0%ED%83%80</guid>
            <pubDate>Thu, 07 Aug 2025 02:33:46 GMT</pubDate>
            <description><![CDATA[<h1 id="restful-api">Restful API</h1>
<ul>
<li><p>HTTP통신을 Rest설계 규칙을 지켜서 개발한 API</p>
</li>
<li><p>Rest설계 규칙은 URI는 정보의 자원만 표현해야 하며, 자원의 상태와 행위는 HTTP Method에 명시.</p>
</li>
</ul>
<h3 id="행위---메소드-종류">행위 - 메소드 종류</h3>
<ul>
<li><p>GET : 정보 요청</p>
</li>
<li><p>POST : 정보 입력( body )</p>
</li>
<li><p>PUT : 전체 데이터 수정</p>
</li>
<li><p>PATCH : 일부 데이터 수정</p>
</li>
<li><p>DELETE : 정보 삭제.</p>
</li>
</ul>
<p>이는 분산 시스템 간의 통신을 효율적이고 표준화된 방식으로 설계하기 위해 고안된 기술.</p>
<h1 id="프레임워크와-라이브러리-차이">프레임워크와 라이브러리 차이</h1>
<p>라이브러리는 주도권을 개발자가, 프레임워크는 주도권을 프레임워크에 위임(제어의 역전).</p>
<h1 id="call-by-value와-call-by-reference의-차이">Call By Value와 Call By Reference의 차이</h1>
<ul>
<li><p>Call By Value(값에 의한 호출) = 인자로 받은 값을 복사하여 처리.
: 값을 복하기 때문에 원래 값을 보존할 수 있지만, 복사로 인해서 메모리 사용량이 증가</p>
</li>
<li><p>Call By Reference(참조에 의한 호출) = 인자로 받은 값의 주소를 참조하여 직접 저장해 값에 영향을 줌.
: 직접 참조를 하기에 원래의 값이 영향을 받는다.</p>
</li>
</ul>
<p>JAVA는 &quot;Call By Value&quot; 이다.</p>
<h1 id="cors">CORS</h1>
<p>도메인이 서로 다른 2개의 사이트가 데이터를 주고 받을 때 발생하는 문제.
따라서 다른 서버의 리소스를 불러오기 위해서는, Response 헤더에 그 출처에서 CORS에 대한 내용을 추가해야 한다.</p>
<ul>
<li><p>Access-Control-Allow-Orgin : 요청을 보내는 페이지의 출처 [ *, 도메인 ]</p>
</li>
<li><p>Access-Control-Allow-Methods : 요청을 허용하는 메소드. Default : GET, POST</p>
</li>
<li><p>Access-Control-Max-Age : 클라이언트에서 preflight 요청 (서버의 응답 가능여부에 대한 확인) 결과를 저장할 시간</p>
</li>
<li><p>Access-Control-Allow-Headers : 요청을 허용하는 헤더</p>
</li>
</ul>
<h1 id="동적-쿼리">동적 쿼리</h1>
<p>실행시에 특정 조건이나 상황에 따라 쿼리 문장이 변경되어 실행되는 쿼리문.
( where절에 조건이 달라질 때 사용 )</p>
<h1 id="csrf">CSRF</h1>
<p>사이트 간 요청 위조 : 사용자가 이미 로그인된 상태에서, 특정 웹사이트에 요청을 보내도록 속임.( 공격자가 의도한대로 사용자가 행동하게 한다. )</p>
<ol>
<li>사용자의 요청에 referrer를 확인하여 도메인 일치여부 파악.</li>
</ol>
<h1 id="base64-인코딩">Base64 인코딩</h1>
<p>binary 데이터 -&gt; text로 인코딩</p>
<h3 id="장점">장점</h3>
<ul>
<li><p>binary 데이터를 텍스트로 변환.</p>
</li>
<li><p>데이터 유실 없이 안전한 인코딩.</p>
</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li><p>원래 데이터보다 33% 증가</p>
</li>
<li><p>단순 변환이므로 보안성이 없음.</p>
</li>
</ul>
<h3 id="과정--binary---8bit로-번들링---ascii-코드로-변환-디코딩은-역방향">과정 : binary -&gt; 8bit로 번들링 -&gt; ASCII 코드로 변환. 디코딩은 역방향.</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java에서 비동기 요청 처리방법]]></title>
            <link>https://velog.io/@new_guy/Java%EC%97%90%EC%84%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%9A%94%EC%B2%AD-%EC%B2%98%EB%A6%AC%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@new_guy/Java%EC%97%90%EC%84%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%9A%94%EC%B2%AD-%EC%B2%98%EB%A6%AC%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Sun, 15 Jun 2025 08:09:39 GMT</pubDate>
            <description><![CDATA[<h1 id="1-비동기-요청-처리방법">1. 비동기 요청 처리방법</h1>
<p><img src="https://velog.velcdn.com/images/new_guy/post/88bd7947-fbe9-4af7-b220-6a0554a1118e/image.png" alt="">
( <a href="https://adjh54.tistory.com/544">https://adjh54.tistory.com/544</a> )</p>
<p>이러한 비동기 작업은 별도의 스레드에서 실행이 되며, 메인 스레드가 블로킹되지 않도록 합니다. 
즉, 메인 스레드가 특정 작업을 기다리느라 멈추지 않고, 다른 작업을 계속해서 수행할 수 있습니다.</p>
<h2 id="12-그렇다면-자바에선-어떤-스레드가-비동기-요청-처리할까">1.2 그렇다면, 자바에선 어떤 스레드가 비동기 요청 처리할까?</h2>
<h2 id="a-forkjoinpool병렬-처리---큰-작업을-잘게-쪼개어">a. ForkJoinPool(병렬 처리) -&gt; 큰 작업을 잘게 쪼개어.</h2>
<pre><code class="language-java">    // ComputableFuture를 통해서 비동기 요청으로 처리할 수 있다.
    // 또한 아래 출력값은 별도의 스레드임을 알 수 있다.
    // ForkJoinPool의 commonPool()을 사용해 작업을 실행할 쓰레드를 쓰레드 풀로부터 얻어 실행시킨다.
    // 만약 원하는 쓰레드 풀을 사용하려면, ExecutorService를 파라미터로 넘겨주면 된다.
    CompletableFuture&lt;Void&gt; future = CompletableFuture.runAsync(() -&gt; {
        System.out.println(&quot;Thread: &quot; + Thread.currentThread().getName());
    });

    future.get();
    System.out.println(&quot;Thread: &quot; + Thread.currentThread().getName());</code></pre>
<ul>
<li>fork 호출시</li>
</ul>
<ol>
<li><p>작업을 작은 서브 task로 분할 한 후, 분할된 작업은 ForkJoinPool의 스레드 데큐에 추가가 된다.</p>
</li>
<li><p>각 스레드는 자신의 deque에서 작업을 가져와 처리한다.</p>
</li>
</ol>
<ul>
<li>join 호출시</li>
</ul>
<ol>
<li>이전에 fork한 다른 작업의 완료를 기다림.
마지막에 병합.</li>
</ol>
<ul>
<li>작업 훔치기
스레드에 작업이 없으면 다른 작업의 데큐에서 테스크를 훔쳐 실행을 한다.( 리소스 사용률 극대화 )</li>
</ul>
<blockquote>
<p>자바에선 Stream의 ParrallelStream이 ForkJoin을 사용한다.</p>
</blockquote>
<p>ForkJoinPool.commonPool()은 JVM 당 1개만 존재하며, 전반의 병렬 스트림 연산에 사용.
( 스트림의 원소들은 작은 테스크로 분할되어 ForkJoinTask로 감싸진 후, ForkJoinPool에 제출되어 처리.)</p>
<p>개수는 물리적 CPU 코어 수, 또는 논리적 프로세스 수(하이퍼스레딩이 활성화된 경우)</p>
<p>공용 풀에 다른 작업을 위해 최소한 하나의 스레드를 남견다.</p>
<h2 id="단-작업이-완료될-때까지-공용-풀로-반환이-되지-않는다">단, 작업이 완료될 때까지 공용 풀로 반환이 되지 않는다.</h2>
<h2 id="b-excutorservice">b. ExcutorService</h2>
<ul>
<li><p>Excutor : 쓰레드를 미리 만들어두고 재사용하기 위한 쓰레드 풀의 인터페이스
( 등록된 작업을 실행하는 책임 = 전달받는 작업(Runnable)만 실행)</p>
</li>
<li><p>ExcutorService : 작업 등록을 위한 인터페이스
Excutor를 상속받아서 작업 등록 뿐만 아니라 실행을 위한 책임도 있다.
( ThreadPool의 기본은 ExcutorService를 구현)</p>
</li>
<li><p>ScheduledExecutorService : 특정 시간 이후에 또는 주기적으로 작업을 실행시키는 메소드, 스케줄링</p>
</li>
<li><p>Executors : 위를 만들어주는 팩토리 클래스.</p>
</li>
</ul>
<h1 id="스레드-풀">스레드 풀</h1>
<p><img src="https://velog.velcdn.com/images/new_guy/post/177adb31-3d68-4c1b-b124-64bf000e30b5/image.png" alt=""></p>
<ol>
<li>애플리케이션(Application)</li>
</ol>
<ul>
<li>비동기 처리의 하나의 새로운 작업(New Task)을 발생시켰고, 이를 작업 큐로 제출(Submit)을 하게 됩니다.</li>
</ul>
<ol start="2">
<li>작업 큐(Task Queue)</li>
</ol>
<ul>
<li>전달받은 작업(Task)은 큐에서 스레드의 사용이 가능할 때까지 보관을 합니다.</li>
<li>또한 큐에서는 FIFO 형태로 먼저 들어온 데이터가 먼저 처리하는 구조를 가지며 순차적으로 데이터가 쌓이고 들어온 순서대로 처리가 수행됩니다.</li>
</ul>
<ol start="3">
<li>스레드(Thread)</li>
</ol>
<ul>
<li>스레드 풀에 있는 스레드 중 하나가 사용이 가능해지면, 작업 큐에서 작업을 가져와서 실행을 하게 됩니다.</li>
<li>작업이 완료되면, 스레드는 유휴 상태가 되며, 작업이 발생하면 다시 큐에서 다음 작업을 가져와서 처리를 합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lock]]></title>
            <link>https://velog.io/@new_guy/Lock</link>
            <guid>https://velog.io/@new_guy/Lock</guid>
            <pubDate>Mon, 09 Jun 2025 02:50:47 GMT</pubDate>
            <description><![CDATA[<h1 id="1-레코드-락--중요-">1. 레코드 락 ( 중요! )</h1>
<p><img src="https://velog.velcdn.com/images/new_guy/post/2afa9893-7828-4e0d-8a5a-42446f8ef800/image.png" alt="">
( <a href="https://20201111start.tistory.com/entry/MySQL-%EB%9D%BDLock-%EC%9D%B4%EB%9E%80">https://20201111start.tistory.com/entry/MySQL-%EB%9D%BDLock-%EC%9D%B4%EB%9E%80</a> )</p>
<p>first_name=&#39;DK&#39;가 250건 조회 + 해당 컬럼에만 &quot;보조 인덱스&quot; 적용</p>
<p>-&gt; 250건 다 락 걸림.</p>
<h4 id="테이블의-레코드가-아니라-인덱스의-레코드를-잠근다">테이블의 레코드가 아니라!, 인덱스의 레코드를 잠근다.</h4>
<h4 id="만약-적당한-인덱스가-없다면-모든-테이블의-레코드에-락을-걸고-테이블을-풀스캔-하면서-작업을-처리---동시성-매우-심각">만약 적당한 인덱스가 없다면 모든 테이블의 레코드에 락을 걸고, 테이블을 풀스캔 하면서 작업을 처리 -&gt; 동시성 매우 심각.</h4>
<p>(단, SELECT를 제외한 UPDATE, DELETE에서만 유효)</p>
<h1 id="2-갭-락">2. 갭 락</h1>
<p>(오직 인덱스 기반의 범위 검색에서만 발생)</p>
<pre><code class="language-sql">-- 배타락 or 공유락에서 발생.
SELECT * FROM member WHERE last_name LIKE &#39;J%&#39; FOR UPDATE;
</code></pre>
<ul>
<li><p>last_name에 인덱스가 있다면</p>
</li>
<li><p>J%로 시작하는 레코드 범위 전체에 Next-Key Lock</p>
</li>
<li><p>&#39;I&#39;와 &#39;J&#39; 사이의 갭</p>
</li>
<li><p>&#39;J&#39; ~ &#39;K&#39; 사이의 갭</p>
</li>
<li><p>결과적으로 J로 시작하는 레코드뿐 아니라,
J~K 사이에 새로운 레코드가 삽입되지 못하게 막음 (갭락)</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>last_name</th>
<th>잠금 종류</th>
</tr>
</thead>
<tbody><tr>
<td>&#39;Isaac&#39;</td>
<td>갭락 (I~J 사이)</td>
</tr>
<tr>
<td>&#39;Jack&#39;</td>
<td>Next-Key Lock</td>
</tr>
<tr>
<td>&#39;James&#39;</td>
<td>Next-Key Lock</td>
</tr>
<tr>
<td>&#39;Jason&#39;</td>
<td>Next-Key Lock</td>
</tr>
<tr>
<td>&#39;Kevin&#39;</td>
<td>갭락 (J~K 사이)</td>
</tr>
</tbody></table>
<h4 id="--팬텀리드-방지">-&gt; 팬텀리드 방지</h4>
<h1 id="3-넥스트-키-락">3. 넥스트 키 락</h1>
<p>( 레코드 락 + 갭 락 )</p>
<p>갭 락이나 넥스트 키 락은 바이너리 로그에 기록되는 쿼리가 리플리카 서버에서 실행될 때 소스 서버에서 만들어낸 결과와 동일한 결과를 만들어내도록 보장해주는 것이 주목적이라고 한다. </p>
<p>그런데 의외로 넥스트 키 락과 갭 락으로 인해 데드락이 발생하거나 다른 트랜잭션이 기다리는 일이 자주 발생하므로, 
바이너리 로그 포맷을 ROW 형태로 바꿔서 넥스트 키 락이나 갭 락을 줄이는 것이 좋다고 한다.</p>
<h1 id="4-자동-증가-락">4. 자동 증가 락</h1>
<p>( 자동 증가하는 숫자값을 채번하기 위해 AUTO_INCREMENT 컬럼 속성을 사용, 주로 대체키에 사용 )</p>
<ul>
<li><p>여러 레코드가 동시에 INSERT 되더라도 &quot;중복되지 않고 순차적으로 증가하는 일련번호를 제공하기 위해서 내부적으로 테이블 수준의 잠금인 자동 증가 락을 사용&quot;</p>
</li>
<li><p>새로운 레코드를 저장하는 쿼리에서만 사용.</p>
</li>
<li><p>자동 증가 락은 테이블에 1개만 존재 -&gt; 한 쿼리에서 락을 획득해서 채번중이면, 다음 쿼리는 락을 대기</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[DB 면접 대비용]]></title>
            <link>https://velog.io/@new_guy/DB-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84%EC%9A%A9</link>
            <guid>https://velog.io/@new_guy/DB-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84%EC%9A%A9</guid>
            <pubDate>Wed, 28 May 2025 04:15:32 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터베이스의-특징">데이터베이스의 특징</h1>
<ul>
<li><p>여러 사람의 공유 목적 -&gt; 체계화된 통합, 관리</p>
</li>
<li><p>이전 파일시스템을 사용했으나, 데이터 종속성, 중복성 무결성의 문제 발생.</p>
</li>
</ul>
<ol>
<li><p>실시간 접근성
비정형적인 조회에 대하여 실시간 처리에 의한 응답이 가능</p>
</li>
<li><p>지속적인 변화
DB는 동적으로 새로운 데이터 삽입, 삭제, 갱신으로 항상 최신의 데이터를 유지</p>
</li>
<li><p>동시 공용
서로 다른 목적을 가진 여러 사용자들을 위한 것이므로, 다수의 사용자가 동시에 같은 내용의 데이터를 이용</p>
</li>
<li><p>내용에 의한 참조
DB의 데이터를 참조 시, 데이터 레코드의 주소나 위치가 아닌 사용자가 요구하는 데이터 내용을 찾는다.</p>
</li>
</ol>
<h4 id="정형-vs-반정형-vs-비정형">정형 vs. 반정형 vs. 비정형</h4>
<ol>
<li><p>정형 데이터( 스키마 )
구조화된 데이터, 미리 정해진 구조에 따라 정해진 데이터
ex) 엑셀, 관계형 DB의 테이블</p>
</li>
<li><p>반정형 데이터</p>
</li>
</ol>
<ul>
<li><p>구조에 따라 저장되지만, 데이터 내용 안에 구조에 대한 설명이 함께 존재</p>
</li>
<li><p>구조를 파악하는 파싱 과정 필요
ex) HTML, XML, JSON</p>
</li>
<li><p>파일 형태로 저장</p>
</li>
</ul>
<ol start="3">
<li>비정형 데이터</li>
</ol>
<ul>
<li>정해진 구조가 없는 데이터
ex) 텍스트, 영상, img, pdf</li>
</ul>
<h1 id="데이터베이스-언어-ddl-dml-dcl-">데이터베이스 언어( DDL, DML, DCL )</h1>
<ul>
<li><p>DDL( Data Definition Language)
DB 구조를 정의, 수정, 삭제하는 언어
ex) alter, crete, drop</p>
</li>
<li><p>DML( Data Manipulation Language)
DB내의 자료 검색, 삽입, 갱신, 삭제를 위한 언어
ex) insert, select, update, delete</p>
</li>
<li><p>DCL( Data Control Language)
데이터에 대한 무결성 유지, 병행 수행 제어, 보호와 관리를 위한 언어
ex) commit, rollback, grant, revoke</p>
</li>
</ul>
<h1 id="select-쿼리-실행-순서">SELECT 쿼리 실행 순서</h1>
<p><img src="https://velog.velcdn.com/images/new_guy/post/931d23c8-3293-405e-813b-682f3c7b5fc1/image.png" alt=""></p>
<p>FROM &gt; ON &gt; JOIN &gt; WHERE &gt; GROUP BY &gt; HAVING &gt; SELECT &gt; DISTINCT &gt; ORDER BY &gt; LIMIT</p>
<h1 id="트리거란">트리거란?</h1>
<p>INSERT, DELETE, UPDATE 같은 DML문이 수행되었을 때, 사용자가 아닌 DB에서 자동 실행.</p>
<h1 id="index란">Index란?</h1>
<p>테이블을 처음부터 끝까지 검색하는 테이블 풀 스캔이 아닌,
{ Key : Value } 형식으로 원하는 Value를 Key를 이용해서 가져온다.
( 단, 데이터는 Arraylist처럼 별도의 정렬없이 저장이 된다. )</p>
<ul>
<li><p>인덱스는 항상 정렬된 상태를 유지하기 때문에 SELECT는 빠르지만,
INSERT, UPDATE, DELETE는 포기</p>
</li>
<li><p>SELECT의 WHERE 조건절 모두 인덱스로 생성하면, 
데이터 저장 성능이 떨어지고 인덱스의 크기가 비대해짐 -&gt; 성능저하</p>
</li>
</ul>
<h2 id="1-index-자료구조">1. Index 자료구조</h2>
<ol>
<li>B+Tree 인덱스 자료구조</li>
</ol>
<p><img src="https://velog.velcdn.com/images/new_guy/post/fc8cb98f-22b2-4f95-ae84-cc020862894e/image.png" alt=""></p>
<ul>
<li><p>자식 노드 2개 이상인 B-Tree를 개선시킨 자료구조</p>
</li>
<li><p>B-Tree 리프노드들을 LinkedList로 연결하여 순차 검색에 용이.
( 해시 테이블보다 long2N의 시간복잡도를 갖지만, 일반적으로 사용 )</p>
</li>
<li><p>실제 data는 리프 노드에만 저장</p>
</li>
</ul>
<ol start="2">
<li>해시 테이블( key : value)</li>
</ol>
<ul>
<li><p>컬럼의 값으로 생성된 해시를 기반으로 인덱스를 구현</p>
</li>
<li><p>O(1)의 시간복잡도</p>
</li>
<li><p>부등호(&lt;,&gt;)와 같은 연속적인 데이터를 위한 순차 검색이 불가능 -&gt; 부적합.</p>
</li>
</ul>
<h2 id="2-인덱스-종류와-특징">2. 인덱스 종류와 특징</h2>
<h3 id="21-primary-key">2.1 PRIMARY KEY</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/cad0f97e-ff0e-425f-a156-1d592edd7507/image.png" alt=""></p>
<p>최초성과 유일성을 만족, 테이블 당 오직 1개, NOT NULL + 중복 허용 안함.</p>
<p>( 만약 Secondary Index와 같이 쓰면 B+Tree가 2개이다. )</p>
<h4 id="innodb에서-모든-secondary-index-검색에서-레코드를-읽기-위해서는-반드시-primary-key를-저장하고-있는-btree-한번-더-거쳐야함">&quot;InnoDB에서 모든 SECONDARY INDEX 검색에서 레코드를 읽기 위해서는 반드시! PRIMARY KEY를 저장하고 있는 B+Tree 한번 더 거쳐야함.&quot;</h4>
<h3 id="22-secondary-index-보조-인덱스-">2.2 SECONDARY INDEX( 보조 인덱스 )</h3>
<p>보조 인덱스의 리프는 [ 인덱스 키, PK ]로 구성되어 있다.</p>
<h2 id="23-foreign-key">2.3 FOREIGN KEY</h2>
<p>참조의 무결성</p>
<h1 id="정규화">정규화</h1>
<p>테이블 간 중복된 데이터 허용하지 않음.( 무결성 유지, DB의 저장 용량 감속 )</p>
<h2 id="-제1-정규화-">[ 제1 정규화 ]</h2>
<p>테이블의 컬럼이 Atomic 하게 값을 갖도록 분해</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/8fdb578b-53fe-4eda-a710-af9e4902eb91/image.png" alt="">( Before )</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/424f845c-2852-4407-b34d-23b61cd2b27a/image.png" alt="">( After )</p>
<h2 id="-제2-정규화-">[ 제2 정규화 ]</h2>
<p>제 1 정규화를 진행한 테이블에 대해 완전 함수 종속(기본키의 부분집합이 결정자가 되어선 안됨.)을 만족하도록 테이블을 분해.
( 모든 비프라이머리 속성이 기본키 전체에 대해 완전 함수 종속 )</p>
<h4 id="즉-현재-테이블의-주제와-관련없는-컬럼을-다른-테이블로-빼는-작업">즉, 현재 테이블의 주제와 관련없는 컬럼을 다른 테이블로 빼는 작업.</h4>
<p>🔍 예시:
| 학생ID | 과목코드  | 학생이름 | 과목이름 |
| ---- | ----- | ---- | ---- |
| 1001 | CS101 | 홍길동  | 자료구조 |
| 1001 | CS102 | 홍길동  | 운영체제 |</p>
<p>기본키: (학생ID, 과목코드)</p>
<p>학생이름은 학생ID에만 의존 → 부분 함수 종속.</p>
<p>과목이름은 과목코드에만 의존 → 역시 부분 함수 종속.</p>
<p>→ 제2정규형으로 분해:
학생(학생ID, 학생이름)</p>
<p>과목(과목코드, 과목이름)</p>
<p>수강(학생ID, 과목코드)</p>
<h2 id="-제3-정규화-">[ 제3 정규화 ]</h2>
<p>제 2 정규화를 진행한 테이블에 대해 이행적 종속( A -&gt; B, B -&gt; C = A -&gt; C)을 제거</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/84eb9495-4ca7-460f-8d04-eafec26c76ff/image.png" alt="">( Before )</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/71128988-7085-4a58-a703-a1abfa30c04f/image.png" alt="">( After )
학생번호 -&gt; 강좌이름, 강좌이름 -&gt; 수강료
( 학생번호 -&gt; 수강료 X )</p>
<h2 id="-bcnf-정규화-">[ BCNF 정규화 ]</h2>
<p>제 3 정규화를 진행한 테이블에 대해 모든 결정자가 후보키가 되도록 테이블을 분해.</p>
<h4 id="참고자료">참고자료</h4>
<ul>
<li><p>슈퍼키
테이블 내에서 어떤 컬럼(속성)끼리 묶떤 절대로 중복값이 안 나오고 서로 구별 가능</p>
</li>
<li><p>후보키
슈퍼키들 중에서 컬럼(속성)은 최소한의 갯수로 구분 가능한 컬럼.</p>
</li>
<li><p>기본키
후보키들 중에서 하나를 선택한 키로 최소성과 유일성을 만족하며, 오직 1개.</p>
</li>
<li><p>대체키
후보키가 2개 이상인 경우, 그 중에서 어느 하나를 기본키로 지정하고 남은 후보키</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/0691ee99-7684-45be-b013-782f373719e6/image.png" alt="">( Before )</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/9af71af1-9a1b-4ec6-88c9-dca39eb042fd/image.png" alt="">( After )</p>
<h4 id="정규화-장단점">정규화 장/단점</h4>
<h4 id="1-장점">1. 장점</h4>
<ul>
<li><p>DB 변경 시 이상현상이 발생하는 문제점 해결 가능</p>
</li>
<li><p>DB 구조 확장 시 정규화된 DB는 그 구조를 변경하지 않아도 되거나 일부만 변경해도 된다.</p>
</li>
</ul>
<h4 id="2-단점">2. 단점</h4>
<ul>
<li>릴레이션 간의 JOIN연산이 많아진다. 이로 인해 질의에 대한 응답 시간이 느려진다.</li>
</ul>
<p>참고)
데이터의 중복 속성을 제거하고 
결정자에 의해 &quot;동일한 의미의 일반 속성이 하나의 테이블로 집약&quot;되므로, 한 테이블의 데이터 용량이 최소화.</p>
<h4 id="역정규화">역정규화</h4>
<p>정규화된 DB를 다시 중복을 포함하는 형태로 변경함.</p>
<p>-&gt; 테이블을 너무 많이 잘게 쪼개면, 여러 태이블이 모두 동시에 조인을 하게 되기 떄문에 성능 이슈가 발생한다.</p>
<h4 id="이상-현상의-종류">이상 현상의 종류</h4>
<ol>
<li><p>삽입 이상
자료를 삽입시, 특정 속성에 해당하는 값이 없어 NULL을 입력</p>
</li>
<li><p>갱신 이상
중복된 데이터 중 일부만 수정되어 데이터 모순</p>
</li>
<li><p>삭제 이상
어떤 정보 삭제시, 의도하지 않은 다른 정보까지 삭제.</p>
</li>
</ol>
<p>=&gt; 이런 현상을 방지하기 위해서, 데이터 정규화.</p>
<h1 id="sql-injection">SQL Injection</h1>
<p>악의적인 의도를 갖는 SQL 구문을 삽입하여 데이터베이스를 비정상적으로 조작하는 코드 인젝션 기법.</p>
<h2 id="방지법">방지법</h2>
<ul>
<li><p>입력된 값이 개발자가 의도한 값(유효값)인지 검증</p>
</li>
<li><p>저장 프로시저 사용
( Query에 미리 형식을 지정, 지정된 형식이 아니면 실행 안됨. )</p>
</li>
</ul>
<h1 id="rdbms-vs-nosql">RDBMS vs. NoSQL</h1>
<ol>
<li>RDBMS
모든 데이터를 2차원 테이블 형태로 표현</li>
</ol>
<ul>
<li><p>장점
스키마에 맞춰 데이터를 관리하기 때문에 데이터의 정합성을 보장</p>
</li>
<li><p>단점
시스템이 커질수록 쿼리가 복잡해지고, 성능 저하( Scale-up만 가능하고 ,Scale-out은 안됨 )</p>
</li>
</ul>
<h4 id="참고">참고</h4>
<ul>
<li><p>Scale-up
기존 서버의 사양을 업그레이드( 스펙업 )</p>
</li>
<li><p>Scale-out
서버를 여러 대 추가
부하를 균등하게 해야 하므로, loadbalancing 필수</p>
</li>
</ul>
<ol start="2">
<li>NoSQL
데이터간의 관계를 정의하지 않아서,
Schema 없이 좀 더 자유롭게 데이터를 관리할 수 있음.</li>
</ol>
<ul>
<li><p>장점
스키마 없이 {key:value}로 데이터를 자유롭게 관리
데이터 분산이 용이 -&gt; scale-up, scale-out 가능</p>
</li>
<li><p>단점
데이터 중복 발생
스키마가 없음 -&gt; 데이터 구조 결정이 어려움.</p>
</li>
</ul>
<h4 id="그러면-언제-rdmbs와-nosql을-사용">그러면 언제 RDMBS와 NoSQL을 사용?</h4>
<ul>
<li><p>RDBMS는 데이터 구조가 명확하고, 변경될 여지가 없으면 사용</p>
</li>
<li><p>NoSQL은 정확한 데이터 구조를 알 수 없고, 데이터가 변경/확장이 될 수 있는 경우 사용.</p>
</li>
</ul>
<h1 id="트랜잭션">트랜잭션</h1>
<p>하나의 논리적 작업 단위이며, 작업의 완전성을 보장해준다.
또한 하나의 트랜잭션은 Commit 또는 Rollback이 되어, ACID를 보장한다.</p>
<h4 id="acid">ACID</h4>
<ol>
<li><p>A(Atomic)
Commit or Rollback(중간에 절반만 적용되는 경우는 절대 없다.)</p>
</li>
<li><p>C(Consistency)
실행이 완료되면 언제나 일관성 있는 상태를 유지
트랜잭션이 진행되는 동안 DB가 변경 되더라도 업데이트된 DB로 진행되는 것이 아니라!,
처음 트랜잭션을 진행하기 위해 참조한 DB로 진행되어야 한다.</p>
</li>
<li><p>I(Isolation)
둘 이상 트랜잭션이 동시에 실행될 경우 서로의 연산에 끼어들 수 없다.</p>
</li>
<li><p>D(Durability)
완료된 결과는 영구적으로 반영되어야 한다.</p>
</li>
</ol>
<h1 id="db락">DB락</h1>
<ul>
<li><p>공유락( Shared Lock, S-Lock )
트랜잭션이 읽기를 할 때 사용하는 락이며, 
데이터를 읽기만하기 때문에 같은 공유락끼리 동시에 접근이 가능</p>
</li>
<li><p>베타락( Exclusive Lock, X-Lock )
쓰기락이라고 불리며, 데이터를 변경시 사용하며,
트랜잭션이 완료될 때까지 유지되며, 베타락이 끝나기 전까지 어떤 접근도 허용x</p>
</li>
</ul>
<h1 id="옵티마이져">옵티마이져</h1>
<p>SQL을 가장 빠르고 효율적으로 수행할 최적의 경로를 생성해줌.
( 알아서 INDEX 사용할지 결정 )</p>
<h1 id="inner-join-vs-outer-join">Inner Join vs. Outer Join</h1>
<ul>
<li><p>Inner Join
교집합으로 두 스키마간 공통 부분.</p>
</li>
<li><p>Outer Join
A여집합 + A와B 교집합으로,
한 쪽에는 데이터가 있고 다른 한쪽에는 데이터가 없는 경우,
데이터가 있는 쪽 전체를 출력하는 방법.</p>
</li>
</ul>
<h1 id="group-by">Group By</h1>
<p>특정 컬럼을 기준으로 그룹을 만듦.</p>
<h1 id="delete-truncate-drop의-차이점은">DELETE, TRUNCATE, DROP의 차이점은?</h1>
<ul>
<li><p>DELETE는 데이터를 지우지만 용량은 줄어들지 않는다 -&gt; 삭제 후 복구 가능</p>
</li>
<li><p>TRUNCATE은 전체 데이터를 삭제해서 용량이 줄고, 인덱스도 삭제 -&gt; 테이블 삭제 불가하고, 복구 안됨.</p>
</li>
<li><p>DROP은 테이블 자체를 삭제 -&gt; 복구 불가.</p>
</li>
</ul>
<h1 id="having-vs-where">Having vs. Where</h1>
<p>having은 group by를 필터링 하는데 사용 -&gt; 그룹화, 집계가 발생한 후 필터링
where은 개별 행을 필터링 하는데 사용. -&gt; 그룹화, 집계가 발생하기 전 필터링.</p>
<h1 id="join에서-on과-where-차이">Join에서 On과 Where 차이</h1>
<p>ON이 WHERE보다 먼전 실행되어 JOIN을 하기 전에 필터링을 하고
(ON 조건으로 필터링이 된 레코들간 JOIN)
WHERE은 JOIN을 한 후 필터링을 한다.
(JOIN을 한 결과에서 WHERE 조건절로 필터링 발생.)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Framework 면접 대비]]></title>
            <link>https://velog.io/@new_guy/Spring-Framework-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84</link>
            <guid>https://velog.io/@new_guy/Spring-Framework-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84</guid>
            <pubDate>Wed, 21 May 2025 04:56:08 GMT</pubDate>
            <description><![CDATA[<h1 id="spring-framework">Spring Framework</h1>
<h2 id="1-개념">1. 개념</h2>
<p>자바 개발을 편하게 해주는 프레임워크로</p>
<ul>
<li>IoC
제어권을 프레임워크로 넘김으로써,
객체 간의 결합도를 줄이고 유연한 코드를 작성할 수 있으며,
가독성 및 코드 중복, 유지 보수에 유리.</li>
</ul>
<h4 id="기존">기존</h4>
<ol>
<li><p>객체 생성</p>
</li>
<li><p>의존성 객체 생성( 클래스 내부에서 생성 )</p>
</li>
<li><p>의존성 객체 메소드 호출</p>
</li>
</ol>
<h4 id="스프링-프레임워크">스프링 프레임워크</h4>
<ol>
<li><p>객체 생성 </p>
</li>
<li><p>의존성 객체 주입
제어권을 스프링에게 위임하여 스프링이 만들어놓은 객체를 주입.</p>
</li>
<li><p>의존성 객체 메소드 호출</p>
</li>
</ol>
<h4 id="스프링이-모든-의존성-객체를-스프링이-실행될-때-다-만들어주고-필요한-곳에-주입시킴으로써-bean은-싱글톤-패턴이며-제어의-흐름은-스프링에게-전적으로-위임한다">스프링이 모든 의존성 객체를 스프링이 실행될 때 다 만들어주고 필요한 곳에 주입시킴으로써 Bean은 싱글톤 패턴이며, 제어의 흐름은 스프링에게 전적으로 위임한다.</h4>
<ul>
<li>DI
각 레이어 간에 의존성이 존재할 경우 프레임워크가 서로 연결시켜준다.
모듈 간의 결합도가 낮아지고 유연성이 높아진다.
(객체를 직접 생성하는 게 아니라 외부에서 생성한 후 주입 시켜주는 방식)</li>
</ul>
<h4 id="생성자-주입-필드-주입-세터-주입이-있는데-생성자-주입을-통해서-1-순환-참조-방지-2-불변성-3-테스트-용이함">생성자 주입, 필드 주입, 세터 주입이 있는데, 생성자 주입을 통해서 1. 순환 참조 방지, 2. 불변성, 3. 테스트 용이함.</h4>
<ul>
<li><p>AOP
여러 모듈(시스템의 구성 요소)에서 공통적으로 사용하는 기능의 경우,
해당 기능을 분리하여 관리.
(공통 모듈인 인증, 로깅, 트랜잭션에 용이)
이를 통해서 중복 코드 제거, 재활용성 극대화</p>
</li>
<li><p>경량 컨테이너로서 자바 객체를 직접 관리
객체 생성, 소멸과 같은 라이프 사이클을 관리.</p>
</li>
</ul>
<h2 id="2-spring-boot-vs-spring-framework">2. Spring Boot vs. Spring Framework.</h2>
<p>가장 큰 차이는 Auto Configuration이다.
Spring은 프로젝트 초기에 다양한 환경설정을 해야하나,
Spring Boot는 많은 부분을 자동화해서 사용자가 편하게 스프링을 활용할 수 있게 해준다.</p>
<h2 id="3-spring-mvc">3. Spring MVC</h2>
<ul>
<li><p>Model( DAO, DTO, Service )
데이터 관리, 비즈니스 로직 처리</p>
</li>
<li><p>View
비즈니스 로직의 처리 결과를 통해 유저 인터페이스가 표현되는 구간</p>
</li>
<li><p>Controller
사용자의 요청을 처리하고, Model과 View를 중개하는 역할.</p>
</li>
</ul>
<p>이는 컴포넌트를 분리함으로써, 시스템 간 결합도를 낮추기 위함이다.</p>
<h4 id="spring-mvc-요청-흐름도">Spring MVC 요청 흐름도</h4>
<p><img src="https://velog.velcdn.com/images/new_guy/post/bc2456f4-d64d-4263-b808-176483da4a2b/image.png" alt=""></p>
<ul>
<li><p>DispatcherServlet
클라이언트에게 요청을 받아 응답까지의 MVC 처리과정을 통제한다.</p>
</li>
<li><p>HandlerMapping
클라이언트의 요청 URL을 어떤 Controller가 처리할지 결정</p>
</li>
<li><p>HandlerAdapter
HandlerMapping에서 결정된 핸들러 정보로 해당 메소드를 직접 호출</p>
</li>
<li><p>ViewResolver
Controller의 처리 결과를 생성할 view를 결정</p>
</li>
</ul>
<ol>
<li><p>클라이언트는 URL을 통해 요청을 전송한다.</p>
</li>
<li><p>DispatcherServlet은 핸들러 매핑을 통해 해당 요청이 어느 컨트롤러에게 온 요청인지 찾는다.</p>
</li>
<li><p>DispatcherServlet은 HandlerAdapter에게 요청의 전달을 맡긴다.</p>
</li>
<li><p>HandlerAdapter는 해당 컨트롤러에 요청을 전달한다.</p>
</li>
<li><p>Contrller는 비즈니스 로직을 처리한 후 반환할 뷰의 이름을 반환한다.</p>
</li>
<li><p>DispatcherServlet은 ViewResolver를 통해 반환할 View를 찾는다.</p>
</li>
<li><p>DispatcherServlet은 Controller에서 View에 전달할 데이터를 추가한다.</p>
</li>
<li><p>데이터가 추가된 View를 반환한다.</p>
</li>
</ol>
<h2 id="4-스프링-bean-등록">4. 스프링 Bean 등록.</h2>
<ol>
<li>@Component로 등록</li>
</ol>
<ul>
<li><p>class level</p>
</li>
<li><p>개발자가 작성</p>
</li>
<li><p>@Scope(&quot;Prototype&quot;)은 싱글톤이 아닌 빈 생성.</p>
</li>
</ul>
<ol start="2">
<li>@Configuration클래스 내부에 @Bean 메소드 등록</li>
</ol>
<ul>
<li><p>method level</p>
</li>
<li><p>외부 라이브러리가 제공하는 객체</p>
</li>
</ul>
<h4 id="빈-라이프-사이클">빈 라이프 사이클</h4>
<p>스프링 IOC 컨테이너 생성 -&gt; 스프링 빈 생성 -&gt; 의존관계 주입 -&gt; 초기화 콜백 메소드 호출 -&gt; 사용 -&gt; 소멸 전 콜백 메소드 호출 -&gt; 스프링 종료.</p>
<p>스프링은 3가지 방법으로 Bean 생명주기 콜백을 관리.</p>
<ol>
<li><p>인터페이스</p>
</li>
<li><p>설정 정보에 초기화 메소드, 종료 메소드 지정</p>
</li>
<li><p>@PostConstuct, @PreDestroy 지원</p>
</li>
</ol>
<h4 id="스프링의-싱글톤-패턴">스프링의 싱글톤 패턴</h4>
<p>@Bean, @Component 생성하면 싱글톤으로 등록이 되는데,
요청이 들어올 때마다 매번 객체를 생성하지 않고, 이미 만들어진 객체를 공유하기 때문에 효율적인 사용이 가능.</p>
<h4 id="spring의-scope-prototype">Spring의 Scope &quot;Prototype&quot;</h4>
<p>default bean(싱글톤)과 달리 컨테이너에게 빈 요청시 매번 새로운 객체를 생성해서 반환.
@Scope(&quot;prototype&quot;)</p>
<h4 id="lombok과-lombok이-만드는-메소드들이-생성되는-시점은">Lombok과 Lombok이 만드는 메소드들이 생성되는 시점은?</h4>
<p>메소드를 &quot;컴파일 하는 과정에 개입&quot;해서 추가적인 코드를 만듦 = Annotation Processing</p>
<p>Annotation Processing은 자바 컴파일러가 컴파일 단계에서 annotation을 분석하고 처리하는 기법.</p>
<h1 id="servlet">Servlet</h1>
<p>클라이언트의 요청을 처리하고, 그 결과를 반환하는 (Servlet 클래스의 구현 규칙을 지킨) 자바 웹 프로그래밍 기술.</p>
<p>Spring MVC에서 &quot;Controller&quot;가 이 역할을 담당한다.
(자바를 사용해 웹을 만들기 위해 필요한 기술.)</p>
<h2 id="1-특징">1. 특징</h2>
<ul>
<li><p>클라이언트의 요청에 대해 동적으로 작동하는 웹 어플리케이션</p>
</li>
<li><p>html을 사용해서 요청에 응답.</p>
</li>
<li><p>Java Thread를 이용</p>
</li>
<li><p>MVC 패턴 중 Controller에 해당.</p>
</li>
<li><p>HttpServlet 클래스를 상속받음.</p>
</li>
<li><p>UDP보다 느림.</p>
</li>
<li><p>HTML 변경 시 Servlet 재컴파일 해야함.</p>
</li>
</ul>
<p>동적인 페이지를 제공시 사용자가 요청한 시점에 페이지를 생성해서 전달해 주는 것을 의미.</p>
<h4 id="servlet-동작방식">Servlet 동작방식</h4>
<p><img src="https://velog.velcdn.com/images/new_guy/post/0a2c9e57-92f3-458f-9e76-5fcd9f5b5efc/image.png" alt=""></p>
<ol>
<li><p>사용자가 URL을 입력하면 HTTP Request가 Servlet Container로 전송됨.</p>
</li>
<li><p>요청 받은 Servlet Container는 HttpServletRequest, HttpServletResponse객체를 생성</p>
</li>
<li><p>web.xml을 기반으로 사용자 요청한 URL이 어느 서블릿(Controller)에 대한 요청인지 찾음.</p>
</li>
<li><p>해당 서블릿에서 service메소드를 호출 한 후, GET, POST에 따라 doGet() 또는 doPost()를 호출한다.</p>
</li>
<li><p>doGet() or doPost() 메소드는 동적 페이지를 생성한 후 HttpServletResponse객체에 응답</p>
</li>
<li><p>응답이 끝나면 HttpServletRequest,httpServletResponse를 종료</p>
</li>
</ol>
<h4 id="참고로-was는-요청-정보를-담은-request-객체와-응답-정보를-담은-response-객체를-새로-생성">참고로, WAS는 요청 정보를 담은 Request 객체와 응답 정보를 담은 Response 객체를 새로 생성</h4>
<p><img src="https://velog.velcdn.com/images/new_guy/post/cd6f6618-b4fb-4e15-9d85-fa468d994602/image.png" alt=""></p>
<h2 id="2-servlet-container">2. Servlet Container</h2>
<p>서블릿을 관리해주는 컨테이너.
(서블릿 컨테이너에 의해서 서블릿이 작동한다.)
Ex) Tomcat</p>
<h4 id="servlet-container-역할">Servlet Container 역할</h4>
<ol>
<li><p>웹서버와의 통신 지원
일반적으로 소켓을 만들고 listen, accept 등을 처리해야 하지만,
이런 과정을 서블릿 컨테이너가 담당하며,
개발자는 비즈니스 로직만 처리하면 된다.</p>
</li>
<li><p>서블릿 생명주기 관리
서블릿 클래스를 로딩하여 인스턴스화하고, 초기화 메소드를 호출하고, 요청이 들어오면 적절한 서블릿 메소드를 호출.
또한 생명이 다하면 GC를 한다.</p>
</li>
<li><p>멀티쓰레드 지원 및 관리
요청 1개당 스레드 1개(커널과 1대1 관계)를 매핑하는데,
스프링부트에서 스레드 풀을 이용해서 재사용을 하며,
API 연결 시간이 지나면 자동으로 연결을 차단한다.</p>
</li>
<li><p>선언적인 보안 관리</p>
</li>
</ol>
<h2 id="서블릿-생명주기">서블릿 생명주기</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/f846dc42-5b3c-4e21-9e86-3ed28ab24aed/image.png" alt=""></p>
<ol>
<li><p>클라이언트 요청이 들어오면 컨테이너는 해당 서블릿이 메모리에 있는지 확인하고, 없을 경우 init()메소드를 호출해서 적재한다.
( init메소드는 처음 한번만 실행)</p>
</li>
<li><p>init()이 호출된 후 클라이언트 요청에 따라 serivce()메소드를 통해 요청에 대한 응답이 doGet(), doPost()로 분기.
또한 들어온 요청에 대해서 HttpServletRequest, HttpServletResponse 생성.</p>
</li>
<li><p>컨테이너가 서블릿에 종료 요청 -&gt; destroy()호출</p>
</li>
</ol>
<h1 id="spring-filter-vs-interceptor">Spring Filter vs. Interceptor</h1>
<h2 id="1-filter">1. Filter?</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/434ab05d-ce2b-458c-abb7-6f258121b051/image.png" alt=""></p>
<p>&quot;Dispatcher Servlet에 요청이 전달되기 전/후&quot;에 &quot;url 패턴에 맞는 모든 요청에 대해 부가작업&quot;을 처리할 수 있는 기능.</p>
<p>필터는 Spring Context(범위) 밖에서 처리.
(스프링 컨테이너가 아닌! 웹(서블릿) 컨테이너가 관리.)</p>
<ul>
<li><p>보안 및 인증/인가</p>
</li>
<li><p>모든 요청에 대한 로깅</p>
</li>
<li><p>이미지/데이터 압축 및 문자열 인코딩</p>
</li>
<li><p>Spring과 분리되어야 하는 기능</p>
</li>
</ul>
<p>만약 필터에서 에러가 발생하면, Spring까지 못가니까 필터에서 처리를 반드시 해야한다.</p>
<h2 id="2-인터셉터">2. 인터셉터</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/b23032a5-4e14-40ca-8bd0-c87c62f72c4f/image.png" alt="">
Spring이 제공하는 기술로써, Dispatcher 서블릿이 컨트롤러를 호출하기 전/후 요청과 응답을 참조하거나 가공할 수 있다.
( 스프링 컨텐그스에서 동작 )
따라서, 인터셉터가 있으면 인터셉트를 거쳐서 -&gt; 컨트롤러로 도착.</p>
<ul>
<li><p>세부적인 보안 및 인증/인가</p>
</li>
<li><p>API 호출에 대한 로깅</p>
</li>
<li><p>Controller로 넘겨주는 정보 가공.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/5bc12d45-32aa-47f7-af3a-cc474a4efac4/image.png" alt=""></p>
<h4 id="dispatcher-servlet">Dispatcher Servlet?</h4>
<p>&quot;HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아&quot;
적합한 컨트롤러에 위임해주는 프론트 컨트롤러.</p>
<p>모든 요청을 프론트 컨트롤러인 Dispatcher Servlet이 가장 먼저 받고,
Dispatcher Servlet은 공통 작업을 먼저 처리한 후, 해당 요청을 처리하는 컨트롤러를 찾아서 작업을 위임한다.</p>
<h4 id="dispatcher-servlet-장점">Dispatcher Servlet 장점</h4>
<p>기존에서는 모든 서블릿을 URL 매핑을 위해 web.xml에 모두 등록해주어야 했지만,
dispatcher-servlet이 들어오는 모든 요청을 핸들링 및 공통 작업으로 편리.</p>
<h4 id="정적-자원-처리">정적 자원 처리</h4>
<p>Dispatcher Servlet이 모든 요청을 처리해서 이미지, html, css, javascript까지 모두 싹다 가로채서 정적 자원을 불러오지 못한다.</p>
<p>그래서 다음과 같이 접근.</p>
<ol>
<li><p>정적 자원 요청과 애플리케이션 요청을 분리
/app은 Dispatcher Servlet이, /resources는 정적자원으로 처리하게 유도한다.
( 모든 요청에 url을 추가해야 하므로, 지저분 )</p>
</li>
<li><p>애플리케이션 요청을 탐색하고 없으면 -&gt; 정적 자원 요청 처리
먼저 컨트롤러 탐색 -&gt; 못 찾으면, 정적 자원 탐색.</p>
</li>
</ol>
<h4 id="vo-bo-dao--dto-구분">VO, BO, DAO , DTO 구분</h4>
<ul>
<li><p>DAO( Data Access Object )
DB의 데이터에 접근을 위한 객체</p>
</li>
<li><p>BO( Business Object )
여러 DAO를 활용해 비즈니스 로직을 처리하는 객체</p>
</li>
<li><p>DTO( Data Transfer Object )
각 계층간의 데이터 교환을 위한 객체
( Controller, Service, Business, ... )</p>
</li>
<li><p>VO( Value Object, read-only )</p>
</li>
</ul>
<ol>
<li><p>불변성 : setter가 없고, getter만 있다.
한번 생성되면 이후 내부 값을 바꿀 수 없음(final, 원시타입)</p>
</li>
<li><p>값 동등성( equals ) : 내부 값 동등성 검사
내부의 값이 동일한 두 객체는 동일한 것으로 판단.</p>
</li>
<li><p>자가 유효성 검사( hashCode ) : 생성자에서 validate</p>
</li>
</ol>
<h1 id="transactional-acid">@Transactional (ACID)</h1>
<h3 id="1-의의">1. 의의</h3>
<p>method level 또는 class level에서 사용 가능.
모든 public 메소드에 트랜잭션을 적용</p>
<p>해당 메소드를 실행시 트랜잭션을 시작하고,
메소드가 정상적으로 종료 -&gt; 트랜잭션 commit
메소드가 예외를 발생시키면 -&gt; rollback</p>
<p>이를 통해서 ACID를 유지할 수 있다.</p>
<p>그리고 기존의 긴 JDB 트랜잭션을 짧은 코드로 바꿀 수 있다.</p>
<pre><code class="language-java">// JDBC
Connection conn = dataSource.getConnection();
Savepoint savepoint;

try (connection) {
    conn.setAutoCommit(false);
    Statement stmt = conn.createStatement();
    savepoint = conn.setSavepoint(&quot;savepoint&quot;);
    String sql = &quot;Insert into User values (16, &#39;Rosie&#39;, &#39;rosie@gmail.com&#39;)&quot;
    stmt.executeUpdate(sql);
    conn.commit(); 
} catch (SQLException e) {
    conn.rollback(savepoint); 
}</code></pre>
<pre><code class="language-java">// @Transactional
public class UserService{
    private final UserRepository userRepository;   

    @Transactional(readOnly = true)
    public List&lt;User&gt; findAll(User user) {
        return userRepository.save(user);
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/new_guy/post/8f24be09-a591-4603-bcc2-5c23651b82e7/image.png" alt=""></p>
<h3 id="2-동작원리">2. 동작원리</h3>
<ol>
<li><p>TransactionAutoConfiguration이 실행
( proxy 생성에 필요 )</p>
</li>
<li><p>요청이 올 경우, Spring은 AOP프레임워크를 이용해서 &quot;Proxy&quot;를 생성하고,
특정 메소드 호출을 가로채서 추가 동작을 수행.
( 각 JointPoint에서 동작하는 횡단 관심의 공통 기능을 수행. )</p>
</li>
</ol>
<h3 id="3-주의사항">3. 주의사항</h3>
<ol>
<li><p>public 선언
프록시 객체로 외부에서 접근 가능한 인터페이스를 제공해야 함.</p>
</li>
<li><p>다른 AOP 기능과의 충돌을 고려
@Secured를 통해 권한이 있는 사용자 여부를 확인하는데, 먼저 @Transactional이 수행된다면 권한 검사가 무의미함.</p>
</li>
<li><p>Service layer 사용
Service layer에서 @Transactional을 Atomic하게 처리.</p>
</li>
</ol>
<h4 id="굳이-proxy를-쓰는-이유">굳이 Proxy를 쓰는 이유?</h4>
<p>메소드 실행을 가로채서, 그 메소드 실행 전후에 트랜잭션을 시작하고 &quot;커밋/롤백&quot;을 위함.</p>
<h2 id="4-만약-트랜잭션을-내부-호출을-할-경우">4. 만약 트랜잭션을 내부 호출을 할 경우</h2>
<pre><code class="language-java">@Service
public class MyService {

    @Transactional // 트랜잭션 적용
    public void methodA() {
        // 트랜잭션이 적용되길 기대
        ...
    }

    public void methodB() {
        methodA(); // 내부에서 자기 자신 호출
    }
}</code></pre>
<h4 id="프록시는-외부에서-접근할-때만-작동">프록시는 외부에서 접근할 때만 작동.</h4>
<ul>
<li><p>Spring은 @Transactional을 프록시 객체에 적용.</p>
</li>
<li><p>외부(Controller 등)에서 myService.methodA()처럼 호출해야,
프록시 -&gt; 트랜잭션 시작 -&gt; 진짜 메소드</p>
</li>
<li><p>동일 클래스 안에서 자가 호출은 작동안함.</p>
</li>
</ul>
<h4 id="트랜잭션-전파">트랜잭션 전파</h4>
<pre><code class="language-java">@Service
public class MyService {

    @Transactional
    public void methodA() {
        methodB();
    }

    @Transactional
    public void methodB() {
        // 작업 수행
    }
}</code></pre>
<p>Propagation.REQUIRED를 할 경우</p>
<ul>
<li><p>호출하는 쪽에 트랜잭션이 있으면 -&gt; 트랜잭션 재사용</p>
</li>
<li><p>없으면 새로운 트랜잭션을 만듦.</p>
</li>
</ul>
<p>여기서는 methodA()가 프록시에 의해서 트랜잭션이 시작되고, methodB()가 실행시 이미 있기 때문에 트랜잭션을 재사용을 한다.</p>
<h4 id="트랜잭션-추가설명">트랜잭션 추가설명</h4>
<p>트랜잭션은 반드시 Commit/Rollback</p>
<ul>
<li>트랜잭션 시작 및 종료</li>
</ul>
<p>트랜잭션은 1개의 Connection을 가져와 사용하고 반납하는 일련의 과정.</p>
<p>하나의 트랜잭션이 시작되면 Commit/Rollback이 호출될 때까지 하나의 트랜잭션으로 묶임.</p>
<p>Commit/Rollback으로 트랜잭션을 종료하는 작업 = 트랜잭션 경계 설정.</p>
<p>트랜잭션의 경계는 하나의 Connection을 통해 진행됨 -&gt; 트랜잭션의 경계는 1개의 커넥션이 만들어지고 닫히는 범위 안에 존재.</p>
<h4 id="transactional에-read-only를-사용하는-이유">@Transactional에 read-only를 사용하는 이유</h4>
<p>read-only이기 때문이며, 영속성 컨텍스트에서 엔티티를 관리할 필요가 없으며, readOnly를 통해서 메모리 성능을 높일 수 있음.</p>
<p>readOnly 속성이 없으면, 데이터 조회 결과 엔티티가 영속성 컨텍스트에 관리되면,
1차 캐싱부터 변경감지까지 가능하게 된다.</p>
<p>하지만, 조회시 스냅샷 인스턴스를 생성해 보관하기 때문에 메모리 사용량이 증가한다.</p>
<h4 id="jpa와-같은-orm을-사용하면서-쿼리가-복잡해진다면">JPA와 같은 ORM을 사용하면서 쿼리가 복잡해진다면?</h4>
<p>JPA 자체는 정적인 상황에서 사용하는걸 권장하므로,
복잡한 쿼리나 동적 쿼리는 JPQL이나 Querydsl을 쓰자.</p>
<h1 id="mybatis-vs-jpa">MyBatis vs. JPA</h1>
<h1 id="-orm이란">! ORM이란?</h1>
<p>객체 관계 매핑으로 객체와 DB테이블 간 매핑.</p>
<h2 id="0-jdbc">0. JDBC</h2>
<p>하나의 파일에 SQL, DB연결, 자바코드 모두 존재해서 재사용성이 좋지 않다.</p>
<h2 id="1-mybatis">1. MyBatis</h2>
<p>Java 메소드와 SQL 간 매핑( SQL 직접 작성. )
( Java 메소드 선언과 SQL문 생성 -&gt; MyBatis가 자동으로 그 둘 간 연결)</p>
<p>SQL문을 별도로 Java 코드에서 분리 -&gt; 관리 용이.</p>
<p>또한 동적인 SQL 생성 기능을 제공 -&gt; &quot;사용자가 입력한 파라미터에 따라&quot; 서로 다른 SQL 문을 동적으로 생성 가능.</p>
<pre><code class="language-sql">-- title을 입력할 경우
SELECT * FROM BLOG WHERE state = ‘active’ AND title like #{title}

-- title을 입력하지 않을 경우
SELECT * FROM BLOG WHERE state = ‘active’</code></pre>
<h1 id="2-jpaorm">2. JPA(ORM)</h1>
<p>ORM은 객체와 DB 테이블간 매핑해주는 기술을 의미한다.</p>
<p>SQL 자동생성 및 DB데이터와 Java 객체를 매핑.</p>
<p>객체 모델과 관계형 DB의 테이블 간 매핑을 자동 처리.</p>
<p>이를 통해서 객체지향적으로 개발 가능하고 DB와 Java 간의 불일치 해소.</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/7d81a063-e374-4373-9d0e-55897b49aaff/image.png" alt="">
( <a href="https://www.elancer.co.kr/blog/detail/231">https://www.elancer.co.kr/blog/detail/231</a> )</p>
<p>Java와 DB 데이터 간의 매핑을 자동화를 통해서</p>
<ul>
<li><p>SQL문 작성 필요 x</p>
</li>
<li><p>내부적으로 java메소드에 적합한 SQL문이 자동으로 생성.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/19da8e03-4cd8-4e62-9887-c60d12b62fcd/image.png" alt="">
( <a href="https://www.elancer.co.kr/blog/detail/231">https://www.elancer.co.kr/blog/detail/231</a> )</p>
<h1 id="비교-분석">비교 분석</h1>
<h2 id="0-jdbc-1">0. JDBC</h2>
<p>하나의 파일에 SQL, DB연결, Java언어가 모두 존재 -&gt; 재사용성이 안좋다.</p>
<h2 id="1-mybatis-1">1. Mybatis</h2>
<h3 id="장점-및-단점">장점 및 단점</h3>
<ul>
<li>SQL 직접 제어</li>
</ul>
<p>하지만, </p>
<ul>
<li><p>CRUD 단순 작업에 반복 수작업 필요</p>
</li>
<li><p>DB에 종속적( 무조건 DB에 맞게 SQL문이 작성되어 있음. DB바뀌면 전체 수정 )</p>
</li>
</ul>
<h2 id="2-jpa">2. JPA</h2>
<h3 id="장점-및-단점-1">장점 및 단점</h3>
<ul>
<li><p>자동 매핑으로 개발 및 유지보수성 향상
JPA는 객체와 DB간의 자동 매핑을 지원</p>
</li>
<li><p>객체 지향적인 접근</p>
</li>
<li><p>DBMS에 독립적
DB가 변경되어도 JPA가 자동으로 적합한 SQL 방언을 만들어준다. -&gt; SQL문을 다시 작성할 필요가 없다.</p>
</li>
</ul>
<p>하지만,</p>
<ul>
<li><p>복잡한 SQL 생성이 어려움 -&gt; JPQL이나 Querydsl 쓰자</p>
</li>
<li><p>성능까지 고려.</p>
</li>
</ul>
<h1 id="jpa-vs-hibernate-vs-spring-data-jpa">JPA vs Hibernate vs Spring Data JPA</h1>
<ul>
<li><p>JPA : 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스( 구현체가 아닌 명세서 )</p>
</li>
<li><p>Hibernate : JPA의 구현체( 다른 것을 직접 구현해도 되지만, 굳이??? ) </p>
</li>
<li><p>Spring Data JPA : @Repository를 이용( JPA를 쓰기 편하게 모은 모듈 )</p>
</li>
</ul>
<h1 id="영속성persistence">영속성(Persistence)</h1>
<ul>
<li><p>데이터를 생성한 프로그램이 종료되더라도, 사라지지 않음</p>
</li>
<li><p>영속성을 갖지 않는 데이터는 단지 메모리에만 존재 -&gt; 프로그램 종료시, 모두 삭제.
따라서, 파일 시스템, RDBMS에 데이터를 영구적으로 저장하여 영속성을 부여.</p>
</li>
</ul>
<h2 id="영속성-레이어">영속성 레이어</h2>
<p>영속성을 부여해주는 계층으로 간단한 작업만으로 DB와 연동되는 시스템을 빠르게 개발할 수 있으며, 안정적인 구동을 보장.</p>
<h2 id="영속성-컨텍스트">영속성 컨텍스트</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/9502abec-3217-4737-8dc1-360fa3fa1614/image.png" alt=""></p>
<p>영속성 컨텍스트는 애플리케이션과 DB 사이에서 엔티티와 레코드의 괴리를 해소하는 기능과 객체를 보관하는 기능을 수행.</p>
<p>엔티티 객체가 영속성 컨텍스트에 들어오면 -&gt; JPA는 엔티티 객체의 매핑 정보를 DB에 반영하는 작업을 수행.</p>
<p>엔티티 객체가 영속성 컨텍스트에 들어와 JPA의 관리 대상이 되는 시점부터, 해당 객체를 영속 객체라고 부름.</p>
<p>엔티티 매니저를 통해 영속성 컨텍스트에 접근.</p>
<p>영속성 컨텍스트는 &quot;세션 단위의 생명주기&quot;를 가짐.
즉, DB에 접근하기 위한 세션이 생성되면 -&gt; 영속성 컨텍스트가 만들어지고,
세션이 종료되면 -&gt; 영속성 컨텍스트도 없어진다.</p>
<ol>
<li><p>비영속(new)
객체 생성인데, 영속성 컨텍스트와 관련이 없음.</p>
</li>
<li><p>영속</p>
</li>
</ol>
<ul>
<li><p>엔티티가 영속성 컨텍스트에 저장된 상태로, 영속성 컨텍스트에 의해 관리</p>
</li>
<li><p>반드시, 트랜잭션 커밋 시점에 DB에 반영.</p>
</li>
</ul>
<ol start="3">
<li><p>준영속 상태
영속성 컨텍스트에 엔티티가 저장되었다가 분리</p>
</li>
<li><p>삭제 상태
영속성 컨텍스트와 DB에서 삭제된 상태.</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/new_guy/post/89559c04-b415-45b5-9765-9a168af6dd4e/image.png" alt=""></p>
<h2 id="영속성-컨텍스트의-특징">영속성 컨텍스트의 특징</h2>
<ol>
<li><p>1차 캐시
: 영속상태의 엔티티는 모두 1차 캐시에 저장되고, 1차 캐시는 @Id를 키로 가지고 있는 Map이 존재한다.
엔티티를 조회시, 바로 DB에 접근하는 것이 아니라, 1차 캐시 조회 후 -&gt; 없는 경우 DB에 접근하여 조회 후, 다시 1차 캐시에 저장.</p>
</li>
<li><p>동일성 보장
: 영속성 컨텍스트와 엔티티의 식별자가 동일한 경우 -&gt; 동일성이 보장.</p>
</li>
<li><p>트랜잭션 쓰기지연
: 영속성 컨텍스트에서 DML이 발생시 바로 DB에 저장하지 않고, 트랜잭션이 커밋 시
영속성 컨텍스트의 쓰기지연 SQL 저장소에 모아둔 쿼리들을 한 번에 저장.</p>
</li>
</ol>
<p>이때 쿼리들은 영속성 컨텍스트에 따로 저장이 되며 커밋을 실행하게 되면, flush를 통해
쿼리들을 DB에 저장 -&gt; 최종적으로 commit을 하여 DB에 쿼리를 반영.</p>
<ol start="4">
<li>변경 감지
영속성 컨텍스트의 1차 캐시에는 스냅샷을 통해 엔티티의 변경을 감지.
JPA는 1차 캐시에 &quot;DB에서 처음 불러온&quot; 엔티티의 스냅샷을 가지고 있음.</li>
</ol>
<p>1차 캐시에 저장된 엔티티와 스냅샷을 비교 후, 변경 내용이 있다면 UPDATE SQL문을 쓰기 지연 SQL 저장소에 담아둔다.
이후, DB 커밋 시점에 변경 내용을 자동으로 반영.(update 호출이 필요없음)
변경감지는 오직 영속 상태의 엔티티에만 적용.
<img src="https://velog.velcdn.com/images/new_guy/post/5bb3f434-f3fc-48fc-bf66-030802c3bc59/image.png" alt="">
( <a href="https://velog.io/@zxzz45/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91JPA#%EC%98%81%EC%86%8D%EC%84%B1persistence">https://velog.io/@zxzz45/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91JPA#%EC%98%81%EC%86%8D%EC%84%B1persistence</a> )</p>
<h1 id="jpa-사용-이유">JPA 사용 이유</h1>
<ul>
<li><p>SQL 중심 -&gt; 객체지향적</p>
</li>
<li><p>생산성</p>
</li>
<li><p>유지보수성</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/a0928ad4-39a5-479b-885b-b0c2be12e801/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/0a3a031c-3ebc-4065-a845-6b5b1015431d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/9b5a0256-2521-4d01-8de0-4a1fab408955/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/0eedd9c8-3ffb-4c68-9fb4-1ddcd28b1dd3/image.png" alt=""></p>
<p>( <a href="https://velog.io/@zxzz45/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91JPA#jpa%EB%9E%80">https://velog.io/@zxzz45/%EA%B8%B0%EC%88%A0-%EB%A9%B4%EC%A0%91JPA#jpa%EB%9E%80</a> )</p>
<h1 id="jpa-장점">JPA 장점</h1>
<ol>
<li><p>특정 DB에 종속되지 않음.
JPA는 추상화한 데이터 접근 계층을 제공. yml에 어떤 DB를 사용하는지만 알려주면, 해당 DB로 변경 가능.</p>
</li>
<li><p>객체지향 프로그래밍</p>
</li>
<li><p>생산성 향상
DB 테이블에 새로운 컬럼이 추가 -&gt; JPA는 오직 테이블과 매핑된 클래스에 필드만 추가 !
SQL문 직접 작성 대신에 객체를 사용하여 동작함 -&gt; 재사용성 우수.</p>
</li>
<li><p>지연로딩과 즉시로딩</p>
</li>
</ol>
<ul>
<li><p>지연 로딩 : 객체가 실제 사용시에만 로딩</p>
</li>
<li><p>즉시 로딩 : JOIN SQL로 한번에 연관된 객체까지 미리 조회</p>
</li>
</ul>
<h1 id="jpa-단점">JPA 단점</h1>
<ol>
<li><p>복잡한 쿼리 처리
Native SQL을 통해 기존의 SQL문을 사용할 수 있지만, 특정 DB에 종속.
따라서, JPQL을 사용.</p>
</li>
<li><p>성능 저하 위험.
객체 간의 매핑 설계 실패 -&gt; 성능 저하.</p>
</li>
<li><p>동적 쿼리를 사용 -&gt; 가독성이 저하.
QueryDsl로 해결 가능.</p>
</li>
</ol>
<h2 id="jpql">JPQL</h2>
<ul>
<li><p>객체지향 쿼리언어</p>
</li>
<li><p>SQL문과 유사하지만, DB의 테이블에 직접 연결되는 것이 아니라, JPA 엔티티에 대해 동작.
( 테이블이 아닌 엔티티에서 표현하고 있는 컬럼의 이름을 쓴다. )
객체를 검색하는 쿼리.</p>
</li>
</ul>
<h3 id="동작과정">동작과정</h3>
<ol>
<li>JPQL을 실행 -&gt; 영속성 컨텍스트로 요청 전송.</li>
<li>영속성 컨텍스트는 &quot;1차 캐시의 엔티티 존재 여부 상관없이&quot; DB에 질의</li>
<li>DB 질의를 통해 조회된 데이터는 영속성 컨텍스트가 다시 받음.</li>
<li>데이터를 전달받은 영속성 컨텍스트는 엔티티를 초기화 후, 캐시에 저장.</li>
<li>캐시에 저장한 후 -&gt; 엔티티를 반환.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크 면접 대비용]]></title>
            <link>https://velog.io/@new_guy/%EA%B8%B0%ED%83%80-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84</link>
            <guid>https://velog.io/@new_guy/%EA%B8%B0%ED%83%80-%EB%A9%B4%EC%A0%91-%EB%8C%80%EB%B9%84</guid>
            <pubDate>Mon, 19 May 2025 02:46:38 GMT</pubDate>
            <description><![CDATA[<h1 id="1-웹서버">1. 웹서버</h1>
<h2 id="11-웹이란">1.1 웹이란?</h2>
<h3 id="인터넷">인터넷</h3>
<p>인터넷은 여러 통신망을 하나로 연결한다는 의미를 가짐(TCP/IP로 통신).</p>
<h3 id="웹">웹</h3>
<p>인터넷 연결된 사용자 간의 정보 공유 시스템(이미지와 문자를 HTTP로 전송하는 정보시스템)</p>
<h4 id="http">HTTP</h4>
<p>단순한 텍스트를 넘어서 하이퍼링크를 통해서 웹 상에 존재하는 여러 문서나 리소스에 접근을 할 수 있다.</p>
<ul>
<li>상태 정보를 저장하지 않는 Stateless
( 각 요청은 서로 독립적이며, 이전 요청의 상태/정보는 기억 x =&gt; 쿠키,세션,토큰이 필요 )</li>
</ul>
<ul>
<li><p>클라이언트의 요청에 맞는 응답을 보낸 후 연결을 끊는 Connectionless
( HTTP/1.0은 해당이 되지만, HTTP/1.1은 해당이 되지 않음. )</p>
</li>
<li><p>장점
연결 상태 처리, 상태 정보를 관리할 필요 x -&gt; 간단한 디자인, 독립적 응답</p>
</li>
<li><p>단점
매번 인증해야함.</p>
</li>
</ul>
<h2 id="12-cookie-vs-session-vs-token">1.2 Cookie vs. Session vs. Token</h2>
<h3 id="1-cookie-인증">1. Cookie 인증</h3>
<p>{ key : value }
<img src="https://velog.velcdn.com/images/new_guy/post/8e022ee8-1317-4e73-8ceb-ea060db89b88/image.png" alt=""></p>
<ul>
<li><p>보안에 매우 취약 (XSS, 자바스크립트 해킹)</p>
</li>
<li><p>용량 제한</p>
</li>
<li><p>브라우저간 공유가 불가능</p>
</li>
</ul>
<h3 id="2-session-인증">2. Session 인증</h3>
<p>민감한 인증 정보를 브라우저가 아닌 서버 측에 저장/관리
( 핵심 정보는 클라이언트가 아닌 서버에서 모두 관리 )
{
  { key1 :
    creationTime : value1,
    lastAccessedTime : value2,
    userId : value3
  }
  ,
  { key2 :
    creationTime : value4,
    lastAccessedTime : value5,
    userId : value6
  }
}
<img src="https://velog.velcdn.com/images/new_guy/post/0e093554-6d77-4244-b326-16b6e0e768f4/image.png" alt=""></p>
<ol>
<li><p>유저가 웹사이트에서 로그인 -&gt; 세션이 서버 메모리(DB)상에 저장</p>
</li>
<li><p>서버에서 브라우저에 쿠키에다가 Session Id 저장</p>
</li>
<li><p>브라우저는 해당 사이트에 대한 모든 요청에 Session Id를 쿠키에 담아 전송.</p>
</li>
<li><p>서버는 클라이언트가 보내는 Session Id와 서버의 Session id를 비교하여 인증.</p>
</li>
</ol>
<ul>
<li><p>단점</p>
</li>
<li><p>세션 ID 자체를 탈취당하면 보안상 문제( IP 특정을 통해 해결 가능. )</p>
</li>
<li><p>서버에서 세션 저장소를 사용( Stateful ) -&gt; 요청이 많으면 부하가 심화</p>
</li>
</ul>
<h3 id="3-token-인증">3. Token 인증</h3>
<p>인증이 될 경우에만 토큰을 발급.(요청 헤더에 토큰을 심어서 전송)
토큰은 세션과 달리 클라이언트에 저장되기 때문에 용량문제가 적다.
또한 토큰 자체의 위변조 여부만 파악하면 된다.
( 앱에서는 쿠키, 세션이 없음, Stateless함 )</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/179b4b81-c65e-40b5-aa85-4fee9c2fbf32/image.png" alt=""></p>
<ol>
<li><p>사용자 아이디/비밀번호 로그인</p>
</li>
<li><p>서버 측에서 사용자에게 유일한 토큰 발급</p>
</li>
<li><p>클라이언트는 서버 측에서 전달받은 토큰을 쿠키나 스토리지에 저장해 두고,
서버에 요청을 할 때마다 해당 토큰에서 요청 헤더에 포함시켜 전달</p>
</li>
</ol>
<p>4.서버는 전달받은 토큰을 검증하고 요청에 응답</p>
<ul>
<li><p>단점</p>
</li>
<li><p>토큰 자체의 데이터 길이가 길어 -&gt; 인증 요청이 많아질수록 네트워크 부하가 심해짐.</p>
</li>
<li><p>Payload 자체는 암호화가 되지 않음 -&gt; 유저의 중요한 정보를 담을 수 없음</p>
</li>
<li><p>토큰 탈취시, 위험( 따라서 TTL 설정 )</p>
</li>
</ul>
<h4 id="세션-기반-vs-토큰-기반">세션 기반 vs. 토큰 기반</h4>
<p>단일 도메인이라면 세션 기반 인증을 쓰고, 아니면 토큰 기반 인증이 더 적합함.
왜냐하면 도메인별 세션 관리 쿠키가 CORS때문에 관리가 어렵다.</p>
<h3 id="31-jwt-json-web-token-">3.1 JWT( JSON WEB TOKEN )</h3>
<p>인증에 필요한 정보들을 암호화 시킨 JSON 토큰
Base64 Encoding으로 직렬화</p>
<p>구성은 다음과 같음
[ Header.Payload.Signature ]</p>
<ul>
<li><p>Header : JWT에서 사용할 타입 + 해시 알고리즘</p>
</li>
<li><p>Payload : 서버에서 첨부한 사용자 권한 정보 및 데이터</p>
</li>
<li><p>Signature : Header, Payload를 Base64로 Encoding을 한 후 Header에 명신된 해시함수를 적용하고, 개인키로 서명.</p>
</li>
<li><p>장점
: 인증을 위한 별도의 저장소가 필요 없음, stateless</p>
</li>
<li><p>단점
: 토큰의 길이가 늘어날수록 네트워크 부하, Base64 Encoding으로 탈취당하면 데이터 볼 수 있다.</p>
</li>
</ul>
<h4 id="base64-encoding">Base64 Encoding</h4>
<p>Binary Data -&gt; Text로 바꿈.
(Binary Data를 6bit씩 자른 뒤 -&gt; 6bit에 해당하는 문자를 Base64 색인표에서 찾아 치환)
<img src="https://velog.velcdn.com/images/new_guy/post/6707cbd1-8dd2-4e6c-b7dd-601a94afde51/image.png" alt=""></p>
<p>그런데, 모든 binary bit가 6bit씩 끊어지는 것은 아니다.
010011 010110 000101 101110 01110 (01 -&gt; 010000) =&gt; padding 0을 추가해서 6비트로 만든다.
T      W      F      u      e            Q = =</p>
<p>: TWFueQ==</p>
<p>전송해야 될 데이터의 양이 약 33% 증가함. + CPU 연산 추가</p>
<p>binary를 ASCII로 쓸 경우 다음과 같은 문제 발생</p>
<ul>
<li><p>ASCII는 7bit Encoding인데 나머지 1bit를 처리하는 방식이 시스템 별로 다름.</p>
</li>
<li><p>바이너리 -&gt; 텍스트로 전송 :ASCII로 안전하게 인코등 가능</p>
</li>
<li><p>HTTP는 텍스트 기반이므로 문자열로 전송 가능</p>
</li>
<li><p>시스템 간 호환성 문제를 회피.</p>
</li>
</ul>
<h4 id="심화-https">심화 HTTPS</h4>
<p>HTTP + SSL/TLS 프로토콜을 추가한 통신 규약</p>
<ul>
<li><p>데이터 전송의 보안을 강화하기 위해 암호화</p>
</li>
<li><p>비대칭 키를 이용함.</p>
</li>
</ul>
<ol>
<li><p>개인 키
웹 사이트 소유자가 보유</p>
</li>
<li><p>공개 키
여러 클라이언트들이 접근</p>
</li>
</ol>
<h4 id="설정안하면-스니핑데이터-가로챔-도청에-취약">설정안하면, 스니핑(데이터 가로챔, 도청)에 취약</h4>
<pre><code class="language-txt">1. 암호화 전:
완전히 읽을 수 있는 텍스트 문자열입니다

2. 암호화 후:
ITM0IRyiEhVpa6VnKyExMiEgNveroyWBPlgGyfkflYjDaaFf/Kn3bo3OfghBPDWo6AfSHlNtL8N7ITEwIXc1gU5X</code></pre>
<h4 id="tls-핸드셰이크">TLS 핸드셰이크</h4>
<p>SSL 인증서 보안 기술은 다음과 같다.</p>
<ul>
<li><p>대칭키</p>
</li>
<li><p>비대칭키
개인키 없이 절대로 복호화가 불가능.
&quot;공개키로 암호화 -&gt; 개인키로 복호화.&quot;</p>
</li>
<li><p>인증(authentication)</p>
</li>
<li><p>디지털 서명과 이를 수행하는 인증기간(CA)</p>
</li>
<li><p>공개키를 안전하게 전달하는 프로토콜</p>
</li>
<li><p>위변조 확인하는 메시지 무결성 알고리즘.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/d2c24564-5890-4315-a6bd-26fa6fa3a283/image.png" alt="">
(<a href="https://www.cloudflare.com/ko-kr/learning/ssl/what-happens-in-a-tls-handshake/">https://www.cloudflare.com/ko-kr/learning/ssl/what-happens-in-a-tls-handshake/</a>)</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/bb3f57ea-4904-4209-a1ae-a516732f3966/image.png" alt="">
(<a href="https://brunch.co.kr/@sangjinkang/38">https://brunch.co.kr/@sangjinkang/38</a>)</p>
<p>(2)에서 서버의 공개키가 담긴 SSL 인증서를 응답하는데,
이때 CA의 비밀키로 암호화된 상태임.</p>
<p>(3)대부분 브라우저는 CA가 있으므로, 내장 CA 공개키로 암호화된 인증서를 복호화를 한다.
(만약에 실패하면, 브라우저 경고 발생)</p>
<p>(4)SSL 인증서에서 딸려노 공개키로 암호화해서 서버로 전송.</p>
<p>(5)서버는 자기 비밀키로, 브라우저가 보낸 값을 복호화</p>
<p>(6)SSL handshake를 종료하고, HTTPS 통신 시작</p>
<h2 id="2-브라우저">2. 브라우저</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/02a2e783-c457-4993-b1a4-7d6d4b43fc9f/image.png" alt="">
(<a href="https://velog.io/@wlwl99/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EA%B5%AC%EC%A1%B0">https://velog.io/@wlwl99/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EA%B5%AC%EC%A1%B0</a>)</p>
<ol>
<li>사용자</li>
</ol>
<p>브라우저에 URL 주소 입력
URL 파싱(프로토콜/도메인/포트)</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/0f4e9279-7557-43bc-92c7-683a87ce5dc0/image.png" alt=""></p>
<p>참고 )
프로토콜, 호스트, 포트 이 3개가 같아야 동일 출처 정책(Same-Origin Policy)이다.</p>
<h4 id="cors">CORS</h4>
<p>출처가 다른 도메인에서의 AJAX 요청이라도 서버 단에서 데이터 접근 권한을 허용.
(서버 단에서 특정 도메인을 허용해주면 된다.)</p>
<ol start="2">
<li>DNS 서버</li>
</ol>
<p>사용자가 입력한 URL 중 도메인 네임을 검색하고,
도메인 네임에 일치하는 주소를 찾아, 사용자가 입력한 URL정보와 함께 전달.
(DNS응답으로 IP주소를 받는다.)</p>
<p>&quot;브라우저&quot;는 DNS로부터 응답받은 IP주소를 캐싱한다.
그리고 사용자가 URL 입력 시, 브라우저는 먼저 캐싱된 데이터 중에서
해당 도메인에 해당하는 IP 주소가 있는지 부터 확인.</p>
<p>만약에 캐시미스이면, DNS에 IP주소를 요청한다.</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/e44de093-1512-43e6-a712-ec71504bfc6c/image.png" alt="">
(<a href="https://velog.io/@gyumin_2/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%A3%BC%EC%86%8C%EC%B0%BD%EC%97%90-URL-%EC%9E%85%EB%A0%A5-%EC%8B%9C-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EA%B3%BC%EC%A0%95-%EB%B0%B1%EC%97%94%EB%93%9C-%ED%8E%B8">https://velog.io/@gyumin_2/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%A3%BC%EC%86%8C%EC%B0%BD%EC%97%90-URL-%EC%9E%85%EB%A0%A5-%EC%8B%9C-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EA%B3%BC%EC%A0%95-%EB%B0%B1%EC%97%94%EB%93%9C-%ED%8E%B8</a>)</p>
<ul>
<li><p>Local DNS(ISP가 제공)
LAN 연결 시, 통신사가 공인 IP를 할당하는데, 각 통신사의 DNS서버가 등록되어 있다.</p>
</li>
<li><p>Root DNS
Local DNS가 IP를 조회할 때 가장 먼저 요청하는 DNS</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/f2ed07fe-eb7d-49c4-8a95-bd21af1fd1e2/image.png" alt=""></p>
<h4 id="과정">과정</h4>
<p>우리가 주소창에 domain.co.kr 을 입력했다고 가정할 때 아래의 과정을 통해 IP 주소가 조회됩니다.</p>
<ol>
<li><p>브라우저는 먼저 Local DNS에 domain.co.kr 에 해당하는 IP 주소를 요청합니다.</p>
</li>
<li><p>Local DNS에는 해당 도메인에 대한 정보가 있을 수도 있고 없을 수도 있습니다. 만약 Local DNS에 해당 도메인에 대한 IP 주소가 있다면 브라우저에게 응답하고, 없으면 Local DNS는 루트 DNS에게 해당 도메인의 IP를 요청합니다.</p>
</li>
<li><p>루트 DNS는 해당 도메인 IP 정보를 갖고 있다면 Local DNS에 응답하고, 없다면 어떤 DNS에 요청해야 하는지를 알려줍니다. domain.co.kr 를 예로들면 루트 DNS는 .kr 도메인을 관리하는 DNS에 물어보라고 Local DNS에 응답합니다.</p>
</li>
<li><p>Local DNS는 .kr 도메인을 관리하는 DNS에 IP 주소 요청을 하고, .kr 도메인을 관리하는 DNS는 해당 IP 정보를 갖고 있다면 해당 IP 주소를 Local DNS에 응답하고, 없다면 .co.kr 도메인을 관리하는 DNS에 물어보라고 응답합니다.</p>
</li>
<li><p>Local DNS는 .co.kr 도메인을 관리하는 DNS에 IP 주소 요청을 하고, .co.kr 도메인을 관리하는 DNS는 해당 IP 정보를 갖고 있다면 해당 IP 주소를 Local DNS에 응답하고, 없다면 domain.co.kr 도메인을 관리하는 DNS에 물어보라고 응답합니다.</p>
</li>
<li><p>Local DNS는 domain.co.kr 도메인을 관리하는 DNS에 IP 주소 요청을 하고, domain.co.kr 도메인을 관리하는 DNS는 Local DNS에 해당 도메인의 IP 주소를 응답합니다.</p>
</li>
<li><p>이를 수신한 Local DNS는 domain.co.kr 도메인에 대한 IP 주소를 캐싱하고, IP 주소를 브라우저에게 응답합니다.</p>
</li>
</ol>
<p>이와 같이 Local DNS 서버가 루트 DNS를 시작으로 하위 도메인을 관리하는 DNS에게 요청하여 IP주소를 찾는 과정을 Recursive Query라고 부릅니다. 그리고 IP 주소를 찾는 과정이 이렇게 길고 복잡하기 때문에 브라우저는 IP 주소를 캐싱합니다.</p>
<h4 id="---kr---cokr---domaincokr-순서">. -&gt; .kr -&gt; .co.kr -&gt; domain.co.kr (순서)</h4>
<ol start="3">
<li><p>HTTP 프로토콜
전달 받은 IP주소와 웹 페이지 URL 정보는 HTTP 프로토콜을 사용해 HTTP 요청 메시지를 생성</p>
</li>
<li><p>TCP/IP 프로토콜
앞선 HTTP 메시지는 TCP 프로토콜에 의해서 인터넷을 거쳐 해당 IP 컴퓨터로 전송되고,
도착한 HTTP 메시지는 HTTP 프로토콜을 이용해 웹 페이지 URL 정보로 변환</p>
</li>
<li><p>웹 서버
변환된 정보에 해당하는 데이터를 검색하여 찾아낸 뒤, HTTP 응답 메시지를 생성
(TPC를 사용해 인터넷을 거쳐 사용자의 컴퓨터로 전송 및 도착한 HTTP 메시지는 웹 페이지 데이터로 변환)</p>
</li>
<li><p>웹 브라우저
변환된 데이터가 웹 브라우저에 출력됨.</p>
</li>
</ol>
<h2 id="웹-서버-vs-was">웹 서버 vs WAS</h2>
<p><img src="https://velog.velcdn.com/images/new_guy/post/5aed4117-da91-47f8-b9e5-3b848a970906/image.png" alt="">
(<a href="https://velog.io/@gyumin_2/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%A3%BC%EC%86%8C%EC%B0%BD%EC%97%90-URL-%EC%9E%85%EB%A0%A5-%EC%8B%9C-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EA%B3%BC%EC%A0%95-%EB%B0%B1%EC%97%94%EB%93%9C-%ED%8E%B8">https://velog.io/@gyumin_2/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC-%EC%A3%BC%EC%86%8C%EC%B0%BD%EC%97%90-URL-%EC%9E%85%EB%A0%A5-%EC%8B%9C-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EA%B3%BC%EC%A0%95-%EB%B0%B1%EC%97%94%EB%93%9C-%ED%8E%B8</a>)</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/9e461ee5-a8d4-43a6-991f-038ff235860b/image.png" alt=""></p>
<ol>
<li><p>정적 페이지( 웹서버 )
클라이언트가 요청을 보내면 서버는 미리 저장된 웹 페이지를 반환한다.
(정적 콘텐츠 반환)
Apache, NGINX</p>
</li>
<li><p>동적 페이지( WAS = 웹서버 + 웹컨테이너(JSP,Servlet 실행 가능한 소프트웨어) )
클라이언트에게 요청을 받은 후 서버에 의해 추가적인 처리 과정을 거쳐 응답된 페이지를 의미
(매번 다른 결과)
또한, 웹 서버가 단독으로 처리하기 어려운 DB조회 및 다양한 비즈니스 로직을 처리해 동적 페이지를 제공
Tomcat</p>
</li>
</ol>
<h4 id="웹-서버와-was-분리">웹 서버와 WAS 분리</h4>
<p>WAS는 정적 콘텐츠 처리 못하는 것이 아니라! 정적인 콘텐츠 + 동적 콘텐츠 모두 처리한다.</p>
<p>WAS는 DB 조회나 프로그래밍 로직 처리도 같이 하므로 부하가 크다.</p>
<p>따라서, 트래픽이 많다면 WAS 앞에 웹 서버 1개 두어 정적인 요청은 웹 서버가 처리하도록 하는 것이 좋다.
(NGINX 웹 콘텐츠 캐싱)</p>
<h1 id="2-tcp-vs-udp">2. TCP vs. UDP</h1>
<h2 id="21-tcpip">2.1 TCP/IP</h2>
<p>[ TCP 특정 ]</p>
<ul>
<li><p>연결 지향 방식으로 &quot;패킷&quot; 교환 방식 사용</p>
</li>
<li><p>3-way handshaking으로 연결, 4-way handshaking을 통해 해제</p>
</li>
<li><p>흐름 제어 및 혼잡 제어</p>
</li>
<li><p>높은 신뢰성을 보장</p>
</li>
<li><p>UDP보다 느림</p>
</li>
<li><p>Full-Duplex, Point to Point 방식</p>
</li>
</ul>
<h3 id="4-way-handshaking">4-way handshaking</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/dd917e0c-aae1-4696-b944-21e7add31c66/image.png" alt=""></p>
<ol>
<li>step 1 : 클라이언트 - (FIN) -&gt; 서버</li>
</ol>
<ul>
<li>클라이언트가 서버에게 연결 종료를 요청하는 FIN 세그먼트 전송</li>
</ul>
<ol start="2">
<li>step 2 : 클라이언트 &lt;- (ACK) - 서버</li>
</ol>
<ul>
<li><p>서버는 FIN을 받고, ACK을 클라이언트에게 보내고 자신의 통신이 끝날때까지 기다린다.</p>
</li>
<li><p>아직 남은 데이티가 있다면 마저 전송을 마친 후 close()</p>
</li>
<li><p>클라이언트는 ACK을 받은 후 서버가 남은 데이터 처리를 끝내고 FIN 패킷을 보낼 때까지 기다린다.(FIN_WAIT_2)</p>
</li>
</ul>
<ol start="3">
<li>step 3 : 클라이언트 &lt;- (FIN) - 서버</li>
</ol>
<ul>
<li><p>서버가 데이터를 모두 보냈다면 -&gt; 연결 종료에 합의 한다는 의미로 FIN을 역으로 전송</p>
</li>
<li><p>ACK을 받을 때까지 기다리는 LAST_ACK 상태</p>
</li>
</ul>
<ol start="4">
<li>step 4 : 클라이언트 - (ACK) -&gt; 서버</li>
</ol>
<ul>
<li><p>클라이언트는 FIN을 받고, 응답 ACK을 서버에게 전송.</p>
</li>
<li><p>서버는 TIME_WAIT을 통해서 대기</p>
</li>
</ul>
<h4 id="만약-서버가-ack을-받으면-closed---time_wait이-끝나면-클라이언트도-closed">만약 서버가 ACK을 받으면, Closed -&gt; TIME_WAIT이 끝나면 클라이언트도 Closed</h4>
<h3 id="연결-지향-vs-비연결-지향">연결 지향 vs. 비연결 지향</h3>
<ol>
<li>연결 지향( TCP )</li>
</ol>
<ul>
<li><p>통신 연결을 유지</p>
</li>
<li><p>연결을 계속 유지 -&gt; 비용이 비쌈.</p>
</li>
<li><p>이미 연결이 된 상태이므로, 상대방을 알 수 있음.
( 송수신자 간 먼저 연결이 설정된 후, 데이터 전송 )</p>
</li>
<li><p>서버와 클라이언트 1:1</p>
</li>
<li><p>스트림 전송으로 전송 데이터의 크기가 무제한</p>
</li>
<li><p>스프리밍 서비스에 불리.( 손실된 경우 재전송 요청 )</p>
</li>
</ul>
<h4 id="연속성보다-신뢰성-있는-전송이-중요할-떄-사용하는-프로토콜">연속성보다 신뢰성 있는 전송이 중요할 떄 사용하는 프로토콜.</h4>
<ol start="2">
<li>비연결 지향( UDP )
데이터를 데이터그램( 독립적인 관계를 지닌 패킷 ) 단위로 처리하는 프로토콜</li>
</ol>
<ul>
<li><p>통신 연결 유지 x</p>
</li>
<li><p>연결 유지 x -&gt; 싸다.</p>
</li>
<li><p>매번 새롭게 연결이 성립 -&gt; 매 연결 시 자신이 누구인지 알려줘야.</p>
</li>
</ul>
<p>HTTP =&gt; stateless, connectionless( 비연결 )</p>
<p>TCP =&gt; 연결지향 프로토콜</p>
<ul>
<li><p>연결 설정이나 해제의 필요 없이 한쪽에서 일방적으로 전송.</p>
</li>
<li><p>신뢰성이 낮다.
( TCP와 달리, 패킷에 순서를 부여하여 재조립을 하거나 흐름 제어, 혼잡 제어가 없다. )</p>
</li>
</ul>
<h4 id="신뢰성보다는-연속성이-중요한-서비스에-적용">신뢰성보다는 연속성이 중요한 서비스에 적용</h4>
<ul>
<li><p>연결 자체가 없다 -&gt; 서버 소켓, 클라이언트 소켓 구분 X</p>
</li>
<li><p>소켓을 활용하되 IP,PORT 기반으로 데이터 전송</p>
</li>
<li><p>서버 : 클라이언트 = 1:N, N:M, 1:1 등 가능.</p>
</li>
</ul>
<h4 id="흐름제어-및-혼잡제어">흐름제어 및 혼잡제어</h4>
<ul>
<li><p>흐름제어
: 데이터 송수신하는 곳의 데이터 처리 속도를 조절하여 수신자의 버퍼 오버플로우 방지.</p>
</li>
<li><p>혼잡제어
네트워크 내의 패킷 수가 넘치게 증가하지 않도록 방지.</p>
</li>
</ul>
<h1 id="osi-7계층">OSI 7계층</h1>
<p><img src="https://velog.velcdn.com/images/new_guy/post/d4715733-62d6-42ed-b999-85f0cddd9bd1/image.png" alt=""></p>
<ul>
<li><p>7 계층(응용 계층) : 사용자에게 통신을 위한 서비스 제공. 인터페이스 역할</p>
</li>
<li><p>6 계층(표현 계층) : 데이터의 형식(Format)을 정의하는 계층 (코드 간의 번역을 담당)</p>
</li>
<li><p>5 계층(세션 계층) : 컴퓨터끼리 통신을 하
기 위해 세션을 만드는 계층</p>
</li>
<li><p>4 계층(전송 계층) : 최종 수신 프로세스로 데이터의 전송을 담당하는 계층 (단위 :Segment) (ex. TCP, UDP)</p>
</li>
<li><p>3 계층(네트워크 계층) : 패킷을 목적지까지 가장 빠른 길로 전송하기 위한 계층 (단위 :Packet) (ex. Router)</p>
</li>
<li><p>2 계층(데이터링크 계층) : 데이터의 물리적인 전송과 에러 검출, 흐름 제어를 담당하는 계층 (단위 :frame) (ex. 이더넷)</p>
</li>
<li><p>1 계층(물리 계층) : 데이터를 전기 신호로 바꾸어주는 계층 (단위 :bit) (장비: 케이블,리피터,허브)</p>
</li>
</ul>
<p>출처: <a href="https://dev-coco.tistory.com/161">https://dev-coco.tistory.com/161</a> [슬기로운 개발생활:티스토리]</p>
<h2 id="http-method">HTTP Method</h2>
<ul>
<li><p>GET : 데이터 조회
URL에 데이터가 노출 -&gt; 보안적으로 중요한 데이터 포함 X</p>
</li>
<li><p>POST : 데이터 등록
Body에 데이터를 포함. GET보다 안정.</p>
</li>
<li><p>PUT : 데이터 변경</p>
</li>
<li><p>PATCH : 일부 데이터만 변경</p>
</li>
<li><p>DELETE : 데이터 삭제</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Java]]></title>
            <link>https://velog.io/@new_guy/Java</link>
            <guid>https://velog.io/@new_guy/Java</guid>
            <pubDate>Wed, 07 May 2025 05:22:01 GMT</pubDate>
            <description><![CDATA[<h1 id="1-java-개념과-기초원리">1. Java 개념과 기초원리</h1>
<h1 id="jdk-vs-jre">JDK vs JRE</h1>
<p><img src="https://velog.velcdn.com/images/new_guy/post/ee2f33f6-c12c-4cb6-a942-f40a3abbe41e/image.png" alt=""></p>
<ul>
<li><p>JDK : &quot;JAVA 개발 키트&quot; = &quot;SDK(Software Development Kit) 키트&quot; = &quot;라이브러리 + javac + javadoc&quot;</p>
</li>
<li><p>JRE : JAVA Runtime Enviroment, JVM과 자바 프로그램을 실행시킬 때 필요한 라이브러리.</p>
</li>
</ul>
<p>Java프로그램을 개발 -&gt; JDK 필요, 컴파일 된 Java프로그램을 실행 -&gt; JRE 필요.</p>
<h2 id="1-java-vs-c언어">1. Java vs C언어</h2>
<h3 id="11-java">1.1 Java</h3>
<p>객체지향 프로그래밍 언어로, 객체간 비즈니스 로직을 이용해서 도메인 문제를 해결을 한다.</p>
<p>JVM 가상 머신에 작동하며, GC에 의해서 메모리 관리가 C언어보다 유용하다.</p>
<h3 id="12-c">1.2 C</h3>
<p>절차지향적 언어로, 함수형 프로그래밍 언어다.
메모리를 직접 malloc, free를 통해서 관리를 해야만 한다.</p>
<h3 id="13-절차지향-vs-객체지향">1.3 절차지향 vs 객체지향</h3>
<p>절차지향 언어는 주로 트랜잭션 스크립트 방식으로 구성됩니다. 즉, 프로그램의 흐름을 순차적인 함수 호출로 구성하며, 로직이 코드 상에 나열되는 형태입니다. 모든 처리는 데이터를 중심으로 함수가 작동하는 구조이며, 데이터와 로직이 분리되어 있습니다.</p>
<p>반면, 객체지향 언어는 객체에 상태와 행위를 함께 부여하고, 각 객체가 책임을 가지고 상호작용함으로써 문제를 해결합니다. 즉, 비즈니스 로직을 객체에 담아 도메인 중심으로 모델링할 수 있어, 코드의 재사용성과 확장성, 유지보수가 유리합니다.</p>
<h2 id="14-객체지향의-설계원칙">1.4 객체지향의 설계원칙</h2>
<h4 id="solid">SOLID</h4>
<ol>
<li><p>SRP(Single Responsibility Principle), 단일 책임 원칙
한 클래스는 하나의 책임만 가져야 한다.</p>
</li>
<li><p>OCP(Open Closed Principle), 개방 폐쇄 원칙
확장에는 열려있고, 수정에는 닫혀있다.</p>
</li>
<li><p>LSP(Listov Substitution Principle), 리스코프 치환 원칙
하위 타입은 항상 상위 타입을 대체 할 수 있어야 한다.</p>
</li>
<li><p>ISP(Interface Segregation Principle), 인터페이스 분리 원칙
인터페이스 내에 메소드는 최소한 일수록 좋다.(하나의 일반적인 인터페이스보다 여러 개의 구체적인 인터페이스와 낫다.)SRP와 같은 문제에 대한 두 가지 다른 해결책이다.</p>
</li>
<li><p>DIP(Dependency Inversion Principle), 의존관계 역전 원칙
구체적인 클래스보다 인터페이스에 의존한다.</p>
</li>
</ol>
<h4 id="객체지향-4대-원칙">객체지향 4대 원칙</h4>
<ol>
<li><p>추상화 ex). 추상 클래스, 인터페이스
공통성과 본질을 모아 추출 = 모듈화</p>
</li>
<li><p>상속
기존의 클래스를 재활용하여 새로운 클래스 작성.
( 상위 클래스를 상속한 모든 하위 클래스는 상위 클래스의 속성을 사용할 수 있음. )</p>
</li>
<li><p>다형성 ex). 오버라이딩, 오버로딩
어떤 객체의 속성이나 기능이 상황에 따라 여러 가지 형태를 가질 수 있음.</p>
</li>
<li><p>캡슐화
서로 연관 있는 속석와 기능들을 하나의 캡슐로 만들어 외부로부터 보호</p>
</li>
</ol>
<p>캡슐화는 클래스 안에다가 데이터와 데이터를 처리하는 행위를 묶어 놓는 것</p>
<p>코드의 중복을 피할 수 있다는 점과, 데이터를 처리하는 동작 방식을 외부에서 알 필요가 없다는 점</p>
<ul>
<li><p>데이터 보호</p>
</li>
<li><p>데이터 은닉</p>
</li>
</ul>
<h2 id="2-jvm">2. JVM</h2>
<p>OS에 종속받지 않고 Java를 실행할 수 있다.
<img src="https://velog.velcdn.com/images/new_guy/post/69db88a7-d5f3-443d-899a-6e048b7719aa/image.png" alt="">
.java 원시코드를 컴파일러가 .class의 바이트 코드로 변환을 한다.
그 이후 JVM이 .bytecode를 기게어로 바꿔준다.
( 컴파일 + 인터프리터 )</p>
<p>그러나 요즘은 JIT Compiler가 추가되었다.</p>
<h3 id="21-클래스는-언제-초기화-로딩">2.1 클래스는 언제 초기화? 로딩?</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/88a098f5-1c34-4b38-894a-a8e156d51a02/image.png" alt=""></p>
<p>.class 파일을 로드한다. 클래스와 클래스 로더의 참조가 더 이상 존재하지 않아야만 GC의 대상이 된다.</p>
<p>ContextClassLoader를 사용하면,
부모 클래스 로더부터 계층적으로 탐색하는 기본 방식(Parent Delegation)을 따르지 않고,
내가 설정한 ContextClassLoader부터 탐색을 시작할 수 있게 됩니다.</p>
<h4 id="211-클래스-로드-시점">2.1.1 클래스 로드 시점</h4>
<p><img src="https://velog.velcdn.com/images/new_guy/post/3052f9f5-950a-4a27-89bc-e2b54c6f4921/image.png" alt="">
( <a href="https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93">https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93</a> )</p>
<h3 id="동적-로딩">&quot;동적 로딩&quot;</h3>
<p>클래스 내의 멤버를 호출하게 되면 그때서야 클래스가 동적으로 메모리에 로드된다.</p>
<ol>
<li><p>로딩
: 클래스 파일을 가져와서 JVM의 메소드 영역에 로드</p>
</li>
<li><p>링킹
: 클래스 파일을 사용하기 위해 검증</p>
</li>
<li><p>초기화
: 클래스 변수들을 적절한 값으로 초기화를 한다.
( static 변수에 코드로 작성된 값 할당, static 블록 실행. )</p>
</li>
</ol>
<p>-&gt; 초기화 시점은 클래스가 실제로 &#39;사용될 때&#39; 발생.</p>
<h4 id="222-클래스-초기화-시점">2.2.2 클래스 초기화 시점</h4>
<ol>
<li><p>클래스의 인스턴스 생성</p>
</li>
<li><p>클래스의 정적 메소드 호출</p>
</li>
<li><p>클래스의 정적 변수 할당</p>
</li>
<li><p>클래스의 정적 변수 사용(final x)</p>
</li>
</ol>
<h4 id="사실-클래스-초기화는-클래스-로드와-거의-동시에-일어난다">사실 클래스 초기화는 클래스 로드와 거의 동시에 일어난다.</h4>
<p>클래스 초기화 작업은 오직 한번만 이행된다.
(멀티 스레드 환경에서도 클래스 초기화는 오직 한 번만 수행!)</p>
<p>이를 통해서 클래스 초기화 동작 자체는 스레드 세이프함!</p>
<h3 id="22-가비지-컬렉션garbage-collection">2.2 가비지 컬렉션(Garbage Collection)</h3>
<p>동적으로 할당된 메모리 영역 중에서 필요가 없어진 메모리 영역을 회수하여 메모리를 관리해주는 기법</p>
<h4 id="--힙-메모리-구조">- 힙 메모리 구조</h4>
<ol>
<li>Young(Minor GC)</li>
</ol>
<ul>
<li><p>새롭게 생성된 객체가 할당</p>
</li>
<li><p>대부분의 객체는 금방 Unreachable -&gt; 많은 객체가 Young에서 사라진다.</p>
</li>
</ul>
<ol start="2">
<li>Old(Major GC)</li>
</ol>
<ul>
<li><p>Young에서 Reachable 상태를 유지하여 살아남은 객체가 복사되는 영역</p>
</li>
<li><p>Young 보다 크며, GC는 적게 발생한다.</p>
</li>
</ul>
<h4 id="--동작-방식">- 동작 방식</h4>
<ol>
<li><p>Stop the world
GC를 실행하는 쓰레드를 제외한 모든 쓰레드들의 작업이 중단되고, GC가 완료되면 작업이 재개된다.
(튜닝은 주로 stop-the-world를 줄이는 작업으로 진행한다.)</p>
</li>
<li><p>Mark and Sweep
<img src="https://velog.velcdn.com/images/new_guy/post/cc742dea-d840-4c9b-a4bc-cdbe7d34d75f/image.png" alt=""></p>
</li>
</ol>
<h4 id="단편화가-발생해서-비추천-재배치를-안함">단편화가 발생해서 비추천, 재배치를 안함!</h4>
<ul>
<li><p>Mark
사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업</p>
</li>
<li><p>Sweep
사용되지 않음으로 식별된 메모리를 해제하는 작업</p>
</li>
</ul>
<p>Stop The World를 통해 모든 작업을 중단시키면, GC는 스택의 모든 변수, Reachable 객체를 스캔하면서 각각이 어떤 객체를 참고하고 있는지를 탐색한다.</p>
<p>여기서 Mark가 되지 않는 객체들을 메모리에서 제거하는데, 이를 Sweep이라고 한다.</p>
<h4 id="--gc-동작-방식--copying-gc-">- GC 동작 방식 ( Copying GC )</h4>
<p>: 기존 Mark and sweep은 참조하지 않는 객체를 다 찾아야 해서 비용이 비쌈.
그래서, active와 in-active로 구분지어서 참조하는 것을 active로 옮긴 다음, inactive 내 garbage를 다 지운다.</p>
<p>연속된 메모리 공간에 차곡차곡, 재배열이 되기에 캐시 효율이 높아진다.</p>
<h4 id="1-minor-gc">1. Minor GC</h4>
<p>Young = Eden×1 + Survivor×2</p>
<ul>
<li><p>Eden : 새로 생성된 객체가 할당되는 영역,</p>
</li>
<li><p>Survivor : 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역</p>
</li>
</ul>
<ol>
<li><p>새로 생성된 객체가 Eden영역에 할당</p>
</li>
<li><p>Eden 영역이 가득찬 경우, Minor GC가 발생
Eden 영역에서 사용되지 않는 객체의 메모리가 해제됨 -&gt;
Eden 영역에서 살아남은 객체는 1개의 Survivor 영역으로 이동
(반복)</p>
</li>
<li><p>1~2 과정이 반복되다가 Survivor 영역이 가득 차면, Survivor 영역의 살아남은 객체를 다른 Survivor 영역으로 이동시킨다.
또한, Survivor 영역을 왕래하면서 age가 증가하는데, 임계치를 넘거야 old로 넘어간다.
(1개의 Survivor 영역은 반드시! 빈 상태가 되어야 한다.)</p>
</li>
<li><p>이 과정이 반복되어도 살아남은 객체는 Old로 이동한다.</p>
</li>
</ol>
<h4 id="survivor-영역-중-1개는-반드시-사용되어야-하면-만약-두-survivor-영역에-모두-데이터가-존재하거나-모두-사용량이-0이라면-시스템에-문제가-있다">Survivor 영역 중 1개는 반드시 사용되어야 하면, 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 모두 사용량이 0이라면 시스템에 문제가 있다.</h4>
<h4 id="2-major-gcfull-gc">2. Major GC(Full GC)</h4>
<p>Young에서 오래 살아남은 객체는 Old 영역으로 승급한다.
Major GC는 Old 영역의 메모리가 부족해지면 발생.
(Minor GC는 0.5~1s에 끝나서 빠름.)</p>
<h3 id="23-jvm-메모리-구조">2.3 JVM 메모리 구조</h3>
<p><img src="https://velog.velcdn.com/images/new_guy/post/97531f34-ef0d-4f57-9181-0c717b2ce0d4/image.png" alt=""></p>
<ol>
<li><p>메소드(static) 영역
JVM이 .class를 읽은 후 생성한 클래스에 대한 정보(바이트 코드)를 메서드 영역에 저장한다.
클래스 변수(static 변수), 멤버 변수(필드), 생성자, 메소드 등이 저장된다.
(프로그램의 시작~종료까지 메모리에 남아있다.)</p>
</li>
<li><p>스택(Stack) 영역, LIFO
메소드가 호출시, 스택 영역에 스택 프레임이 생기고, 그안에 메소드를 호출
원시타입, 지역변수, 매개 변수가 저장
메소드가 호출 시, 메모리에 할당되고 종료되면 메모리에서 사라짐</p>
</li>
</ol>
<p>참고로, 스택 프레임은 하나의 메소드당 1개씩 생성이 된다.</p>
<ol start="3">
<li>힙 영역,
new로 생성된 인스턴스, 배열 등이 힙에 저장되며, 가비지 컬렉션 대상이다.(단, 레퍼런스 변수는 stack에 적재된다.)
해당 객체의 참조를 상실해야만, GC에 의해서 메모리 청소가 발생한다.</li>
</ol>
<h4 id="요약">요약</h4>
<ul>
<li><p>힙 메모리는 애플리케이션 모든 부분에 사용되지만, 스택 메모리는 스레드당 1개씩 개별적인 영역을 할당 받는다.</p>
</li>
<li><p>객체가 생성되면 힙 공간에 저장되며, 스택 메모리는 힙 공간의 객체를 참조만 한다.(참조 변수)</p>
</li>
<li><p>스택 메모리 사이즈는 힙 메모리에 비해 매우 작으나, LIFO를 써서 힙 메모리보다 빠르다.</p>
</li>
</ul>
<h2 id="3-java의-데이터-타입">3. Java의 데이터 타입</h2>
<h3 id="1-원시-타입">1. 원시 타입</h3>
<ul>
<li><p>정수형
byte(1)
short(2)
int(4)
long(8)</p>
</li>
<li><p>실수형
float(4)
double(8)</p>
</li>
<li><p>문자형
char(2)</p>
</li>
<li><p>논리형
boolean(1)</p>
</li>
</ul>
<ol start="2">
<li>참조 타입
참조 타입은 힙 메모리의 객체를 참조하고 있으며, GC의 대상이다.</li>
</ol>
<h3 id="2-클래스">2. 클래스</h3>
<h4 id="클래스와-객체">클래스와 객체</h4>
<p>클래스는 객체를 생성하기 위한 설계도이고, 이 객체를 메모리에 할당을 한 것이 객체(인스턴스)이다.</p>
<h4 id="오버라이딩-vs-오버로딩">오버라이딩 vs 오버로딩</h4>
<p>오버라이딩은 하위 클래스에서 상위 클래스의 메소드를 재정의 하는 것을 의미하고,
오버로딩은 매개변수의 개수,타입을 달리하여 같은 이름의 메소드를 여러 개 정의하는 것을 의미한다.</p>
<h4 id="생성자란-무엇인가">생성자란 무엇인가</h4>
<p>클래스로 객체를 생성하기 위해서는 생성자를 이용하는데,
기본 생성자를 이용하며, 오버로딩을 통해서 매개변수 생성자도 만들 수 있다.</p>
<h4 id="추상-클래스-vs-인터페이스">추상 클래스 vs 인터페이스</h4>
<ol>
<li>공통점</li>
</ol>
<ul>
<li><p>추상 메소드를 가지고 있어야 한다.</p>
</li>
<li><p>new 생성자 사용 X</p>
</li>
<li><p>구현체를 통해서 인스턴스 생성이 가능하다.</p>
</li>
<li><p>인터페이스와 추상클래스를 구현한 클래스는 추상 메소드를 반드시 구현해야 한다.</p>
</li>
</ul>
<ol start="2">
<li>차이점</li>
</ol>
<ul>
<li><p>인터페이스(자유로운 타입 묶음)
다중 상속이 가능하다
동작이 필요한 클래스에만 따로 상속에 구애받지 않고 묶음이 가능하다.
클래스와 별도로 구현 객체가 같은 동작을 한다는 것을 보장
기능 구현
그때 그때 필요에 따라 구현해서 자유롭게 알맞게 사용</p>
</li>
<li><p>추상클래스(논리적인 타입 묶음)
단일 상속
클래스간의 연관 관계를 구축
자신의 기능들을 하위 클래스로 확장
&quot;공통&quot; 중복 멤버 통합
미리 논리적인 클래스 상속 구조를 만들어 놓고 사용</p>
</li>
</ul>
<h3 id="3-싱글톤-패턴">3. 싱글톤 패턴</h3>
<p>단 하나의 유일한 객체를 만들기 위한 코드 패턴이며, 똑같은 인스턴스를 새로 만들지 않고 기존의 인스턴스를 가져와 활용한다.
주로 그 객체가 리소스를 많이 차지하는 경우에 사용을 한다.
(디스크 연결, 네트워크 통신, 커넥션풀, 스레드풀, 캐시 등...)</p>
<h3 id="4-string">4. String</h3>
<ol>
<li>new String() vs. 리터럴 &quot;&quot;
new String은 new를 사용하므로 Heap 메모리 영역에 저장되고,
&quot;&quot;는 Heap 안에 String Constant Pool영역에 저장된다.
<img src="https://velog.velcdn.com/images/new_guy/post/278e1049-5dd4-4a03-8137-08ac4f8e2461/image.png" alt=""></li>
</ol>
<p>메소드 내에서 동일한 문자열을 생성할 경우 해당 객체들은 String Constan Pool 내의 동일한 객체를 바라본다.</p>
<p>하지만, new 연산자를 사용할 경우 Heap에서 서로 다른 객체를 생성한다.</p>
<ol start="2">
<li>String, StringBuilder, StringBuffer</li>
</ol>
<ul>
<li>String</li>
</ul>
<p>String은 immutable(불변)하다.
( 단순한 경우, 굳이 StringBuffer, StringBuilder를 사용할 필요없이 +연산자를 사용하면 된다. )</p>
<p>+연산자를 사용할 경우, 기존 문자열에 새로운 문자열을 붙이는 것이 아니라, 새로운 String 객체를 만든 후, 새 String 객체에 연결된 문자열을 저장하고, 그 객체를 참조하도록 한다.</p>
<p>따라서, 문자열 연산이 많은 경우 최악이지만, Thread-safe하다.</p>
<ul>
<li>StringBuffer와 StringBuilder
문자열 연산 등으로 기존 객체의 공간이 부족하게 되면, 기존 버퍼 크기를 늘려 유연하게 동작한다.</li>
</ul>
<p>StringBuffer는 각 메소드별로 Synchronized Keyword가 존재하여, 멀티스레드 환경에서도 동기화를 지원하지만,
StringBuilder는 동기화를 보장하지 않는다.</p>
<p>그러므로 멀티스레드 환경이라면 값 동기화 보장을 위해 StringBuffer를 사용하고,
단일스레드 환경이라면 StringBuilder를 사용하는 것이 좋다.</p>
<h4 id="string-객체가-불변인-이유">String 객체가 불변인 이유</h4>
<ul>
<li><p>리터럴 String의 경우 Heap의 String Pool에 저장이 되는데, 문자열 재사용이 가능하다.</p>
</li>
<li><p>또한 불변이므로, Thread-Safe하다.</p>
</li>
<li><p>강제로 변경이 또한 불가능해서 보안상 우수하다.</p>
</li>
</ul>
<h3 id="5-불변-객체와-final">5. 불변 객체와 final</h3>
<h4 id="51-불변-객체read-only">5.1 불변 객체(read-only)</h4>
<p>ex) string</p>
<ul>
<li><p>객체 생성 이후 내부의 상태가 변하지 않는 객체</p>
</li>
<li><p>final로 생성이 가능하다.</p>
</li>
<li><p>방어적 복사
참조를 통해서 값을 수정하면 내부의 상태가 변하기 때문에 내부를 복사하여 전달.</p>
</li>
</ul>
<h4 id="얕은-복사-vs-방어적-복사-vs-깊은-복사">얕은 복사 vs 방어적 복사 vs 깊은 복사</h4>
<ol>
<li><p>얕은 복사(=)
객체의 주소 값만 복사.
복사된 객체와 원본 객체는 같은 객체를 참조하게 되어, 하나의 객체를 수정하면 다른 객체에도 영향을 미친다.</p>
</li>
<li><p>방어적 복사
객체의 주소를 복사하지 않고, 객체의 내부 값을 참조하여 복사하는 방법
(내부의 값들은 동일하지만, 객체의 주소가 달라졌다.)
특히 컬렉션을 복사하는 경우 유용하다.
복사본이 원본의 주소를 그대로 참조하여 사용하지는 않지만, 복사복 객체 내부에 있는 객체들은 원본과 동일한 주소를 참조하게 된다.</p>
</li>
</ol>
<pre><code class="language-java">public class Member {
    private final String name;

    public Member(String name) {
        this.name = name;
    }
}

public class VIPMembers {
    private final List&lt;Member&gt; members;

    public VIPMembers(List&lt;Member&gt; members) {
        //new ArrayList 로 새로운 객체를 만들어 방어적 복사를 수행한다.
        this.members = new ArrayList&lt;&gt;(members);
    }
}

public class Application {
    public static void main(String[] args) {
        List&lt;Member&gt; memberList = new ArrayList&lt;&gt;();
        memberList.add(new Member(&quot;김씨&quot;));
        memberList.add(new Member(&quot;쿨씨&quot;));

        VIPMembers vipMembers = new VIPMembers(memberList);
        memberList.add(new Member(&quot;아저씨&quot;));
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/new_guy/post/47683519-b15f-409e-a246-07dff086c360/image.png" alt="">
( <a href="https://dev-cool.tistory.com/25">https://dev-cool.tistory.com/25</a> )</p>
<ol start="3">
<li>깊은 복사
객체의 모든 내부 상태를 완전히 복사하여 새로운 객체를 만드는 방식.</li>
</ol>
<h4 id="52-불변-객체-및-final-사용-이유">5.2 불변 객체 및 final 사용 이유</h4>
<ol>
<li><p>Thread-safe(안전한 병렬 프로그래밍 및 동기화 고려x)
항상 동일한 값을 반환하므로, 동기화를 고려하지 않아도 된다.</p>
</li>
<li><p>실패 원자적인 메소드 작성 가능</p>
</li>
<li><p>Cache, Map, Set 가능
한 번 데이터가 저장된 이후에 다른 작업들을 고려하지 않아도 된다.</p>
</li>
</ol>
<ol start="4">
<li><p>부수 효과를 피해 오류가능성 최소화
Setter를 남발할 경우 유지보수성을 상당히 떨어뜨린다.
따라서, 불변 객체를 통해서 안전하게 재사용하도록 유도를 한다.</p>
</li>
<li><p>다른 사람의 함수 예측가능</p>
</li>
<li><p>가비지 컬력션 성능 높임</p>
</li>
</ol>
<pre><code class="language-java">public class ImmutableObject {
    private final Object value;
    public ImmutableObject(Object o) { value = o; }
    private Object getValue() { return value; }
}</code></pre>
<p>생성과정은 다음과 같다.</p>
<ol>
<li><p>Object 타입의 value 객체가 생성</p>
</li>
<li><p>ImmutableObject의 생성자를 통해 ImmutableObject 객체가 생성</p>
</li>
<li><p>ImmutableObject 객체가 value 객체를 참조</p>
</li>
</ol>
<p>ImmutableObject가 reachable하다 -&gt; 그 내부 객체도 자동으로 reachable 하다.</p>
<p>결과적으로, GC가 객체의 참조 관계를 복잡하게 추적할 필요가 줄어들어, 스캔해야 할 객체의 수가 감소하고 스캔해야 하는 메모리 영역과 빈도도 줄어든다.</p>
<p>또한 객체의 생성 비용보다 GC의 스캔 범위 축소 비용이 더 크다.</p>
<pre><code class="language-txt">Programmers are often reluctant to employ immutable objects, 
because they worry about the cost of creating a new object as opposed to updating an object in place. 
The impact of object creation is often overestimated, 
and can be offset by some of the efficiencies associated with immutable objects. 
These include decreased overhead due to garbage collection, 
and the elimination of code needed to protect mutable objects from corruption.</code></pre>
<h4 id="만약-참조-타입일-경우-불변-객체를-만들기-위해서-어떤-것을-해야하나">만약 참조 타입일 경우, 불변 객체를 만들기 위해서 어떤 것을 해야하나</h4>
<ol>
<li><p>참조 변수가 일반 객체인 경우 객체를 사용하는 필드의 팜조 변수도 불변 객체로 변경해야 한다.</p>
<pre><code class="language-java">public class Something{
 private final String someValue;
 // String, Integer는 한번 할당되면 안 바뀐다.
}</code></pre>
</li>
<li><p>배열일 경우, 배열을 받아 copy해서 저장하고, getter를 clone으로 반환하도록 한다.
(배열을 그대로 참조하거나, 반환할 경우 외부에서 내부 값을 변경할 수 있음.
따라서 clone을 반환해 외부에서 값 변경하지 못하게 함.)</p>
</li>
<li><p>리스트인 경우에도 배열과 마찬가지로 새로운 List를 만들어 값을 복사하도록 해야 한다.</p>
</li>
</ol>
<h4 id="결국-배열-리스트를-반환할-경우-새로운객체를-생성해서-반환을-해야-한다">결국 배열, 리스트를 반환할 경우 새로운객체를 생성해서 반환을 해야 한다.</h4>
<h3 id="6-접근-제한자와-static">6. 접근 제한자와 static</h3>
<h4 id="61-접근-제한자">6.1 접근 제한자</h4>
<ul>
<li><p>public
접근 제한이 없다.( 같은 프로젝트 내 어디서든 사용 가능 )
가능 : 클래스 내부, 동일 패키지, 하위 클래스, 그 외의 영역</p>
</li>
<li><p>protected
상속받은 클래스 또는 같은 패키지에서만 접근이 가능하다.
가능 : 클래스 내부, 동일 패키지, 하위 클래스(다른 패키지에 있어도, 해당 클래스를 상속한 하위 클래스는 가능하다.)</p>
</li>
<li><p>default
해당 패키지 내에서만 접근 가능
가능 : 클래스 내부, 동일 패키지</p>
</li>
<li><p>private
해당 클래스에서만 접근 가능
가능 : 클래스 내부</p>
</li>
</ul>
<table>
<thead>
<tr>
<th>접근 위치</th>
<th><code>private</code></th>
<th><code>default</code> (package)</th>
<th><code>protected</code></th>
<th><code>public</code></th>
</tr>
</thead>
<tbody><tr>
<td>동일 클래스</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>같은 패키지 내 다른 클래스</td>
<td>❌</td>
<td>✅</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>다른 패키지 하위 클래스</td>
<td>❌</td>
<td>❌</td>
<td>✅</td>
<td>✅</td>
</tr>
<tr>
<td>다른 패키지 비하위 클래스</td>
<td>❌</td>
<td>❌</td>
<td>❌</td>
<td>✅</td>
</tr>
</tbody></table>
<h4 id="62-static">6.2 static</h4>
<p>클래스가 메모리에 올라갈 떄 자동으로 생성되며, 클래스 로딩이 끝나면 바로 사용이 가능하다.
(인스턴스 생성 없이 바로 사용 가능하다.)</p>
<p>모든 객체가 메모리를 공유하고, GC 관리 영역 밖에 있기 때문에 프로그램이 종료될 때까지 메모리에 값이 유지된 채로 존재한다.</p>
<ol>
<li><p>인스턴스에 공통적으로 사용해야 하는 것에 static을 붙인다.
(인스턴스들이 공통적인 값이 유지되어야 하는 경우에는 static을 붙인다.)</p>
</li>
<li><p>static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용 가능하다.
(클래스가 메모리에 올라갈 때 이미 자동적으로 생성이 된다.)</p>
</li>
<li><p>static 메소드는 인스턴스 변수를 사용할 수 없다.
( 인스턴스 변수, 메소드에선 static이 붙은 멤버들을 사용하는 것은 가능)</p>
</li>
<li><p>메소드 내에서 인스턴스 변수를 사용하지 않는다면, static 붙이는 것을 고려한다.
(메소드 호출 시간이 짧아지기 때문이다.)</p>
</li>
<li><p>클래스 설계시 static 사용지침</p>
</li>
</ol>
<ul>
<li><p>클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야 하는 것이 있는지 보고 있다면 static을 사용한다.</p>
</li>
<li><p>작성한 메소드 중 인스턴스 변수를 사용하지 않는 메소드에 대해서 static을 붙일 것을 고려한다.</p>
</li>
</ul>
<h4 id="static-사용-이유">static 사용 이유</h4>
<ul>
<li><p>자주 변하지 않는 값이나 공통으로 사용되는 값 같은 공용자원에 대한 접근에 있어서 매번 메모리에 로딩하거나 값을 읽어들이는 것보다
전역변수와 같은 개념을 통해 접근하는 것이 비용도 줄이도 효율을 높일 수 있다.</p>
</li>
<li><p>인스턴스 없이 생성을 하므로, 공통으로 사용되는 데이터 관리에 유용하다.</p>
</li>
</ul>
<h4 id="inner-class와-static">Inner Class와 static</h4>
<ol>
<li>Inner Class</li>
</ol>
<ul>
<li><p>내부 클래스에서 외부 클래스의 멤버에 손쉽게 접근</p>
</li>
<li><p>서로 관련 있는 클래스를 논리적으로 묶어서 표현함으로써, 캡슐화를 증가시키고, 코드의 복잡성을 낮출 수 있음.</p>
</li>
<li><p>외부에서는 내부 클래스에 접근할 수 없으므로, 코드의 보안성을 높일 수 있음.
(캡슐화와 정보 은닉 측면에서)</p>
</li>
</ul>
<ol start="2">
<li>내부 클래스를 static으로 사용하는 이유</li>
</ol>
<ul>
<li>내부 인스턴스 클래스를 만들기 위해서는 먼저 외부 클래스를 초기화한 뒤 내부 클래스를 초기화를 하는데, 이 과정에서 inner 클래스는 자신을 만들어준 인스턴스에 대한 &#39;외부 참조&#39;를 갖게 된다.
(Inner Class의 생성자에서 외부 클래스를 매개변수로 받아 인스턴스 변수로 암묵적으로 저장을 한다. = 숨은 외부 참조)
<img src="https://velog.velcdn.com/images/new_guy/post/0343abcf-6475-4e80-9a4c-0d9660de1ac9/image.png" alt=""></li>
</ul>
<ul>
<li>외부 클래스가 필요 없어지고 내부 클래스만 남을 경우, 필요 없는 외부 클래스를 GC대상으로 삼아야 하지만, 외부 참조로 내부 클래스와 연결되어 메모리에 제거되지 않아서 메모리 누수가 발생한다.</li>
</ul>
<pre><code class="language-java">import java.util.ArrayList;

class Outer_Class {
    // 외부 클래스 객체의 크기를 불리기 위한 배열 변수
    private int[] data;

    // 내부 클래스
    class Inner_Class {
    }

    // 외부 클래스 생성자
    public Outer_Class(int size) {
        data = new int[size]; // 사이즈를 받아 배열 필드의 크기를 불림
    }

    // 내부 클래스 객체를 생성하여 반환하는 메소드
    Inner_Class getInnerObject() {
        return new Inner_Class();
    }
}</code></pre>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        // inner_Class 객체를 저장할 리스트
        ArrayList&lt;Object&gt; al = new ArrayList&lt;&gt;();

        for (int counter = 0; counter &lt; 50; counter++) {
            // inner_Class 객체를 생성하기 위해 Outer_Class를 초기화하고 메서드를 호출하여 리스트에 넣는다.
            // 이때 Outer_Class 객체는 메소드 호출용으로 일회용으로 사용되고 버려지기 때문에 GC 대상이 되어야 한다.
            al.add(new Outer_Class(100000000).getInnerObject());
            System.out.println(counter);
        }
    }
}
// Outer_Class의 data 배열의 크기가 400MB인데, Inner Class가 참조를 하고 있기 때문에(외부 참조), GC가 되지 않는다.

/* 
  메소드 호출용으로 쓰인 일회용 객체 Outer_Class는 바로 GC 수거 대상이 되어 제거되어야 하지만, 
  내부 클래스에서 외부 클래스를 참조하고 있기 때문에, 내부 클래스가 살아있는 한 외부 클래스 데이터도 계속 살아있다.
*/</code></pre>
<h4 id="static-내부-클래스를-사용할-경우">static 내부 클래스를 사용할 경우</h4>
<pre><code class="language-java">public class Outer_Class {
    int field = 10;

    // static inner class
    static class Inner_Class {
       int inner_field = 20;
    }
}</code></pre>
<p><img src="https://velog.velcdn.com/images/new_guy/post/971e953f-c86b-45e8-993b-7ef81adfb6b7/image.png" alt="">
외부 참조를 하고 있지 않음.
<img src="https://velog.velcdn.com/images/new_guy/post/af08c482-3719-47b1-84e3-0103bd36258c/image.png" alt="">
따라서, this 기능도 사용 불가능하다.</p>
<pre><code class="language-java">import java.util.ArrayList;

class Outer_Class {

    private int[] data;

    // static 내부 클래스
    static class Inner_Class {
    }

    public Outer_Class(int size) {
        data = new int[size];
    }

    Inner_Class getInnerObject() {
        return new Inner_Class();
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList&lt;Object&gt; al = new ArrayList&lt;&gt;();
        for (int counter = 0; counter &lt; 50; counter++) {
            al.add(new Outer_Class(100000000).getInnerObject());
            System.out.println(counter);
        }
    }
}
/*
    정적 멤버 클래스는 &#39;외부 참조&#39;를 하지 않기 때문에,
    일회용으로 사용된 외부 클래스 객체는 정상적으로 GC 수거 대상이 되어 메모리 관리가 잘 된다.
*/</code></pre>
<h2 id="4-예외-및-오류">4. 예외 및 오류</h2>
<ol>
<li>try-with-resources</li>
</ol>
<p>resources란 외부의 데이터(DB, Network, File)을 일컫는다.
( 자바 내부에 위치한 요소들이 아님. 
그리고, 사용후 반드시 resource 반납을 해야한다. )</p>
<p>그런데 try-catch-finally를 할 경우 가독성이 매우 안좋다.</p>
<pre><code class="language-java">import java.io.FileWriter;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        FileWriter file = null;
        try {
            file = new FileWriter(&quot;data.txt&quot;);
            file.write(&quot;Hello World&quot;);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            // close()에서 발생하는 예외를 처리하기 위해서 아래와같이 바꿀수도 있지만 코드가 복잡해져서 좋지않다.
            try {
                file.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}</code></pre>
<p>그래서 아래와 같이 수정</p>
<pre><code class="language-java">try (파일을 열거나 자원을 할당하는 명령문) {
     ...
}</code></pre>
<pre><code class="language-java">import java.io.FileWriter;
import java.io.IOException;

public class Main {
    public static void main(String[] args) {
        try (FileWriter file = new FileWriter(&quot;data.txt&quot;)) { // 파일을 열고 모두 사용되면 자동으로 닫아준다
            file.write(&quot;Hello World&quot;);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}</code></pre>
<ul>
<li><p>try-catch-finally의 문제점을 보완하기 위해 나온 개념</p>
</li>
<li><p>try(...) 안에 자원 객체를 전달하면, try 블록이 끝나고 자동으로 자원 해제 해주는 기능</p>
</li>
<li><p>finally 구문이나 모든 catch 구문에 종료 처리를 하지 않아도 된다.</p>
</li>
</ul>
<ol start="2">
<li>Error vs. Exception</li>
</ol>
<ul>
<li><p>Error는 실행 중 일어날 수 있는 치명적 오류
(컴파일 시점에 체크할 수 없고, 오류가 발생하면 프로그램 비정상 종료)  = UncheckedException</p>
</li>
<li><p>Exception은 Error보다 비교적 경미한 오류이며, try-cath로 비정상 종료를 막을 수 있다.</p>
</li>
</ul>
<h4 id="checkexception-vs-uncheckedexception">CheckException vs. UnCheckedException</h4>
<ul>
<li><p>CheckException은 실행하기 전에 예측 가능한 예외를 말하고, 반드시 예외 처리.
(I/O, ...)</p>
</li>
<li><p>UnCheckedException은 실행하고 난 후에 알 수 있는 예외를 말하고, 따로 예외처리를 하지 않아도 됨.
(NullPointerException,...)</p>
</li>
<li><p>RuntimeException은 UnCheckedException을 상속할 클래스이고, RuntimeException이 아닌 것은 CheckException을 상속한 클래스이다.</p>
</li>
</ul>
<h4 id="final-vs-finally-vs-finalizedeprecated">final vs. finally vs. finalize(deprecated)</h4>
<ol>
<li>final
클래스, 메소드, 변수, 인자를 선언 시, 한 번만 할당하고 싶을 때 사용</li>
</ol>
<ul>
<li><p>final 변수
한 번 초기화되면 그 이후에 변경 x</p>
</li>
<li><p>final 메소드
다른 클래스가 이 클래스를 상속시, 오버라이딩 금지</p>
</li>
<li><p>final 클래스
다른 클래스에서 이 클래스를 상속 x</p>
</li>
</ul>
<ol start="2">
<li>finally
try-catch와 함께 사용되며, try-catch가 종료될 때 finally block이 항상 수행이 됨.
(자원 반납의 경우 finally에 쓴다.)</li>
</ol>
<h2 id="5-기타">5. 기타</h2>
<h3 id="1-wrapper-class와-boxing-unboxing">1. Wrapper Class와 Boxing, UnBoxing</h3>
<ul>
<li><p>기본 자료형(원시 타입)에 대한 객체 표현 = Wrapper Class</p>
</li>
<li><p>기본 자료형 -&gt; Wrapper class(Boxing)</p>
</li>
<li><p>Wrapper class -&gt; 기본 자료형(UnBoxing)</p>
</li>
</ul>
<h3 id="2-synchronized">2. Synchronized</h3>
<h3 id="3-리플렉션이란-v">3. 리플렉션이란? (v)</h3>
<p>구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드 ,타입, 변수들에 접근할 수 있도록 해주는 자바 API</p>
<p>코드를 작성할 시점에는 어떤 타입의 클래스를 사용할지 모르지만,
런타임 시점에 지금 실행되고 있는 클래스를 가져와서 실행해야 하는 경우 사용된다.
( 스프링의 어노테이션 )</p>
<h3 id="4-컬렉션-프레임워크">4. 컬렉션 프레임워크</h3>
<ul>
<li><p>다수의 데이터를 효과적으로 관리할 수 있는 표준화된 방법을 제공하는 클래스의 집합.
( 자료 구조 종류의 형태들을 자바 클래스로 구현한 모음집 )</p>
</li>
<li><p>List, Set, Map, Stack, Queue 인터페이스가 존재한다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/99454b77-573f-44bc-9cae-4185ef2d023a/image.png" alt=""></p>
<ul>
<li><p>List는 순서가 있는 데이터의 집합이며, 중복을 허용</p>
</li>
<li><p>Set은 순서가 없는 데이터의 집합이며, 중복을 허용x
(LinkedHashSet은 순서를 보장한다.)</p>
</li>
<li><p>Map은 key:value로 구성, key를 기준으로 중복을 허용하지 않으며, 순서가 없다.
(LinkedHashMap은 key의 순서를 보장한다.)</p>
</li>
<li><p>Stack은 직접 new로 사용할 수 있고, Queue인터페이스는 LinkedList에 new 키워드로 적용해 사용할 수 있다.</p>
</li>
</ul>
<h4 id="set과-map의-타입이-wrapper-class가-아닌-object를-받을-때-중복-검사는-어떻게-하나">Set과 Map의 타입이 Wrapper Class가 아닌 Object를 받을 때 중복 검사는 어떻게 하나</h4>
<p>: hashCode()를 오버라이딩해서 리턴된 해시코드 값이 같은지를 보고, 만약 다르면 다른 객체이다.</p>
<h4 id="vector-vs-list">Vector vs. List</h4>
<ul>
<li><p>벡터는 데이터 삽입시 원소를 밀어내지마, 리스트는 노드를 연결만 하므로, 삽입 삭제에서 리스트가 더 빠르다. ( 연결 리스트만 해당 )</p>
</li>
<li><p>벡터는 랜덤부분접근이 가능하지만, 리스트는 더블링크드리스트이므로, 랜덤 접근이 안되므로, 검색적인 측면에서 벡터가 우위.</p>
</li>
<li><p>벡터는 동기화가 되는데, 멀티쓰레드에서는 안전하게 객체 추가/삭제가 되지만, 단일쓰레드에서도 동기화가 되므로, 이때는 List보다 성능이 느리다.</p>
</li>
<li><p>둘다 모두 동적 배열 클래스인데, 최대 인덱스를 초과할 때 추가되는 인덱스 수는 vector는 현재 배열크기 100%, arraylist는 50%증가한다.</p>
</li>
</ul>
<h3 id="참고">참고</h3>
<p>ArrayList vs LinkedList</p>
<ul>
<li>ArrayList는 배열 공간(capacity)가 꽉 차거나, 요소 중간에 삽입을 행하려 할때 기존의 배열을 복사해서 요소를 뒤로 한칸씩 일일히 이동해야 하는 작업이 필요하다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/c7b36bea-c7d1-411c-89e5-5e459502f0d7/image.png" alt="">
(ArrayList 작동 : <a href="https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-ArrayList-vs-LinkedList-%ED%8A%B9%EC%A7%95-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90#arraylist%EC%9D%98_%EB%AC%B8%EC%A0%9C%EC%A0%90">https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-ArrayList-vs-LinkedList-%ED%8A%B9%EC%A7%95-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90#arraylist%EC%9D%98_%EB%AC%B8%EC%A0%9C%EC%A0%90</a> )</p>
<ul>
<li>요소를 get 하는 과정에서 ArrayList와 굉장한 성능 차이를 보이는데, ArrayList에서는 무작위 접근(random access)이 가능하지만, LinkedList에서는 순차접근(sequential access) 만이 가능하기 때문이다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/97384566-5589-415e-906b-db6c736781ee/image.png" alt="">
(ArrayList vs LinkedList : <a href="https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-ArrayList-vs-LinkedList-%ED%8A%B9%EC%A7%95-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90#arraylist%EC%9D%98_%EB%AC%B8%EC%A0%9C%EC%A0%90">https://inpa.tistory.com/entry/JCF-%F0%9F%A7%B1-ArrayList-vs-LinkedList-%ED%8A%B9%EC%A7%95-%EC%84%B1%EB%8A%A5-%EB%B9%84%EA%B5%90#arraylist%EC%9D%98_%EB%AC%B8%EC%A0%9C%EC%A0%90</a> )</p>
<p><img src="https://velog.velcdn.com/images/new_guy/post/c512af01-2523-4e71-8cbe-6d36121069a9/image.png" alt="">
근데, LinkedList 잘 안씀.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로세스간 통신 IPC]]></title>
            <link>https://velog.io/@new_guy/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EA%B0%84-%ED%86%B5%EC%8B%A0-IPC</link>
            <guid>https://velog.io/@new_guy/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EA%B0%84-%ED%86%B5%EC%8B%A0-IPC</guid>
            <pubDate>Sun, 04 May 2025 12:54:33 GMT</pubDate>
            <description><![CDATA[<p><a href="https://velog.io/@new_guy/05.%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EA%B0%84-%ED%86%B5%EC%8B%A0IPC">https://velog.io/@new_guy/05.%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EA%B0%84-%ED%86%B5%EC%8B%A0IPC</a></p>
<p>실제 통신
<a href="https://velog.io/@new_guy/06.-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EA%B0%84-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%8B%A4%EC%A0%9C">https://velog.io/@new_guy/06.-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EA%B0%84-%ED%86%B5%EC%8B%A0%EC%9D%98-%EC%8B%A4%EC%A0%9C</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2-2. Process Scheduling]]></title>
            <link>https://velog.io/@new_guy/2-2.-Process-Scheduling</link>
            <guid>https://velog.io/@new_guy/2-2.-Process-Scheduling</guid>
            <pubDate>Sat, 03 May 2025 02:58:17 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/new_guy/post/66929953-a587-497b-964b-eccda1367a06/image.png" alt=""></p>
<h1 id="1-context-switch">1. Context Switch</h1>
<ul>
<li><p>Context란?
CPU가 해당 프로세스를 실행하기 위한 해당 프로세스의 정보들로 PCB를 의미한다.</p>
</li>
<li><p>Context Switching?
현재 실행 중인 프로세스나 스레드를 중단하고 다른 프로세스나 스레드로 전환하는 과정.
이때, 이전 프로세스나 스레드의 PCB, TCB 같은 Context(상태)를 저장하고, 새로운 프로세스나 스레드의 상태를 복원한다.</p>
</li>
</ul>
<p>컨텍스트 스위칭은 캐시 오염이라는 간접적인 영향이 발생한다.
따라서</p>
<ul>
<li><p>장점
멀티 태스킹 즉, Concurrent하게 실행이 가능하다.
또한 CPU 스케줄링을 통해서 우선순위가 높은 작업을 처리할 수 있다.</p>
</li>
<li><p>단점
CPU가 실제로 작업을 처리하는 것보다, 상태 저장 및 복원에 더 많은 시간을 소모한다.
캐시의 효율이 저하된다.(캐시 미스 발생)</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/dee70421-76f8-4a86-9343-f72be8733547/image.png" alt=""></p>
<h1 id="2-fork">2. fork</h1>
<p>가상 메모리는 분리되어 있으나(다른 프로세스), 서로 동일한 물리 메모리(frame)을 참조하고 있다.
fork를 해도 제어권은 여전히 parent가 가지고 있다.</p>
<ul>
<li>execlp</li>
</ul>
<p>현재 프로세스의 메모리 공간이 완전히 새로운 프로그램으로 대체됩니다.</p>
<p>이때 기존의 가상 주소 공간은 새로운 프로그램의 가상 주소 공간으로 덮어씌워지며, 이전에 사용되던 물리 메모리도 해제되고, 새로운 프로그램이 필요로 하는 메모리가 다시 할당됩니다.</p>
<p>Ex)
게임 laucher가 child로 복제한 다음, execlp를 통해서 하고자 하는 게임을 실행한다.</p>
<p>synchronized가 필요하다.</p>
<ul>
<li>cow</li>
</ul>
<p>두 프로세스는 동일한 페이지를 참조하고 있다가 하나의 프로세스가 해당 페이지를 수정하려 할 때, 그 페이지가 복사되고 부모와 자식이 각자 독립적인 메모리를 사용하게 됩니다.</p>
<h4 id="zombie-and-orphan">Zombie and Orphan</h4>
<ul>
<li>Zombie
자식 프로세스가 종료되었지만, 부모 프로세스가 wait() 또는 waitpid()로 자식의 종료 상태를 수거하지 않았을 때 발생합니다.</li>
</ul>
<p>PID는 여전히 프로세스 테이블에 남아 있음 (exit code 등 상태 정보만).</p>
<p>부모가 자식 종료 후 상태를 수거하지 않으면, OS는 그 상태 정보를 유지해야 함 → 그래서 프로세스 테이블에 남아 있음.</p>
<p>🛠 해결:
부모가 wait()를 호출해야 함.</p>
<p>또는 SIGCHLD 시그널 핸들링을 통해 자동 수거 설정.</p>
<ul>
<li>Orphan
: 부모 프로세스가 먼저 종료되어 자식 프로세스가 부모를 잃은 상태.
이 경우 자식 프로세스는 init 프로세스 (pid 1)가 자동으로 입양해서 관리합니다.</li>
</ul>
<p>리눅스에서는 systemd나 init이 orphan을 관리하며, 종료 시 상태도 수거해줍니다.</p>
<p>🧠 특징:
Orphan은 위험하지 않음. OS가 처리함.</p>
<p>Zombie는 잘못 관리된 자식이고, Orphan은 부모가 먼저 죽은 정상 자식.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[14 테스트 대역]]></title>
            <link>https://velog.io/@new_guy/14-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8C%80%EC%97%AD</link>
            <guid>https://velog.io/@new_guy/14-%ED%85%8C%EC%8A%A4%ED%8A%B8-%EB%8C%80%EC%97%AD</guid>
            <pubDate>Wed, 30 Apr 2025 04:42:33 GMT</pubDate>
            <description><![CDATA[<p>테스트 대역 = 가짜 객체나 컴포넌트(실제 객체 대신 역할)</p>
<pre><code class="language-java">public class UserService{

    private final UserRepository userRepository;
    private final VerificationEmailSender verificationEmailSender;

    @Transactional
    public User register(UserCreadteDto userCreateDto){
        User user = User.builder()
        ...
        .build();

        user = userRepository.save(user);
        verificationEmailSender.send(user);
        return user;
    }
}</code></pre>
<p>위와 같이 구성할 경우, 테스트를 진행할 때마다 실제 동작을 한다.</p>
<p>메소드를 호출한 결과로 제대로 된 상태 값이 반영됐는지만 확인하면 된다.
(실제 전송은 불필요하다.)</p>
<pre><code class="language-java">public class DummyVerificationEmailSender implements VerificationEmailSender{

    @Overrride
    public void send(User user){
        // do nothing...
    }
}</code></pre>
<pre><code class="language-java">public class UserServiceTest{

    @Test
    public void ...(){
        // given UserCreateDto userCreateDto = UserCreateDto.builder()
        ...
        .build();

        // when
        UserService userService = UserService.builder()
        ... // &lt;- Mock객체인 new DummyVerificationEmailSender()를 추가한다.
        .build();

        // then
        assertThan(user.isPending()).isTrue();

    }
}
</code></pre>
<p>실제 DB 연결하는 객체 대신에 Mock 객체를 주입해서 단순 테스트만 진행을 한다.
(API 호출 없이 테스트가 가능하다.)</p>
<p>Mock객체의 의의는 해당 메일을 발송하는 부분 외의 나머지가 정상 작동을 하는지 알기 위함이다!</p>
<p>Mock 객체를 이용해서 다양한 시나리오를 연출할 수 있다.</p>
<h4 id="그러나-너무-과도하면-실제-구현과-거리가-멀어지기-때문에-유의해야-한다">그러나 너무 과도하면, 실제 구현과 거리가 멀어지기 때문에 유의해야 한다.</h4>
<ul>
<li>테스트 대역의 5가지 유형</li>
</ul>
<ol>
<li><p>Dummy
아무런 동작을 하지 않는다.</p>
</li>
<li><p>Stub
지정한 값만 반환한다.</p>
</li>
<li><p>Fake
자체적인 로직이 있다.</p>
</li>
<li><p>Mock
아무런 동작을 하지 않지만, 어떤 행동이 호출됐는지 기록한다.</p>
</li>
<li><p>Spy
실제 객체와 똑같이 행동하고, 모든 행동 호출을 기록한다.</p>
</li>
</ol>
<h1 id="141-dummy">14.1 Dummy</h1>
<p>아무런 동작도 하지 않는다.
단순히 코드가 정상적으로 돌아가게 하기 위한 역할만 수행하고, 특정 행동이 일어나지 않게 한다.
( Dummy 부분을 제외한 나머지가 정상 작동을 하는기 알기 위해 사용. )</p>
<p>멤버 변수뿐만 아니라 필드 변수 호출로도 가능하다.</p>
<pre><code class="language-java">public class SomethingFilter extends GenericFilterBean{

    @Override
    public void doFilter(
        ...
    ){
        if(servletRequest.getAttribute(&quot;giveMe&quot;).equals(&quot;text&quot;)){
            servletResponse.setContentType(&quot;text/plain&quot;);

        filterChain.doFilter(...);
        }
    }
}
알고 싶은 것은 giveMe 어트리뷰트가 text일 때 제대로 동작하는지이다.

따라서 ,아래와 같이 수정한다.
```java
public class SomethingFilterTest{

    @Test 
    public void ...(){
        // given
        ServletRequest servletReq = new MockHttpServletRequest();
        servletRequest.setAttribute(&quot;giveMe&quot;,&quot;text&quot;);
        ServletResponse servletResponse = new MockHttpServletResponse();

        // when
        SomethingFilter somethingFiler = new SomeghingFilter();

        somethingFilter.doFilter(...,newFilterChain(){

            @Override
            public void doFilter(...){
                ...// do nothing
                // 이렇게 함으로써, 재귀적으로 빠져 들어가는 것을 방지한다. 오직 1번만 실행
            }
        })
    }
}</code></pre>
<h1 id="142-stub">14.2 Stub</h1>
<p>부본: 원본과 비슷하기 만들어 참고로 보관하는 서류(사본)</p>
<p>실제 객체의 &quot;응답을 최대한 비슷하게&quot; 따라하는 대역.</p>
<p>그래서 Stub은 응답을 원본과 똑같이 반환하는 데만 집중한다.
(원본의 응답을 복제해 똑같은 응답으로 미리 준비하고 이를 바로 반환한다.)</p>
<p>Stub은 미리 준비된 값을 반환하는 대역 객체를 의미한다.
Dummy처럼 실제 구현체의 코드를 실행하지 않는다는 점에서 유사하지만 Dummy보다는 조금 더 발전된 형태이다.
(Dummy는 아무것도 안하지만, Stub은 개발자가 의도한 미리 준비된 값을 반환한다.)</p>
<p>Ex)
실제로 API 호출을 하는 것보다 응답값을 미리 만들어서 반환하는 편이 낫다.</p>
<p>디크스 I/O, 네트워크 호출, JPA도 마찬가지이다.</p>
<p>Stub은 외부 연동을 하는 컴포넌트나 클라이언트를 대체하는 데 자주 사용된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링부트 OS 관계]]></title>
            <link>https://velog.io/@new_guy/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-OS-%EA%B4%80%EA%B3%84</link>
            <guid>https://velog.io/@new_guy/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-OS-%EA%B4%80%EA%B3%84</guid>
            <pubDate>Wed, 30 Apr 2025 02:28:30 GMT</pubDate>
            <description><![CDATA[<ol>
<li>네트워크 연결</li>
</ol>
<p>API 요청이 들어올 경우, OS의 네트워크 SYN 큐에 SYN 패킷을 저장한 후, SYN+ACK 패킷을 반환한다.
클라이언트는 ACK 패킷으로 응답한 후, ESTABLISHED가 된다면, SYN 큐를 스프링부트의 ACCEPT큐로 PUSH를 한다.
톰캣의 ACCEPT 큐의 패킷을 톰캣 워커 스레드가 하나씩 처리를 한다.</p>
<ul>
<li>이때 ACCEPT 큐가 적을 경우, ACCEPT 큐의 버퍼 오버플로우가 발생</li>
</ul>
<ol start="2">
<li>커널 스레드</li>
</ol>
<p>Java는 One-to-One Threading-Model로 Thread를 생성한다.
또한 User Thread 생성시 OS Thread와 1대1로 연결이 된다.</p>
<ul>
<li><p>스프링부트 톰캣 스레드 수를 조정할 필요가 있다.
( 스레드 생성 자체가 오버헤드가 매우 큼)</p>
</li>
<li><p>스레드가 많아질수록 컨텍스트 스위칭 비용이 증가한다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/new_guy/post/e97a0138-3c33-41a2-ac81-579e0d8f5eb2/image.png" alt=""></p>
]]></description>
        </item>
    </channel>
</rss>