<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>mangez_DEV.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Tue, 11 Mar 2025 07:01:39 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <copyright>Copyright (C) 2019. mangez_DEV.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/mangez_js" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[Trouble Shooting : N+1 문제]]></title>
            <link>https://velog.io/@mangez_js/N1-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@mangez_js/N1-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Tue, 11 Mar 2025 07:01:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>ORM(Object-Relational Mapping)에서 발생하는 성능 이슈 중 하나로, 특정 엔티티를 조회 할 때 연관된 엔티티들을 추가로 조회하면서 불필요한 쿼리가 다시 실행되는 문제</p>
</blockquote>
<ul>
<li>하나의 <code>Review</code>엔티티를 가져올 때 관련된 <code>Participants</code> 엔티티가 존재한다면</li>
</ul>
<ol>
<li>1개의 쿼리로 <code>Review</code> 목록을 가져옵니다.</li>
<li>이후, N개의 쿼리로 각 <code>Review</code>와 연관된 <code>Participants</code>를 조회합니다.</li>
</ol>
<ul>
<li>즉 하나의 <code>Review</code>를 가져오는데 추가적으로 <code>Participants</code>를 개별적으로 조회하게 되어 <code>N+1</code>개의 쿼리가 실행</li>
</ul>
<h2 id="문제-상황">문제 상황</h2>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/c25d174a-cf3a-476d-9b46-207cb94b02c2/image.png" alt=""></p>
<blockquote>
<ul>
<li><code>review.getParticipants()</code> 호출 시, 각 <code>Participants</code>를 개별적으로 조회</li>
</ul>
</blockquote>
<ul>
<li><code>participant.getUsers().getId()</code> 호출 시, 각 <code>Users</code>를 추가로 조회</li>
<li>결과 : <code>Review</code> 1개 조회 시 N개의 추가 쿼리 발생 → N+1 문제 발생</li>
</ul>
<h2 id="원인-분석">원인 분석</h2>
<blockquote>
<ul>
<li><code>Review</code> 엔티티에서 <code>Participants</code> 엔티티를 조회할 때, Lazy Loading(지연 로딩) 설정으로 인해 개별 쿼리 실행</li>
</ul>
</blockquote>
<ul>
<li><code>Participants</code>에서 <code>Users</code>를 조회할 때도 각각 쿼리 실행 → 쿼리 다중 발생</li>
<li>결과적으로 <code>Review</code> 1개 조회할 때 1개의 쿼리 + Participants 개수만큼 추가 쿼리 발생</li>
</ul>
<h2 id="해결방법">해결방법</h2>
<h3 id="①-해결방법--fetch-join을-사용하여-한-번의-쿼리로-조회">① 해결방법 : <code>fetch join</code>을 사용하여 한 번의 쿼리로 조회</h3>
<pre><code>@Query(&quot;SELECT r FROM Review r JOIN FETCH r.participants p JOIN FETCH p.users WHERE r.id = :reviewId&quot;)
Review findReviewWithParticipantsAndUsers(@Param(&quot;reviewId&quot;) Long reviewId);</code></pre><blockquote>
<ul>
<li><code>JOIN FETCH</code>를 사용하여 <code>Review</code>와 <code>Participants</code>, <code>Users</code>를 한 번의 쿼리로 조회</li>
</ul>
</blockquote>
<ul>
<li>N+1 문제 해결 → 쿼리 실행 횟수 1회로 줄어듦</li>
</ul>
<hr>
<h3 id="②-해결방법--entitygraph-활용">② 해결방법 : <code>@EntityGraph</code> 활용</h3>
<pre><code>@EntityGraph(attributePaths = {&quot;participants.users&quot;})
@Query(&quot;SELECT r FROM Review r WHERE r.id = :reviewId&quot;)
Review findReviewWithParticipantsAndUsers(@Param(&quot;reviewId&quot;) Long reviewId);</code></pre><blockquote>
<ul>
<li><code>@EntityGraph</code>를 사용하여 필요한 연관 엔티티를 한 번에 가져옴</li>
</ul>
</blockquote>
<ul>
<li>코드 변경 없이 간단하게 <code>fetch join</code>과 유사한 효과</li>
</ul>
<hr>
<h3 id="③-해결방법--batchsize-또는-hibernatedefault_batch_fetch_size-설정">③ 해결방법 : <code>@BatchSize</code> 또는 <code>hibernate.default_batch_fetch_size</code> 설정</h3>
<ul>
<li>Lazy Loading 유지하면서도 여러 개 데이터를 한 번에 가져오도록 설정</li>
<li>설정 방법 1(엔티티에 직접 적용)<pre><code>@Entity
public class Participant {
  @ManyToOne(fetch = FetchType.LAZY)
  @BatchSize(size = 10)  // 10개씩 한 번에 조회
  private Users users;
}</code></pre></li>
<li>설정 방법 2(<code>application.yml</code>에서 설정)<pre><code>spring:
jpa:
  properties:
    hibernate.default_batch_fetch_size: 100</code></pre><blockquote>
<p><code>IN</code> 쿼리를 활용하여 여러 개의 데이터를 한 번에 조회</p>
</blockquote>
</li>
<li>불필요한 개별 쿼리를 줄이고 성능 개선 가능</li>
</ul>
<hr>
<h2 id="해결-방법-장단점">해결 방법 장단점</h2>
<table>
<thead>
<tr>
<th>해결 방법</th>
<th>주요 장점</th>
<th>주요 단점</th>
</tr>
</thead>
<tbody><tr>
<td><code>fetch join</code>(JPQL 사용)</td>
<td>한 번의 쿼리로 연관 엔티티를 모두 가져와서 성능 최적화</td>
<td>JPQL을 직접 작성해야 하며, 복잡한 쿼리가 될 수 있음</td>
</tr>
<tr>
<td><code>@EntityGraph</code>(어노테이션 기반)</td>
<td>JPQL 수정 없이 적용 가능/ Lazy Loading 유지 가능/ 코드 재사용성이 높음</td>
<td>Hibernate의 구현 방식에 따라 쿼리가 다르게 실행될 수도 있음</td>
</tr>
<tr>
<td><code>@BatchSize</code>(IN 쿼리 사용)</td>
<td>Lazy Loading을 유지하면서 개별 조회를 <code>IN</code> 쿼리로 최적화/ 설정으로 쉽게 작용 가능</td>
<td>완벽한 N+1 해결책이 아님(여전히 여러 개의 쿼리가 발생)</td>
</tr>
</tbody></table>
<hr>
<h1 id="결론">결론</h1>
<p><code>@EntityGraph</code>를 적용하면 연관 엔티티를 미리 로딩하여 N+1 문제를 해결할 수 있으며, 전체적인 성능이 개선된다.
fetch join과 유사한 효과를 내면서도 JPQL을 수정하지 않아도 되므로 유지보수가 용이하다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[2-3 관리구문]]></title>
            <link>https://velog.io/@mangez_js/2-3-%EA%B4%80%EB%A6%AC%EA%B5%AC%EB%AC%B8</link>
            <guid>https://velog.io/@mangez_js/2-3-%EA%B4%80%EB%A6%AC%EA%B5%AC%EB%AC%B8</guid>
            <pubDate>Mon, 17 Feb 2025 13:10:59 GMT</pubDate>
            <description><![CDATA[<h1 id="dml">DML</h1>
<h2 id="insert">INSERT</h2>
<blockquote>
<p>테이블에 데이터를 입력하는 명령어
-&gt; INSERT INTO 테이블(컬럼1, 컬럼2...) VALUES(데이터1, 데이터2...);</p>
</blockquote>
<h2 id="update">UPDATE</h2>
<blockquote>
<p>이미 저장된 데이터를 수정하고 싶을 때 사용하는 명령어
-&gt; UPDATE 테이블 SET 속성 = 데이터 WHERE;</p>
</blockquote>
<h2 id="delete">DELETE</h2>
<blockquote>
<p>이미 저장된 데이터를 삭제하고 싶을 때 사용하는 명령어, WHERE 절이 없으면 테이블의 모든 ROW가 삭제
-&gt; DELETE FROM 테이블(WHERE 수정할 데이터에 대한 조인); : <strong>모든 데이터를 삭제</strong>, <strong>테이블 용량은 감소하지 않음</strong>
-&gt; TRUNCATE TABLE 테이블; : <strong>모든 데이터를 삭제</strong> 후 <strong>테이블 용량 초기화</strong></p>
</blockquote>
<h2 id="merge">MERGE</h2>
<blockquote>
<p>테이블에 새로운 데이터를 입력하거나 이미 저장되어 있는 데이터에 대한 변경 작업을 한번에 할 수 있또록 해주는 명령어
 -&gt; MERGE INTO 변경할 테이블
 -&gt; USER 비교할 테이블 | 서브쿼리
 -&gt; ON 조건문
 -&gt; WHEN MATCHED THEN UPDATE~
 -&gt; WHEN NOT MATCHED THEN INSERT~</p>
</blockquote>
<h1 id="tcl">TCL</h1>
<blockquote>
<p>제어명령어 : COMMIT, ROLLBACK, SAVEPOINT</p>
</blockquote>
<ul>
<li>트랜잭션 : 데이터베이스 시스템에서 하나의 논리적 기능을 정상적으로 수행하기 위한 작업의 기본 단위
특징)</li>
<li>ATOMICITY 원자성 : ALL OR NOTHING</li>
<li>CONSISTENCY 일관성 : 트랜잭션이 완료된 후에도 데이터베이스가 가진 데이터에 일관성이 있어야 한다.</li>
<li>ISOLATION 고립성 : 하나의 트랜잭션을 고립되어 수행</li>
<li>DURABILITY 지속성 : 트랜잭션이 성공하면 갱신한 내용이 데이터베이스에 영구 저장</li>
</ul>
<h2 id="commit">COMMIT</h2>
<blockquote>
<p>INSERT, DELETE, UPDATE 후 변경된 내용을 확정, 반영하는 명령어</p>
</blockquote>
<h2 id="rollback">ROLLBACK</h2>
<blockquote>
<p>INSERT, DELETE, UPDATE 후 변경된 내용을 취소하는 명령어</p>
</blockquote>
<h2 id="savepoint">SAVEPOINT</h2>
<blockquote>
<p>ROLLBACK을 수행할 때 전체 작업을 되돌리지 않고 일부만 되돌릴 수 있게 하는 명령어</p>
</blockquote>
<h1 id="ddl">DDL</h1>
<blockquote>
<p>정의명령어 : CREATE, ALTER, DROP, RENAME, TRUNCATE</p>
</blockquote>
<h1 id="create">CREATE</h1>
<blockquote>
<p>테이블을 생성하기 위한 명령어
-&gt; CREATE TABLE 테이블(컬럼 데이터타입(DEFAULT/NULL 여부), ...);</p>
</blockquote>
<ul>
<li>NULL : 공백(&#39; &#39;)과는 다르며 존재하지 않는 값</li>
<li>DEFAULT : 데이터의 기본 값</li>
<li><em>주의사항*</em></li>
<li>테이블 명은 고유해야 한다.</li>
<li>컬럼명 뒤에 데이터 유형과 데이터 크기가 명시되어야 한다.</li>
<li>테이블 내의 컬럼명 중복 X</li>
<li>컬럼에 대한 정의는 괄호() 안에 기술한다.</li>
<li>각 컬럼들은 ,(콤마)로 구분된다.</li>
<li>테이블 명과 컬럼명은 숫자로 시작될 수 없다.</li>
<li>마지막은 ;(세미콜론)으로 끝난다.</li>
<li><em>제약조건의 종류*</em></li>
</ul>
<table>
<thead>
<tr>
<th>CONSTRAINTS</th>
<th>NULL허용여부</th>
<th>데이터 중복 허용 여부</th>
<th>특징</th>
</tr>
</thead>
<tbody><tr>
<td>NOTNULL</td>
<td>NULL불가</td>
<td>중복 가능</td>
<td></td>
</tr>
<tr>
<td>UNIQUE</td>
<td>NULL가능</td>
<td>중복 불가(NULL끼리는 중복으로 간주하지 않음)</td>
<td></td>
</tr>
<tr>
<td>PK(고유키)</td>
<td>NULL불가</td>
<td>중복 불가</td>
<td>지정한 열은 유일한 값을 반드시 가져야함, 테이블 당 1개만 지정가능</td>
</tr>
<tr>
<td>FK(외래키)</td>
<td>다른 테이블 열을 참조하여 해당 테이블에 존재하는 값만 입력 가능, 다른 테이블의 고유키(PK)를 참조</td>
<td></td>
<td></td>
</tr>
<tr>
<td>CHECK</td>
<td>설정한 조건식을 만족하는 데이터만 입력가능 ,조건식을 만족하지 않는 데이터는 입력이 거부됨</td>
<td></td>
<td></td>
</tr>
</tbody></table>
<h2 id="alter">ALTER</h2>
<blockquote>
<p>테이블 구조를 변경해야 할 때 쓸 수 있는 명령어
① ADD COLUMN : 새로운 컬럼을 추가할 때 쓰는 명령어</p>
</blockquote>
<ul>
<li>ALTER TABLE 테이블명 ADD 컬럼명 데이터 유형;
② DROP COLUMN : 기존에 있던 컬럼이 필요 없어졌을 때 삭제하는 명령어</li>
<li>ALTER TABLE 테이블명 DROP COLUMN 컬럼명;
③ MODIFY COLUMN : 기존에 있던 컬럼을 변경하고 싶을 때 쓰는 명령어</li>
<li>ALTER TABLE 테이블명 MODIFY(컬럼명1 데이터유형[DEFAULT 값][NOTNULL], 컬럼명2 데이터 유형...);
④ RENAME COLUMN : 기존에 있던 컬럼의 이름을 변경하고 싶을 때 쓰는 명령어</li>
<li>ALTER TABLE 테이블명 RENAME COLUMN 기존 컬렴명 TO 변경할 컬럼명
⑤ ADD CONSTRAINT : 계약조건을 추가하고 싶을 때 쓰는 명령어</li>
<li>ALTER TABLE 테이블명 ADD CONSTRAINT 제약조건명 제약조건(컬럼명);</li>
</ul>
<h2 id="drop-table">DROP TABLE</h2>
<blockquote>
<p>테이블을 삭제할 때 쓰는 명령어</p>
</blockquote>
<ul>
<li>DROP TABLE 테이블명[CASCADE CONSTRAINT];</li>
</ul>
<h2 id="rename-table">RENAME TABLE</h2>
<blockquote>
<ul>
<li>테이블을 변경할 때 쓰는 명령어</li>
</ul>
</blockquote>
<ul>
<li>RENAME 기존 테이블명 TO 변경할 테이블명;</li>
</ul>
<h2 id="truncate-table">TRUNCATE TABLE</h2>
<blockquote>
<ul>
<li>테이블에 저장되어 있는 데이터를 모두 제거하는 명령어</li>
</ul>
</blockquote>
<ul>
<li>TRUNCATE TABLE 테이블명;</li>
</ul>
<h1 id="dcl">DCL</h1>
<blockquote>
<p>USER를 생성하고 권한을 부여해주는 명령어 : CREATE USER, ALTER USER, DROP USER</p>
</blockquote>
<h2 id="user-관련-명령어">USER 관련 명령어</h2>
<blockquote>
<p>① CREATE USER : 사용자를 생성하는 명령어</p>
</blockquote>
<ul>
<li>CREATE USER 사용자명 IDENTIFIED BY 패스워드;
② ALTER USER : 사용자를 변경하는 명령어</li>
<li>ALTER USER 사용자명 IDENTIFIED BY 패스워드;
③ DROP USER : 사용자를 삭제하는 명령어</li>
<li>DROP USER 사용자명;</li>
</ul>
<h2 id="권한-관련-명령어">권한 관련 명령어</h2>
<blockquote>
<p>① GRANT : 사용자에게 권한을 부여하는 명령어</p>
</blockquote>
<ul>
<li>GRANT 권한 TO 사용자명;
② REVOKE : 사용자에게 권한을 회수하는 명령어</li>
<li>REVOKE 권한 FROM 사용자명;</li>
</ul>
<h2 id="role-관련-명령어">ROLE 관련 명령어</h2>
<blockquote>
<p>① ROLE을 이용한 권한 부여
㉠. ROLE을 생성
-&gt; CREATE ROLE 롤명;
㉡. ROLE에 권한을 부여
-&gt; GRANT 권한 TO 롤명;
㉢. ROLE을 사용자에게 부여
-&gt; GRANT 롤명 TO 사용자명;</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[2-2 SQL 활용]]></title>
            <link>https://velog.io/@mangez_js/2-2-SQL-%ED%99%9C%EC%9A%A9</link>
            <guid>https://velog.io/@mangez_js/2-2-SQL-%ED%99%9C%EC%9A%A9</guid>
            <pubDate>Mon, 17 Feb 2025 12:51:51 GMT</pubDate>
            <description><![CDATA[<h1 id="서브쿼리">서브쿼리</h1>
<blockquote>
<p>하나의 SQL문 안에 포함되어 있는 또 다른 SQL문, 알려지지 않은 기준을 이용한 검색에 사용</p>
</blockquote>
<ul>
<li>괄호를 감싸서 사용</li>
<li>단일행 또는 복수행 비교연산자와 함께 사용 가능</li>
<li>ORDER BY 사용 불가</li>
<li>WHERE 구에 SELECT 문을 사용하면 서브쿼리
<img src="https://velog.velcdn.com/images/mangez_js/post/975b9946-68c1-4403-8c29-4ebdaf55a0d7/image.png" alt=""></li>
</ul>
<h2 id="스칼라-서브쿼리---select절">스칼라 서브쿼리 -&gt; SELECT절</h2>
<blockquote>
<p>컬럼을 반환하는 서브쿼리, 주로 SELECT에서 사용 -&gt; FROM절에는 올 수 없다.</p>
</blockquote>
<h2 id="인라인뷰다이나믹뷰---from-절">인라인뷰(다이나믹뷰) -&gt; FROM 절</h2>
<blockquote>
<p>FROM절에서 사용되는 서브쿼리 -&gt; 메인쿼리에서 사용 가능 ORDER BY를 사용 가능</p>
</blockquote>
<h2 id="중첩서브쿼리---where-having-절">중첩서브쿼리 -&gt; WHERE, HAVING 절</h2>
<blockquote>
<p>WHERE, HAVING
<strong>동작 방식</strong>
 ㉠. 비연관 서브쿼리 : 서브쿼리 내에 메인쿼리의 컬럼이 존재하지 않는다.
 ㉡. 연관 서브쿼리 : 서브쿼리 내에 메인쿼리의 컬럼이 존재
<strong>반환 데이터</strong>
 ㉠. 단일행 서브쿼리 : 실행결과 1건 이하
  -&gt; 단일행 비교연산자 : =, &lt;, &gt;, &lt;&gt; 등
 ㉡. 다중행 서브쿼리 : 실행결과 2건 이상
  ㉡-1 IN : 반환되는 여러 개의 행 중 하나만 참 이여도 참
    -&gt; WHERE COL1 IN(&#39;A&#39;, &#39;B&#39;)는 COL1 = &#39;A&#39; or COL1 = &#39;B&#39;를 의미
    -&gt; IN 안에 NULL이 와도 무시
    -&gt; WHERE COL1 NOT IN(a, b)은 COL1 ≠ a and COL1 ≠ b의미 그래서 NULL 포함이면 항상 거짓
   ㉡-2 ALL : 메인 서브 쿼리의 결과가 모두 동일하면 참
    -&gt; &#39;&lt;ALL:최솟값 반환&#39;,&#39;&gt;ALL:최댓값 반환&#39;
    -&gt; WHERE COL1 = ALL(서브쿼리)
   ㉡-3 ANY : 메인쿼리의 비교조건이 서브 쿼리 결과 중 하나 이상 동일하면 참
    -&gt; &#39;&lt;ANY:하나라도 크만 참&#39;,&#39;&gt;ANI=Y:하나라도 작으면 참&#39;
   ㉡-4 EXISTS : 서브쿼리로 어떤 데이터의 존재 여부를 확인
    -&gt; 메인/서브 쿼리의 결과가 하나라도 존재한다면 참
    -&gt; TRUE/FALSE -&gt; WHERE EXIST(서브쿼리)
  ㉢. 다중 컬럼 서브쿼리 : 실행결과 컬럼 여러 개 -&gt; SQL Server에서는 X</p>
</blockquote>
<h1 id="뷰">뷰</h1>
<blockquote>
<p>테이블로부터 유도된 가상의 테이블로 실제 데이터를 가지고 있지 않고 테이블을 참조해서 원하는 컬럼만 조회
<strong>장점</strong></p>
</blockquote>
<ul>
<li>독립성 : 테이블 구조가 변경되어도 뷰를 사용하는 응용프로그램은 변경하지 않아도 된다.</li>
<li>편리성 : 복잡한 질의를 뷰로 생성하여 질의 단순하게 가능. 또한 해당 SQL 자주 사용 시 뷰를 이용하면 편히</li>
<li>보안성 : 복잡한 쿼리 구문을 뷰명으로 단축시킴으로써 가독성을 높이고 편리하게 사용</li>
</ul>
<h1 id="집합-연산자">집합 연산자</h1>
<blockquote>
<p>조인을 사용하지 않고 연관 데이터를 조회하는 방법 중 하나로 2개 이상의 질의 결과를 하나로 만들어줌</p>
</blockquote>
<ul>
<li>UNION ALL(합집합) : 중복된 행도 그대로 출력<img src="https://velog.velcdn.com/images/mangez_js/post/9ed4c170-c21e-4a29-b47f-12e128d61a90/image.png" alt=""></li>
<li>UNION(합집합) : 중복된 행은 한 줄로 출력
<img src="https://velog.velcdn.com/images/mangez_js/post/f04efec1-43f5-4cd8-be48-e275c91d5e1d/image.png" alt=""></li>
<li>INTERSECT(교집합) : 중복된 행은 한 줄로 출력
<img src="https://velog.velcdn.com/images/mangez_js/post/926e3491-0fad-46c9-9d35-7e1fa9e2a447/image.png" alt=""></li>
<li>MINUS/EXCEPT(차집합) : 중복된 행은 한 줄로 출력
<img src="https://velog.velcdn.com/images/mangez_js/post/87011bfc-94b0-4470-9d0d-9741e01ba0d7/image.png" alt=""></li>
</ul>
<h1 id="그룹함수">그룹함수</h1>
<blockquote>
<p>특정 그룹에 대해 작업을 수행하고 결과를 반환하는 함수로 관계형</p>
</blockquote>
<ul>
<li>집계함수 : COUNT, SUM, AVG, MAX, MIN 등</li>
<li>소계(총계)합수 : ROLLUP, CUBE, GROUPING SETS 등</li>
</ul>
<h2 id="roll-up--소계와-총계-생성-인수의-순서가-바뀌면-다른-결과를-출력">ROLL UP : 소계와 총계 생성, 인수의 순서가 바뀌면 다른 결과를 출력</h2>
<pre><code>- ROLLUP(COL1) : COL1 별 그룹핑 + 총계
- ROLLUP(COL1, COL2) : 
COL1, COL2별 그룹핑 
+ COL1 
+ 총계
- ROLLUP((COL1, COL2), COL3) : 
COL1, COL2, COL3별 그룹핑 
+ COL1, COL2별 그룹핑 
+ 총계
- ROLLUP(COL1, (COL2, COL3)) : 
COL1, COL2, COL3별 그룹핑 
+ COL1 
+ 총계
- ROLLUP(COL1, COL2, COL3) : 
COL1, COL2, COL3별 그룹핑 
+ COL1, COL2별 그룹핑 
+ COL1 
+ 총계</code></pre><p><img src="https://velog.velcdn.com/images/mangez_js/post/8b2022a9-aac8-411a-a99f-695a22246ef8/image.png" alt=""></p>
<h2 id="cube--모든-경우의-수에-대해-소계와-총계-생성-roll-up에-비해-시스템에-부하-심함">CUBE : 모든 경우의 수에 대해 소계와 총계 생성, ROLL UP에 비해 시스템에 부하 심함</h2>
<pre><code class="language-TEXT">- CUBE(COL1) : COL1별 그룹핑 + 총계
- CUBE(COL1, COL2) : 
COL1, COL2별 그룹핑 
+ COL1 + COL2 
+ 총계
- CUBE((COL1, COL2), COL3) : 
COL1, COL2, COL3별 그룹핑 
+ COL1, COL2별 그룹핑 
+ COL3 
+ 총계
- CUBE(COL1, (COL2, COL3)) :
COL1, COL2, COL3별 그룹핑
+ COL1
+ COL2, COL3별 그룹핑
+ 총계
- CUBE(COL1, COL2, COL3) : 
COL1, COL2, COL3별 그룹핑 
+ COL1, COL2별 그룹핑 + COL1, COL3별 그룹핑 + COL2, COL3별 그룹핑 
+ COL1 + COL2 + COL3 
+ 총계</code></pre>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/7ea043b3-c79d-4c08-ab3d-a07d2d6d3d13/image.png" alt=""></p>
<h2 id="grouping-sets--rollup-cube와-다르게-계층이-나타나지-않고-그룹핑된-결과값만-보여줌---총계-x">GROUPING SETS : ROLLUP, CUBE와 다르게 계층이 나타나지 않고 그룹핑된 결과값만 보여줌 -&gt; 총계 X</h2>
<pre><code class="language-TEXT">- GROUPING SETS(COL1) : GROUP BY COL1과 동일
- GROUPING SETS(COL1, COL2) : COL1 + COL2
- GROUPING SETS(COL1, COL2, ()) : COL1 + COL2 + 총계
- GROUPING SETS(COL1, ROLLUP(COL2)) : COL1 + COL2 + 총계
- GROUPING SETS(COL1, COL2, COL3) :  COL1 + COL2 + COL3
- GROUPING SETS(COL1, COL2, ROLLUP(COL3)) : COL1 + COL2 + COL3 + 총계
- GROUPING SETS(COL1, ROLLUP(COL2, COL3)) : 
COL1 
+ COL2, COL3
+ COL2
+ 총계
- GROUPING SETS(ROLLUP(COL1, COL2), COL3) :
COL1, COL2
+ COL1 + COL3
+ 총계</code></pre>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/9a6c3bb1-3dc6-4e23-af93-1aaeacee1f43/image.png" alt=""></p>
<h2 id="grouping--집계-표시면-1-아니면-0---null-같은-것이-1로-표시되는데-이를-다른-문자로-바꿀-때-주로-사용">GROUPING : 집계 표시면 1, 아니면 0 -&gt; NULL 같은 것이 1로 표시되는데 이를 다른 문자로 바꿀 때 주로 사용</h2>
<blockquote>
<ul>
<li>OVER, PARTITION BY는 분석함수와 함께 사용</li>
</ul>
</blockquote>
<ul>
<li>SELECT SUM(SAL) OVER(PARTITION BY DEPT)</li>
</ul>
<h1 id="윈도우-함수">윈도우 함수</h1>
<blockquote>
<p>OVER 구문 필수, PARTITION BY 구문 이용하여 집계의 대상이 되는 레코드 범위를 지정</p>
</blockquote>
<h2 id="순위함수">순위함수</h2>
<blockquote>
<ul>
<li>RANK : 동일한 값에 대해서는 동일한 순위를 부여(1,2,2,4,5,5,7...)</li>
</ul>
</blockquote>
<ul>
<li>DENSE_RANK : 동일한 순위를 하나의 등수로 간주(1,2,2,3,4,4,5...)</li>
<li>ROW_NUMBER : 그냥 처음~마지막까지 고유한 순위 부여, 중복 X</li>
</ul>
<h2 id="집계함수">집계함수</h2>
<blockquote>
<ul>
<li>SUM/AVG : 파티션 별로 합계/평균을 계산</li>
</ul>
</blockquote>
<ul>
<li>COUNT : 파티션 별로 행 수를 계산</li>
<li>MAX/MIN : 파티션 별로 최댓값/최솟값 계산</li>
</ul>
<h2 id="행-순서-함수">행 순서 함수</h2>
<blockquote>
<ul>
<li>FIRST_VALUE : 파티션별 윈도우의 처음 값</li>
</ul>
</blockquote>
<ul>
<li>LAST_VALUE : 파티션별 윈도우의 마지막 값</li>
<li>LAG : 파티션별 윈도우에서 이전 몇번째 행의 값</li>
<li>LEAD : 파티션별 윈도우에서 이후 몇번째 행의 값</li>
</ul>
<h2 id="비율함수">비율함수</h2>
<blockquote>
<ul>
<li>RATIO_ID_REPORT : 파티션 내 전체 SUM에 대한 행별 컬럼 값의 백분율을 소수점까지 조회</li>
<li><blockquote>
<p>컬럼 값/ 전체 합한 값을 백분율로</p>
</blockquote>
</li>
</ul>
</blockquote>
<ul>
<li>PERCENT_RANK : 파티션에서 제일 먼저 나온 것은 0, 제일 늦게 나온 것은 1로 하여 값이 아닌 행의 순서 별 백분율 조회</li>
<li><blockquote>
<p>(현재 행 순위 -1)/ (전체 행 순위 -1)</p>
</blockquote>
</li>
<li>CUBE_DIST : 현재 행보다 작거나 같은 건수에 대한 누적 백분율로 구한다. 결과 값이 0보다 크고 1보다 작은 값을 가지는 함수</li>
<li><blockquote>
<p>그룹 1개 행 -&gt; 1
그룹 2개 행 -&gt; 0.5,1
그룹 3개 행 -&gt; 0.333, 0.666, 1</p>
</blockquote>
</li>
<li>NTILE : 파티션 별로 전체 건수를 인자 값으로 N등분한 결과를 조회</li>
<li>CURRENT ROW : 현재 행</li>
<li>UNBOUNDED PRECEDING : 첫번째 행, end point에서 사용 불가</li>
<li>UNBOUNDED FOLLOWING : 마지막 행, start point에서 사용 불가</li>
<li>n PRECEDING : 현재 행에서 위로 n만큼 이동</li>
<li>n FOLLOWING : 현재 행에서 아래로 n만큼 이동</li>
</ul>
<h1 id="top-n-쿼리">TOP-N 쿼리</h1>
<blockquote>
<ul>
<li>ROWNUM : 조회되는 행 수를 제한할 때 많이 사용(페이지 단위 출력은 인라인 뷰)</li>
</ul>
</blockquote>
<h1 id="셀프조인">셀프조인</h1>
<blockquote>
<p>나 자신과의 조인</p>
</blockquote>
<h1 id="계층-쿼리">계층 쿼리</h1>
<blockquote>
<p>테이블에 계층 구조를 이루는 컬럼이 존재할경우 계층 쿼리를 이용해서 데이터를 출력</p>
</blockquote>
<ul>
<li>LEVEL : 현재의 DEPTH를 반환. 루트 노드는 1이 된다.</li>
<li>SYS_CONNECT_BY_PATH(컬럼, 구분자) : 루드 노드부터 현재노드까지의 경로를 출력해주는 함수</li>
<li>START WITH : 경로가 시작되는 루드 노드를 생성해주는 절</li>
<li>CONNECT BY : 루드로부터 자식노드를 생성해주는 절, 조건에 만족하는 데이터가 없을 때 노드를 생성</li>
<li>PRIOR : 바로 앞에 있는 부모 노드의 값을 반환</li>
<li>CONNECT_BY_ROOT 컬럼 : 루드노드의 주어진 컬럼 값을 반환</li>
<li>CONNECT_BY_ISLEAF : 가장 하위 노드인 경우 1을 반환하고 그 외에는 0을 반환</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[2-1 SQL 기본]]></title>
            <link>https://velog.io/@mangez_js/2-1-SQL-%EA%B8%B0%EB%B3%B8</link>
            <guid>https://velog.io/@mangez_js/2-1-SQL-%EA%B8%B0%EB%B3%B8</guid>
            <pubDate>Sun, 16 Feb 2025 10:57:00 GMT</pubDate>
            <description><![CDATA[<h1 id="select문">SELECT문</h1>
<blockquote>
<p>FROM -&gt; WHERE -&gt; GROUP BY -&gt; HAVING -&gt; SELECT -&gt; ORDER BY
테이블에 입력된 데이터를 조회하기 위해서 사용되며, 특징 컬럼/행 만 조회 가능</p>
</blockquote>
<h2 id="문법">문법</h2>
<blockquote>
<p>① SELECT * : 모든 컬럼을 출력(&#39;*&#39;은 모든 컬럼을 의미)
② FROM 테이블명 : 테이블을 지정
③ WHERE 조건 : FROM에서 지정한 테이블의 조회 조건을 지정</p>
</blockquote>
<h2 id="컬럼-지정">컬럼 지정</h2>
<blockquote>
<p>① SELECT 컬럼1, 컬럼2 FROM 테이블 명;
 -&gt; 해당 테이블에서 컬럼 1,2만 출력
 ② SELECT * FROM 테이블 명;
 -&gt; 해당 테이블의 모든 컬럼과 행을 조회
 ③ SELECT 컬럼 1 :: &#39;문자&#39; FROM 테이블 명;
 -&gt; 해당 테이블의 모든 행에서 컬럼 1을 조회</p>
</blockquote>
<ul>
<li>단, 컬럼 1 뒤에 &#39;문자&#39;에 들어간 단어를 결합 / 컬럼 1 문자</li>
</ul>
<h1 id="함수">함수</h1>
<h2 id="문자-함수">문자 함수</h2>
<blockquote>
<p>① ASCII(문자) : 문자/숫자를 ASCII 코드 값으로 변환 
 -&gt; ex) CHR(65) -&gt; A
② LOWER(문자열) : 문자열을 소문자로 반환 
 -&gt; ex) LOWER(&#39;JENNIE&#39;) -&gt; jennie
③ UPPER(문자열) : 문자열을 대문자로 변환
 -&gt; ex) UPPER(&#39;jennie&#39;) -&gt; JENNIE
④ LTRIM(문자열, 지정 문자) : 왼쪽에서 지정된 문자를 삭제
 -&gt; ex) LTRIM(&#39;<code></code>JENNIE&#39;) -&gt; JENNIE
⑤ RTRIM(문자열, 지정 문자) : 오른쪽에서 지정된 문자를 삭제
 -&gt; ex) RTRIM(&#39;JENNIE<code></code>&#39;) -&gt; JENNIE
⑥ TRIM(문자열, 지정 문자) : 왼쪽 및 오른쪽에서 지정된 문자 삭제
 -&gt; ex) TRIM(&#39;<code></code>JENNIE<code></code>&#39;) -&gt; JENNIE
⑦ SUBSTR(문자열, m, n) : 문자열 m번째 위치부터 n개를 자름
 -&gt; ex) SUBSTR(&#39;블랙핑크제니&#39;, 3, 2) -&gt; 핑크
⑧ LENGTH(문자열) : 공백 포함 문자열의 길이를 알려줌
 -&gt; ex) LENGTH(&#39;JENNIE&#39;) -&gt; 6
⑨ REPLACE(문자열, 찾는 문자열, [변경할 문자열]) : 변경할 문자 미입력시 없앰.
 -&gt; ex) REPLACE(&#39;블랙핑크제니&#39;, &#39;제니&#39;, &#39;지수&#39;) -&gt; 블랙핑크지수
⑩ LPAD(문자열, 길이, 문자) : 문자열이 설정한 길이가 될 때 까지 왼쪽을 특정문자로 채우는 함수
 -&gt; ex) LPAD(&#39;JENNIE&#39;, 10, &#39;V&#39;) -&gt; VVVVJENNIE </p>
</blockquote>
<h2 id="숫자-함수">숫자 함수</h2>
<blockquote>
<p>① ABS(숫자) : 절대값 변환
 -&gt; ex) ABS(-1) -&gt; 1
② SIGN(숫자) : 양수, 음수, 0을 구분
 -&gt; ex) SIGN(-n) -&gt; -1, SIGN(n) -&gt; 1
③ ROUND(숫자, m) : 소수점 m자리에서 반올림(m의 기본 값은 0)
 -&gt; ex) ROUND(17.5) -&gt; 18
④ TRUNC(숫자, m) : 소수점 m자리에서 절삭(m의 기본 값은 0)
 -&gt; ex) TRUNC(18.5) -&gt; 18
⑤ CEIL(숫자) : 숫자보다 크거나 같은 최소의 정수 반환
 -&gt; ex) CEIL(17.5) -&gt; 18
⑥ FLOOR(숫자) : 숫자보다 작거나 같은 최대의 정수 반환
 -&gt; ex) FLOOR(17.5) -&gt; 17
⑦ MOD(숫자 1, 숫자 2) : 숫자 1을 숫자 2로 나눈 나머지를 계산
 -&gt; ex) MOD(15, 7) -&gt; 1</p>
</blockquote>
<h2 id="날짜-함수">날짜 함수</h2>
<blockquote>
<p>① SYSDATE : 오늘의 날짜를 날짜 타입으로 변환
② EXTRACT(YEAR FROM SYSDATE) : 날짜에서 년, 월, 일 조회
③ ADD_MONTHS(날짜 데이터, 특정 개월 수) : 날짜데이터에서 특정 개월 수를 더한 날짜를 반환해주는 함수
-&gt; ex) ADD_MONTHS(DATE &#39;2022-01-31&#39;, 1) -&gt; 2022-02-28</p>
</blockquote>
<h2 id="시간-연산">시간 연산</h2>
<blockquote>
<p>1/12 : 하루를 12 등분 한 값
-&gt; 24등분을 12롷 나누면 1은 2시간</p>
</blockquote>
<h2 id="변환-함수">변환 함수</h2>
<blockquote>
<p>① 명시적 형변환 : 변환함수를 사용하여 데이터 유형 변환을 명시적으로 나타냄
② 암시적 형변환 : 데이터베이스가 내부적으로 알아서 데이터 유형을 변환함
<strong>쓰이는 함수</strong>
ⓐ TO_NUMBER(문자열) : 문자열을 숫자형으로 변환해주는 함수
-&gt; TO_NUMBER(&#39;1234&#39;) -&gt; 1234
ⓑ TO_CHAT(숫자 or 날짜) : 숫자나 날짜형의 데이터를 포멧 형식의 문자형으로 변환해주는 함수
-&gt; TO_CHAT(1234) -&gt; &#39;1234&#39;
ⓒ TO_DATE(문자열, 포맷) : 포맷 형식의 문자형의 데이터를 날짜형으로 변환해주는 함수
-&gt; TO_DATE(&#39;20210602&#39;, &#39;YYYYMMDD&#39;) -&gt; 2021-06-02</p>
</blockquote>
<h2 id="null-관련-함수">NULL 관련 함수</h2>
<blockquote>
<p>① NVL(인수1, 인수2) : 인수1이 NULL일 경우 인수2 반환, 아니면 인수1을 반환
-&gt; ex) NVL(REVIEW_SCORE, 0), 컬럼 데이터가 NULL일 경우 0 반환, 널이 아닐 경우 컬럼 값 반환
② NULLIF(인수1, 인수2) : 인수1 == 인수2 이면 NULL을 반환, 아니면 인수1을 반환
③ COALESCE(인수1, 인수2, 인수3 ...) : NULL이 아닌 최초의 인수 반환
④ NVL2(인수1, 인수2, 인수3) : 인수1이 NULL이 아니면 인수2 반환, NULL인 경우 인수3 반환</p>
</blockquote>
<h2 id="case">CASE</h2>
<blockquote>
<p>조건을 WHERE구에 사용, 조건이 참이면 THEN 반환, 거짓이면 ELSE 반환
구조</p>
</blockquote>
<pre><code>CASE(expression)
 WHEN condition_1 THEN result_1
 WHEN condition_2 THEN result_2
 ... ELSE result END</code></pre><h1 id="where-절">WHERE 절</h1>
<blockquote>
<p>원하는 자료만을 검색하기 위한 조건문, 집계함수를 사용할 수 없다.
 연산자 종류</p>
</blockquote>
<h2 id="비교연산자">비교연산자</h2>
<table>
<thead>
<tr>
<th>비교연산자</th>
<th>비교연산자</th>
</tr>
</thead>
<tbody><tr>
<td>=</td>
<td>같음</td>
</tr>
<tr>
<td>&lt;</td>
<td>작음</td>
</tr>
<tr>
<td>&lt;=</td>
<td>작거나 같음</td>
</tr>
<tr>
<td>&gt;</td>
<td>큼</td>
</tr>
<tr>
<td>&gt;=</td>
<td>크거나 같음</td>
</tr>
</tbody></table>
<h2 id="부정비교자">부정비교자</h2>
<table>
<thead>
<tr>
<th>부정비교자</th>
<th>부정비교자</th>
</tr>
</thead>
<tbody><tr>
<td>!=</td>
<td>같지 않음</td>
</tr>
<tr>
<td>^=</td>
<td>같지 않음</td>
</tr>
<tr>
<td>&lt;&gt;</td>
<td>같지 않음</td>
</tr>
<tr>
<td>not 컬럼명 =</td>
<td>같지 않음</td>
</tr>
<tr>
<td>not 컬럼명 &gt;</td>
<td>크지 않음</td>
</tr>
</tbody></table>
<h2 id="sql-연산자">SQL 연산자</h2>
<p> ① BETWEEN A AND B : A와 B의 범위에 있는 값을 조회
 -&gt; Wherer col between 1 and 10
 ② LIKE &#39;비교문자열&#39; : 비교문자여을 조회 / % : 어떤 문자를 포함한 모든 것을 조회 / _(underscore) : 한개인 단일 문자를 의미
 -&gt; Where col like &#39;%탄소년%&#39;/ Where col like &#39;방_소%&#39;
 ③ IN(LIST) : LIST 값 중 하나만 일치해도 조회 / OR의 의미를 가지고 있어서 하나의 조건만 만족해도 조회
 -&gt; Where col in(1,3,5)
 ④ ISNULL : NULL 값을 조회 / NULL 값은 모르는 값, 값의 부재를 의미
  -&gt; ex) Where col is null</p>
<ul>
<li>NULL + 숫자/날짜 = NULL</li>
<li>NULL과 어떤 값을 비교한다면 &#39;알 수 없음&#39;이 반환</li>
</ul>
<h2 id="부정-sql-연산자">부정 SQL 연산자</h2>
<p> ① NOT BETWEEN A AND B : A와 B 사이에 해당되지 않은 값
 -&gt; ex) Where col not between 1 and 10
 ② NOT IN(LIST) : LIST와 불일치한 것을 조회
 -&gt; ex) Where col not in(1,3,5)
 ③ IS NOT NULL : NULL 값이 아닌 것을 조회
 -&gt; ex) Where col is not null</p>
<h2 id="논리-연산자">논리 연산자</h2>
<p>① AND : 조건을 모두 만족해야 TRUE 반환
-&gt; ex) Where col &gt; 1 and col &lt; 10
② OR : 조건 중 하나만 만족해도 TRUE 반환
-&gt; ex) Where col = 1 or col = 10
③ NOT : TRUE/FALSE의 결과 값을 반대로 출력
-&gt; ex) Where not col &gt; 10</p>
<h1 id="group-by">Group By</h1>
<blockquote>
<p>테이블에서 소규모 행을 그룹화하여 합계/평균/최댓값/최솟값을 계산, NULL 데이터도 집계에 포함</p>
</blockquote>
<h2 id="집계-함수">집계 함수</h2>
<p>① COUNT(*) : 테이블의 모든 행을 셉니다.
② COUNT(컬럼) : 해당 컬럼에서 NULL이 아닌 값만 셉니다.
③ COUNT(DISTINCT 컬럼) : 특정 열의 중복된 값을 제외하고 고유한 값의 개수
④ SUM(컬럼)/AVG(컬럼)/MIN(컬럼)/MAX(컬럼) : 합계/평균/최솟값/최댓값을 반환</p>
<h1 id="having">HAVING</h1>
<blockquote>
<p>GROUP BY에 조건절을 사용하기 위한 조건문
WHERE 절에 조건문을 사용하게 된다면 조건 충족을 하지 못하는 데이터들은 GROUP BY 대상에서 제외됨 </p>
</blockquote>
<h1 id="order-by">ORDER BY</h1>
<blockquote>
<p>결과를 특정 열을 기준으로 &quot;오름차순&quot; 또는 &quot;내림차순&quot;으로 정렬하는데 사용</p>
</blockquote>
<ul>
<li>ASC : 오름차순 *Default값</li>
<li>DESC : 내림차순</li>
</ul>
<h1 id="join">JOIN</h1>
<blockquote>
<p>여러 개의 릴레이션을 사용하여 새로운 릴레이션을 만드는 과정
<img src="https://velog.velcdn.com/images/mangez_js/post/e0f9c81f-30fb-4960-8677-d5470d21c272/image.png" alt="">
<img src="https://velog.velcdn.com/images/mangez_js/post/74c66b7a-c8ef-44a2-8348-8fcbc6770217/image.png" alt="">
① EQUI JOIN(등가)</p>
</blockquote>
<ul>
<li>조인의 가장 기본으로 두 개의 테이블 간에 일치하는 것을 조인</li>
<li>&quot;=&quot;을 사용하여 두 개의 테이블을 연결
②-① NON EQUI JOIN(비등가)</li>
<li>정확하게 일치하지 않는 것을 조인</li>
<li>&quot;&gt;&quot;, &quot;&lt;&quot;, &quot;&gt;=&quot;, &quot;&lt;=&quot; 사용
②-② STANDARD JOIN</li>
<li>ANSI/ISO 표준 SQL에서 규정
① INNER JOIN</li>
<li>JOIN 조건에서 동일한 값이 있는 행만 반환(ON으로 테이블 연결)
② OUTER JOIN</li>
<li>두 개의 테이블 간에 EQUI JOIN을 조회하고 한 쪽 테이블에만 있는 데이터도 포함시켜서 조회(동일한 값이 없는 행도 반환)
1) LEFT OUTER JOIN<ul>
<li>두 테이블에서 같은 것을 조회하고 좌측 테이블 데이터를 포함해서 조회</li>
<li>우측 값에서 좌측과 같은 데이터가 없는 경우 NULL
<img src="https://velog.velcdn.com/images/mangez_js/post/4ec74c29-2cd5-4b48-bd5f-4b2e43f2760a/image.png" alt="">
2) RIGHT OUTER JOIN</li>
<li>두 테이블에서 같은 것을 조회하고 우측 테이블 데이터를 포함해서 조회</li>
<li>좌측 테이블의 NULL인 행도 조회
<img src="https://velog.velcdn.com/images/mangez_js/post/2e1de377-1ea2-45ac-9266-6ddfd9ecad91/image.png" alt="">
3) NATURAL JOIN</li>
<li>두 개에 테이블에 공통인 행만 남기는 것</li>
<li>ON절 사용 불가
4) CROSS JOIN</li>
<li>조인 조건구 없이 두 개의 테이블을 하나로 조인</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[재귀 알고리즘]]></title>
            <link>https://velog.io/@mangez_js/%EC%9E%AC%EA%B7%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-st0v427w</link>
            <guid>https://velog.io/@mangez_js/%EC%9E%AC%EA%B7%80-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-st0v427w</guid>
            <pubDate>Sat, 15 Feb 2025 13:07:53 GMT</pubDate>
            <description><![CDATA[<h1 id="재귀란">재귀란?</h1>
<blockquote>
<p>어떤 사건이 자기 자신을 포함하고 있거나 또는 자기 자신을 사용하여 정의하고 있을 때 이를 재귀적(recursive)이라고 합니다</p>
</blockquote>
<ul>
<li>1은 자연수입니다.</li>
<li>자연수 n의 바로 다음 정수도 자연수입니다.</li>
</ul>
<h2 id="팩토리얼-구하기">팩토리얼 구하기</h2>
<ul>
<li><p>0 != 1</p>
</li>
<li><p>n &gt; 0이면 n! = n X (n-1)!</p>
<pre><code class="language-java">class Factorial{
  static int factorial(int n){
      if(n &gt; 0)
          return n * factorial(n - 1);
      else
          return 1;
  }

  public static void main(String[] args){
      Scanner stdIn = new Scanner(System.in);

      int x = stdIn.nextInt();

      System.out.println(factorial(x));
  }
}</code></pre>
</li>
<li><p>매개변수 n에 전달받은 값이 0보다 클 때 : n * factorial(n-1)</p>
</li>
<li><p>매개변수 n에 전달받은 값이 0보다 크지 않을 때 : 1
<code>return (n &gt; 0) ? n * factorial(n - 1) : 1;</code>
<img src="https://velog.velcdn.com/images/mangez_js/post/41f1b03b-5c79-4da5-b381-6aba48c7e7bc/image.png" alt=""></p>
</li>
</ul>
<h2 id="유클리드-호제법">유클리드 호제법</h2>
<blockquote>
<p>두 정수의 최대공약수를 재귀적으로 구하는 방법
<img src="https://velog.velcdn.com/images/mangez_js/post/ff2ae90c-4fe4-4722-bde9-b27be9d75b54/image.png" alt=""></p>
</blockquote>
<pre><code class="language-java">class EuclidGCDP
    static int gcd(int x, int y){
        if(y == 0)
            return x;
        else
            return gcd(y, x % y);
    }

    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);
        int x = stdIn.nextInt();
        int y = stdIn.nextInt();

        System.out.println(gcd(x, y)
    }
}</code></pre>
<h1 id="재귀-알고리즘-분석">재귀 알고리즘 분석</h1>
<h2 id="하향식-분석">하향식 분석</h2>
<p>recur(4)
① recur(3)을 실행
② 4를 출력
③ recur(2)를 실행
<img src="https://velog.velcdn.com/images/mangez_js/post/6766b88a-5194-4073-bd78-cc205e469c72/image.png" alt=""></p>
<h2 id="상향식-분석">상향식 분석</h2>
<p>recur(1)
① recur(0)을 실행
② 1를 출력
③ recur(-1)를 실행
<img src="https://velog.velcdn.com/images/mangez_js/post/80cd7240-bb94-4eed-8a26-ec943c6a8a0b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[1-1 데이터 모델의 이해]]></title>
            <link>https://velog.io/@mangez_js/1-1-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@mangez_js/1-1-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Thu, 13 Feb 2025 14:31:33 GMT</pubDate>
            <description><![CDATA[<h1 id="데이터-모델링">데이터 모델링</h1>
<blockquote>
<p>데이터 모델링은 <strong>현실 세계</strong>를 단순화하여 표현하는 기법</p>
</blockquote>
<h2 id="데이터-모델링-특징추∙단∙명">데이터 모델링 특징(추∙단∙명)</h2>
<blockquote>
<ul>
<li>추상화 : 현실세계, 개념을 <strong>일정한 형식</strong>으로 <strong>간략하게</strong> 표현</li>
</ul>
</blockquote>
<ul>
<li>단순화 : 현실세계를 <strong>정해진 표기법</strong>으로 <strong>단순하고 쉽게 표현</strong>, 핵심에 집중 + <strong>불필요 제거</strong></li>
<li>명확화 : <strong>불분명함(애매모호함)</strong>을 제거하고 <strong>정확하게 현상을 기술</strong></li>
</ul>
<h3 id="특징">특징</h3>
<blockquote>
<ul>
<li>업무 설명, 분석, 형상화 목적도 있음</li>
</ul>
</blockquote>
<ul>
<li>개발 및 데이터 관리에도 사용</li>
</ul>
<h2 id="데이터-모델링의-3가지-관점">데이터 모델링의 3가지 관점</h2>
<blockquote>
<ul>
<li>데이터 관점(What, Data)<ul>
<li>업무와 데이터 및 데이터 사이의 관계를 모델링</li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li>프로세스 관점(How, Process)<ul>
<li>업무가 실제로 하고 있는 일, 해야 하는 일 모델링</li>
</ul>
</li>
<li>데이터와 프로세스의 상관 관점(Data VS Process, Intercation)<ul>
<li>데이터에 대한 업무 처리 방식의 영향을 모델링</li>
</ul>
</li>
</ul>
<h3 id="데이터-모델링의-중요성과-유의성">데이터 모델링의 중요성과 유의성</h3>
<blockquote>
<p>① 중요성 : 파급효과, 간결한 표현, 데이터 품질 유지
② 유의점
     - 중복 : 같은 데이터가 엔티티에 중복 저장되면 안된다.
    - 비유연성 : 애플리케이션의 <strong>사소한 변경</strong>에도 데이터 모델이 수시로 변경되면 안된다.
    -&gt;  <strong>데이터 모델과 프로세스 분리</strong>해서 유연성 높여야한다.
    - 비일관성 : 중복이 없는 경우에도 비일관성 발생 가능성 있음
    -&gt; 데이터 간의 <strong>연관 관계에 대해 명확</strong>하게 정의</p>
</blockquote>
<h2 id="데이터-모델링의-3단계개∙논∙물">데이터 모델링의 3단계(개∙논∙물)</h2>
<blockquote>
<ul>
<li>개념적 모델링 : ERD 도출, 업무중심적이고 포괄적(추상화 레벨 가장 높음)</li>
</ul>
</blockquote>
<ul>
<li>논리적 모델링 : 테이블 도출, (Key, 속성, 관계)를 표현, 재사용성↑, 정규화 수행</li>
<li>물리적 모델링 : DB 구축, 물리적 성격, 개념적 보다 구체적</li>
</ul>
<h2 id="데이터의-독립성">데이터의 독립성</h2>
<blockquote>
<p>데이터의 구조가 변경되어도 응용 프로그램이 변경될 필요가 없음
필요성</p>
</blockquote>
<ul>
<li>유지보수 비용</li>
<li>데이터 복잡도</li>
<li>데이터 중복성</li>
<li>요구사항 대응</li>
</ul>
<h2 id="테이터-스키마-단계에-따른-독립성외∙개∙내---논리적-물리적">테이터 스키마 단계에 따른 독립성(외∙개∙내 -&gt; 논리적, 물리적)</h2>
<blockquote>
<p>스키마 : 테이블이 어떠한 구성으로 되어있는지, 어떤 정보를 가지고 있는지에 대한 기본적인 테이블의 구조를 정의
<strong>USER</strong></p>
</blockquote>
<ul>
<li>외부 스키마 : 사용자 관점, View 관점, 개개인의 사용자나 프로그래머</li>
<li>개념 스키마 : 모든(여러X) 사용자 관점 통합, 조직 전체 DB, 통합 관점</li>
<li>내부 스키마 : 물리적인 저장 구조를 나타내는 단계 -&gt; 저장 구조, 칼럼, 인덱스 정의
<strong>DB</strong></li>
<li>논리적 독립성 : 개념 스키마가 변경 되어도 외부 스키마는 영향 X (외부 - 개념)</li>
<li>물리적 독립성 : 내부 스키마가 변경 되어도 개념/외부 스키마는 영향 X(외부,개념 - 내부)</li>
</ul>
<h2 id="erd-작성-순서도∙배∙관∙명∙참∙필">ERD 작성 순서(도∙배∙관∙명∙참∙필)</h2>
<blockquote>
<ol>
<li>엔티티 도출</li>
<li>엔티티 배치</li>
<li>엔티티 관계 설정</li>
<li>관계명 기입</li>
<li>관계 참여도 기입</li>
<li>관계 필수/선택 여부 기입
<img src="https://velog.velcdn.com/images/mangez_js/post/7511bfdf-20de-4122-8cdc-6aa8d8862b93/image.png" alt="">
<img src="https://velog.velcdn.com/images/mangez_js/post/2ec9eb83-b686-4c34-bf79-da7459606afa/image.png" alt=""></li>
</ol>
</blockquote>
<h1 id="엔티티">엔티티</h1>
<blockquote>
<p>업무에서 쓰이는 데이터들을 용도별로 분류한 데이터의 그룹
<strong>엔티티의 특징</strong></p>
</blockquote>
<ul>
<li>업무에서 쓰이는 정보 </li>
<li>식별자가 있어야함</li>
<li>2개 이상의 인스턴스를 가져야함</li>
<li>반드시 속성을 가져야함 -&gt; 이 때 하나의 인스턴스는 2개 이상의 속성을 가짐 -&gt; 즉, 하나의 엔티티는 2개 이상의 속성을 가짐</li>
<li>다른 엔티티와 1개 이상의 관계</li>
</ul>
<h2 id="엔티티의-분류">엔티티의 분류</h2>
<blockquote>
<h3 id="유형∙무형에-따른-분류개사유-계셔유">유형∙무형에 따른 분류(개사유~ 계셔유~)</h3>
</blockquote>
<ul>
<li>유형 엔티티 : 물리적인 형태 O ex) 상품, 회원, 사원, 물품, 강사</li>
<li>개념 엔티티 : 물리적인 형태 X ex) 부서, 학과, 조직, 보험 상품</li>
<li>사건 엔티티 : 행위로 읺한 발생 ex) 주문, 이벤트 응모, 청구, 미납<h3 id="발생시점에-따른-분류행기중">발생시점에 따른 분류(행기중)</h3>
</li>
<li>기본 엔티티 : 업무에 대해 원래 존재하는 요소 -&gt; 독립적, 자식 엔티티 가질 수 있음 ex) 상품, 회원, 부서</li>
<li>중심 엔티티 : 업무 과정 중 하나, 기본 엔티티로부터 파생, 행위 엔티티 생성 ex) 주문, 매출, 계약</li>
<li>행위 엔티티 : 2개 이상의 엔티티로부터 파생 ex) 주문 내역, 이벤트 응모 이력</li>
</ul>
<h2 id="엔티티의-명명">엔티티의 명명</h2>
<ul>
<li>현업 업무에서 사용하는 용어</li>
<li>약어 X, 영어 대문자로 표시</li>
<li>단순 명사로 표현, 띄어쓰기 X</li>
<li>의미상 중복 X(주문, 결제 엔티티는 중복 O)</li>
<li>명확하게 표현</li>
</ul>
<h1 id="속성">속성</h1>
<blockquote>
<p>엔티티의 특징을 나타내는 최소의 데이터 단위</p>
</blockquote>
<h3 id="특징-1">특징</h3>
<blockquote>
<ul>
<li>더 이상 쪼개지지 않는 레벨</li>
</ul>
</blockquote>
<ul>
<li>업무에서 필요로 하는 항목</li>
<li>엔티티를 설명, 인스턴스를 설명</li>
<li><strong>하나의 속성</strong>은 <strong>하나의 속성값</strong>만 가짐 -&gt; 여러 개 가지면 1차 정규화</li>
<li>일반 속성은 정해진 주식별자에 함수적 종속성을 가져야 한다. -&gt; 완전 함수적 종속이 아닌 부분 종속이면 2차 정규화 해준다.</li>
</ul>
<h2 id="속성-분류">속성 분류</h2>
<blockquote>
<h3 id="특성에-따른-분류">특성에 따른 분류</h3>
</blockquote>
<ul>
<li>기본 속성 : 업무 프로세스(기본 틀) 분석했더니 <strong>바로 정의 가능한 속성</strong></li>
<li>설계 속성(인스턴스에 유니크함을 부여하는 속성) : 업무엔 없으니ㅏ, 모델링 하다보니 고유함 보전하기 위해 필요해져서 만들어짐 ex) 학번, 사번</li>
<li>파생 속성(성능, 편의 위해 서로 만든 엔티티의 속성) : 데이터를 조회할 때 빠른 성능 낼 수 있도록 원래 속성값을 계산하여 저장할 수 있도록 하는 속성 ex) 평균, 재고 -&gt; <em>데이터 정합성 고려 &amp; 가급적 적게 정의</em><h3 id="구성-방식에-따른-분류">구성 방식에 따른 분류</h3>
<ul>
<li>PK 속성 : 인스턴스의 유니크함을 부여하는 속성, 일반 속성들의 종속성을 가진 키</li>
<li>(기본키, 주식별자 키) #으로 표현 ex) 학번, 사번</li>
<li>FK 속성 : 다른 엔티티에서 가져온 속성(외래키), 다른 엔티티와의 관계를 맺게 해줌</li>
<li><blockquote>
<p>주식별자에 있는 속성이 FK가 될 수 있음 ex) #사원번호(FK), g</p>
</blockquote>
</li>
<li>일반 속성 : PK, FK를 제외한 나머지 속성<h3 id="속성의-분해-가능-여부에-따른-분류">속성의 분해 가능 여부에 따른 분류</h3>
</li>
</ul>
</li>
<li>단일 속성 : 속성이 하나의 의미로 구성</li>
<li>복합 속성 : 여러 개의 의미로 구성(주소 = 시+구+동)</li>
<li>다중값 속성 : 속성이 여러 개 값 가짐 -&gt; 1차 정규화 OR 별도 엔티티 생성</li>
</ul>
<h2 id="속성이-만들어낸-데이터-모델의-개념">속성이 만들어낸 데이터 모델의 개념</h2>
<blockquote>
<h3 id="도메인">도메인</h3>
<p> : 속성이 가질 수 있는 속성 값의 범위</p>
</blockquote>
<h3 id="용어-사전">용어 사전</h3>
<p> : 속성의 <strong>이름을 정확, 직관적으로 부여하기 위한 용어 사전</strong></p>
<h3 id="시스템-카탈로그">시스템 카탈로그</h3>
<p> : 시스템 자체에 관련있는 데이터를 가진 DB
 : 시스템 테이블로 구성 &amp; SQL로 조회 가능
 : 여기 저장된 데이터 = 메타 데이터, SELECT만 가능, INSERT, UPDATE 등 불가능</p>
<h1 id="관계">관계</h1>
<blockquote>
<p>엔티티와 엔티티 사이에 속성끼리의 연결에 의해 만들어지는 상관 관계</p>
</blockquote>
<h3 id="종류">종류</h3>
<ul>
<li>존재 관계 : 모델링 된 엔티티들이 존재로서 관계를 가짐</li>
<li>행위 관계 : 모델링 된 엔티티들이 행위에 의해 관계를 가짐<h3 id="uml의-클래스다이어그램에-의해-나뉘는-종류">UML의 클래스다이어그램에 의해 나뉘는 종류</h3>
</li>
<li>연관 관계 : 필수적 관계(존재적 관계, 식별자 관계) - 항상 서로 이용(실선)<pre><code>    - 멤버 변수로 선언</code></pre></li>
<li>의존 관계 : 선택적 관계(비식별자 관계) - 상대 클래스 행위에 따라 이용(점선)<pre><code>   - 행위 코드 오퍼레이션에서 파라미터로 사용</code></pre></li>
</ul>
<h2 id="관계-표기-방법erd에-따른-특성-분류">관계 표기 방법(ERD)에 따른 특성 분류</h2>
<blockquote>
<ul>
<li>관계명 : 관계 이름은 시작 엔티티 - 능동적/끝 엔티티 -수동적 <strong>동사</strong> 사용</li>
</ul>
</blockquote>
<ul>
<li>관계 차수 : 각 엔티티 끼리의 관계에 참여하는 <strong>속성의 수</strong> 1:1, 1:M, M:N 형식으로 구분</li>
<li>관계 선택 사양 : <strong>필수적 관계</strong>(엔티티끼리 항상 관계), <strong>선택적 관계</strong>(행위에 의해 관계 여부가 성립)<h3 id="관계-체크-사항두-엔티티-사이-관계-정의-시-유의할-사항">관계 체크 사항(두 엔티티 사이 관계 정의 시 유의할 사항)</h3>
</li>
<li>두 엔티티 사이 <strong>관심있는 연관 규칙</strong>이 존재하는가</li>
<li>두 엔티티 사이 <strong>정보의 조합</strong>이 발생하는가</li>
<li>업무 기술 시, 장표의 관계 연결을 가능하게하는 <strong>동사</strong>가 있는가</li>
<li>업무 기술 시, 장표의 관계 연결을 가능하게하는 <strong>규칙이 서술</strong> 되어 있는가</li>
</ul>
<h1 id="식별자">식별자</h1>
<blockquote>
<p>각각의 인스턴스를 구분 가능하게 만들어주는 대표 속성</p>
</blockquote>
<h2 id="주식별자">주식별자</h2>
<blockquote>
<p>PK에 해당하는 속성 -&gt; PK는 여러 개 존재 할 수 있음</p>
</blockquote>
<ul>
<li>유일성 : 해당 속성이 인스턴스를 유일하게 식별할 수 있는 성질을 가졌는지</li>
<li>최소성 : 최소한의 속성들로만 유일성을 보장하게 하는지</li>
<li>불변성 : 속성 값이 변하지 않아야함</li>
<li>존재성 : 속성값은 NULL이 될 수 없음</li>
</ul>
<h2 id="식별자의-특성-여부에-따른-분류">식별자의 특성 여부에 따른 분류</h2>
<blockquote>
<h3 id="대표성-여부">대표성 여부</h3>
</blockquote>
<ul>
<li>주식별자(PK) - #으로 표현
: 유일성, 최소성, 불변성, 존재성을 모두 만족하는 식별자</li>
<li>보조식별자
: 인스턴스 식별은 가능하나 엔티티를 대표하는 식별자는 아님
-&gt; 즉, 다른 엔티티와의 참조 관계로 연결되지 않는다.<h3 id="스스로-생성-되었는가에-대한-여부">스스로 생성 되었는가에 대한 여부</h3>
</li>
<li>내부식별자
: 다른 엔티티 참조 없이 해당 엔티티 내부에서 스스로 생성된 식별자</li>
<li>외부식별자
: 다른 엔티티에서 온 식별자 - 다른 엔티티와 연결고리 역할
-&gt; 만약, 부모 엔티티의 FK를 받아서 이를 주식별자로 사용하면
-&gt; 해당 자식엔티티의 PK는 SQL 조인에서 반드시 사용되고 WHERE 절에서 사용 가능성이 높음<h3 id="단일-속성의-여부주식별자-구성이-여러-속성인가">단일 속성의 여부(주식별자 구성이 여러 속성인가)</h3>
</li>
<li>단일식별자
: 주식별자가 1개의 속성으로 구성</li>
<li>복합식별자
: 주식별자가 2개 이상의 속성으로 구성
-&gt; 주식별자가 2개 이상이면 해당 속성들의 우선순위를 잘 매겨서 복합 시킨 후
-&gt; 일반 속성들에게 종속 시켜야 주식별자로서 기능을 다 하게 된다.<h3 id="대체여부">대체여부</h3>
</li>
<li>원조(본질)식별자
: 업무에 의해 만들어지는 식별자, 가공되지 않은 원래 식별자</li>
<li>인조(대리)식별자
: 인위적으로 만들어지는 식별자, 주식별자가 복잡할 때 이를 통합
<img src="https://velog.velcdn.com/images/mangez_js/post/70698278-3503-4855-8a3e-673b39787c06/image.png" alt=""></li>
</ul>
<h2 id="식별자강한-연결관계-vs-비식별자약한-연결관계">식별자(강한 연결관계) VS 비식별자(약한 연결관계)</h2>
<blockquote>
<ul>
<li>식별자 관계(트랜잭션에 의해 관계∙동시에 커밋, 롤백-하나의 커밋 단위로 엔티티들이 묶임
: 부모 엔티티의 식별자 속성이 <strong>자식 엔티티의 주식별자</strong>가 되는 관계
: SQL 문의 조인을 최소화 해줌</li>
</ul>
</blockquote>
<ul>
<li>비식별자 관계
: 부모 엔티티의 식별자 속성이 <strong>자식 엔티티의 일반 속성</strong>이 되는 관계</li>
</ul>
<h1 id="key의-종류">KEY의 종류</h1>
<blockquote>
<p>논리 모델링에서 식별자가 물리 모델링에서는 Key가 되는데 이를 Key의 특징에 따라 다음과 같이 분류
① 기본키(PK)</p>
</blockquote>
<ul>
<li>엔티티를 대표할 수 있는 키
② 후보키(Candidate Key)</li>
<li>유일성과 최소성을 만족하는 키</li>
<li>결국 후보키들 중 하나가 기본키가 되고, 나머지를 대체키라고 부름
③ 슈퍼키(Super Key)</li>
<li>유일성은 만족하지만 최소성은 만족하지 않는 키
ex) 학생 테이블에서 학번으로만 PK를 구성해도 되는데, (학번+이름)으로 구성한다면 이는 슈퍼키
④ 대체키(AlternateKey)</li>
<li>여러 후보키 중 기본키가 아닌 키
⑤ 외래키(FK)</li>
<li>다른 테이블의 기본키를 참조하는 키</li>
<li>참조 테입를은 하나 또는 여러 개 가능</li>
</ul>
<blockquote>
<h6 id="참고문헌">참고문헌</h6>
<p><a href="https://www.youtube.com/watch?v=xmkaOqbTQRE">https://www.youtube.com/watch?v=xmkaOqbTQRE</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[1-2 데이터 모델과 SQL]]></title>
            <link>https://velog.io/@mangez_js/1-2-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-SQL</link>
            <guid>https://velog.io/@mangez_js/1-2-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EA%B3%BC-SQL</guid>
            <pubDate>Wed, 12 Feb 2025 14:46:29 GMT</pubDate>
            <description><![CDATA[<h1 id="정규화">정규화</h1>
<blockquote>
<p>ERD내에서 중복요소를 찾아 제거해 나가는 과정</p>
</blockquote>
<h1 id="데이터베이스-정규화-절차">데이터베이스 정규화 절차</h1>
<blockquote>
<p>함수 종속성을 이용해 릴레이션을 연관성이 있는 속성들로만 구성되도록 분해해서 이상현상이 발생하지 않도록 Step By Step Approach로 수행</p>
</blockquote>
<h2 id="제-1-정규화">제 1 정규화</h2>
<blockquote>
<p>같은 성격과 내용의 컬럼이 연속적으로 나타내는 컬럼이 존재할 때, 해당 컬럼을 제거하고 기본테이블의 PK를 추가해 새로운 테이블을 생성하고, 기존의 테이블과 1:N 관계를 형성하는 것
-&gt; <strong>모든 속성은 반드시 하나의 값만 가져야됨 =&gt; 원자값</strong>
<img src="https://velog.velcdn.com/images/mangez_js/post/d17688af-ac71-4099-a258-3ead02e9cd6b/image.png" alt="">
tag 필드를 보면, 값들이 여러개가 있다 하나의 필드에 값들이 여러개 있으며 안된다.
<strong>이를 정규화 시키면</strong></p>
</blockquote>
<ol>
<li>우선 하나의 title과 여러개의 tag를 갖는다. 또한 하나의 tag(rdb)는 여러개의 title(MySQL, Oracle)을 갖는다.</li>
<li>그러면 title과 tag를 테이블 두 개로 분리했을 때 이들의 관계는 M:N이 된다.</li>
<li>M:N을 표현하기 위해선 테이블 3개를 만들어야 한다.</li>
<li>title과 topic 테이블을 분단시키고, 그 중간경로 테이블인 topic_tag_relation을 만든다. 그리고 각 테이블을 이어올 새로운 태그 tag_id 속성을 만든다.</li>
<li>각각 1:N 관계를 연결해주면 정규화가 완료한 것.
<img src="https://velog.velcdn.com/images/mangez_js/post/2b6fdbcb-8039-4d60-a190-c7c41b7e8c55/image.png" alt=""></li>
</ol>
<h2 id="제-2-정규화">제 2 정규화</h2>
<blockquote>
<p>PK가 여러 키로 구성된 복합키로 구성된 경우가 2차 정규화의 대상이 되며, 복합키 전체에 의존하지 않고 복합키의 일부분에만 종속되는 속성들이 존재할 경우 (즉, 부분적 함수 종속 관계) 이를 분리 하는 것
-&gt; <strong>엔티티의 일반속성은 주식별자 전체에 종속 &gt; 완전 종속 =&gt; 부분 함수 종속 제거</strong>
<img src="https://velog.velcdn.com/images/mangez_js/post/d5b19e47-aa90-4b59-be4b-6fa7ce243bc9/image.png" alt=""></p>
</blockquote>
<ol>
<li>제 1정규화를 마친 테이블을 보면, 중복되는 레코드(적갈색)가 보인다.</li>
<li>저 부분이 중복되어 나타나는 이유는 type와 price 필드 값이 각기 다르기 때문이다.</li>
<li>그러면 각기 다른 부분을 테이블로 나누고 중복부분을 하나로 표현 되게 해보자</li>
<li>먼저 중복이 나타나게 한 원인 필드인 type와 price 필드를 따로 빼서 topic_type 테이블을 만든다.</li>
<li>그러고 topic_type에서 식별 할 수 있는 외래키 title을 등록</li>
<li>이렇게 하면, 중복되는 것이 없이 title이 MySQL이냐 아니냐에 따라 topic 테이블에선 저자정보, topic_type 테이블에선 가격과 타입을 각각 나타낼 수 있게 된다.
<img src="https://velog.velcdn.com/images/mangez_js/post/6d07e088-443d-4443-8cbe-3634813695a0/image.png" alt=""></li>
</ol>
<h2 id="제-3-정규화">제 3 정규화</h2>
<blockquote>
<p>테이블의 키가 아닌 컬럼들은 기본키에 의존해야 하는데 겉으로는 그런 것처럼 보이지만 실제로는 기본키가 아닌 다른 일반 컬럼에 의존하는 컬럼들이 있을 수 있다.
이를 이전적 함수 종속 관계 라고 한다.
제 3정규화는 PK에 의존하지 않고 일반 컬럼에 의존하는 컬럼들을 분리한다.
-&gt; <strong>엔티티의 일반속성 간에는 서로 종속 X =&gt; 이행 종속 제거</strong>
<img src="https://velog.velcdn.com/images/mangez_js/post/cc073078-3f6b-4b43-bde3-0907c5ac23aa/image.png" alt=""></p>
</blockquote>
<ol>
<li>제 2정규화를 마쳤지만 여전히 중복된 값(노란색)이 보인다.</li>
<li>저 레코드는 author_id에 의존하는 컬럼들이다. 언뜻보면 title에 의존하는 것처럼 보이지만 아닌 것이다.</li>
<li>그럼 PK(title)에 의존하지 않는 컬럼들을 분단</li>
<li>author라는 테이블을 만들고 중복되는 컬럼들 3개를 그대로 따온다. 그리고 topic 테이블과 author_id로 외래키 관계를 맺어준다. 그러면 중복이 사라지는 것을 볼 수 있다.
<img src="https://velog.velcdn.com/images/mangez_js/post/d2d9e020-0882-4445-828a-88d2bc1d7162/image.png" alt=""></li>
</ol>
<h1 id="반정규화">반정규화</h1>
<blockquote>
<ul>
<li>정규화 된 데이터 모델(엔티티, 속성, 관계)에 대해 <strong>성능 향상</strong>, <strong>개발, 운영의 단순화</strong>를 위해 <strong>데이터를 중복, 통합, 분리하는 기법</strong></li>
</ul>
</blockquote>
<ul>
<li>정규화 시 엔티티의 갯수 증가 -&gt; 여러 조인 요구 -&gt; 이런 경우 디스크 I/O 양이 많아져 성능이 저하되거나 경로가 멀어서 <strong>조인</strong>으로 인한 <strong>성능 저하가 예상</strong><h2 id="특징">특징</h2>
<ul>
<li>조회(SELECT) 속도 향상</li>
<li>-&gt; 입력/수정/삭제 성능 저하</li>
</ul>
</li>
</ul>
<h2 id="테이블-반정규화">테이블 반정규화</h2>
<blockquote>
<table>
<thead>
<tr>
<th>테이블 병합</th>
<th>테이블 분할</th>
<th>테이블 추가</th>
</tr>
</thead>
<tbody><tr>
<td>1:1 관계 테이블 병합</td>
<td>테이블 수직 분할(속성 분할)</td>
<td>중복 테이블 추가</td>
</tr>
<tr>
<td>1:M 관계 테이블 병합</td>
<td>테이블 수평 분할(인스턴스 분할, 파티셔닝</td>
<td>통계 테이블 추가</td>
</tr>
<tr>
<td>슈퍼 서브 타입 테이블 병합</td>
<td></td>
<td>이력 테이블 추가</td>
</tr>
<tr>
<td>-&gt; 공통 속성과 개별 속성을 별도로 관리하는 설계 타입</td>
<td></td>
<td>부분 테이블 추가</td>
</tr>
</tbody></table>
</blockquote>
<h2 id="컬럼-반정규화">컬럼 반정규화</h2>
<blockquote>
<ul>
<li>중복 컬럼 추가 : 조회 감소를 위해 중복 컬럼 추가  ex) 최근 상품 가격</li>
</ul>
</blockquote>
<ul>
<li>파생 컬럼 추가 : 미리 값을 계산하여 컬럼에 보관</li>
<li>이력 테이블 컬럼 추가 : 대량의 이력 데이터를 처리할 때 가능성 컬럼(최근값 여부, 시작 &amp; 종료일 등)을 추가</li>
</ul>
<h2 id="관계-반정규화">관계 반정규화</h2>
<blockquote>
<ul>
<li>중복 관계 추가 : 여러 경로를 거쳐 조인을 할 수 있찌만, 성능 저하를 예방하기 위해 추가적인 관계를 맺음
-&gt; 데이터무결성은 깨뜨릴 위험성이 없음.</li>
</ul>
</blockquote>
<h1 id="트랜잭션">트랜잭션</h1>
<blockquote>
<p>데이터를 조작하기 위한 논리적인 작업 단위</p>
</blockquote>
<h1 id="null">NULL</h1>
<blockquote>
<ul>
<li>NULL은 존재하지 않음, 즉 값이 없음을 의미</li>
</ul>
</blockquote>
<ul>
<li><p>Not Null, PK로 정의되지 않은 데이터 유형은 Null 값 포함가능</p>
</li>
<li><p>Null 연산 결과 -&gt; Null</p>
</li>
<li><p>Null 비교 결과 -&gt; Unknown or False</p>
<blockquote>
<ul>
<li>NVL/ISNULL 비교 =&gt; null 0이나 x 등으로 치환</li>
</ul>
</blockquote>
</li>
<li><p>NVL(a,0) : a가 null이면 0을 반환</p>
</li>
<li><p>NVL2(a,1,0) : a가 null이 아니면 1을 반환, null이면 0을 반환</p>
</li>
<li><p>NULLIF(a,b) : a와 b가 일치하면 null을 반환, 일치하지 않으면 a를 반환</p>
</li>
<li><p>COALESE(a,b,c,d) : NULL이 아닌 최초의 인자 값을 반환</p>
</li>
</ul>
<h1 id="이상">이상</h1>
<blockquote>
<ul>
<li>삽입 이상 : 데이터 삽입 시 의도했던 데이터 외에 다른 값들도 삽입됨</li>
</ul>
</blockquote>
<ul>
<li>갱신 이상 : 속성 값 변경 시 일부 레코드만 변경되어 일관성이 깨짐</li>
<li>삭제 이상 : 데이터 삭제 시 의도했던 데이터 외에 다른 값들도 연쇄 삭제됨.</li>
</ul>
<blockquote>
<h6 id="참고문헌">참고문헌</h6>
<p><a href="https://inpa.tistory.com/entry/DB-%F0%9F%93%9A-%EC%A0%9C-1-2-3-%EC%A0%95%EA%B7%9C%ED%99%94-%EC%97%AD%EC%A0%95%EA%B7%9C%ED%99%94">https://inpa.tistory.com/entry/DB-%F0%9F%93%9A-%EC%A0%9C-1-2-3-%EC%A0%95%EA%B7%9C%ED%99%94-%EC%97%AD%EC%A0%95%EA%B7%9C%ED%99%94</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[깃 브랜치 전략]]></title>
            <link>https://velog.io/@mangez_js/%EA%B9%83-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EC%A0%84%EB%9E%B5</link>
            <guid>https://velog.io/@mangez_js/%EA%B9%83-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EC%A0%84%EB%9E%B5</guid>
            <pubDate>Tue, 11 Feb 2025 15:34:50 GMT</pubDate>
            <description><![CDATA[<h1 id="git-브랜치-전략">GIT 브랜치 전략</h1>
<hr>
<blockquote>
<p>브랜치 전략이 <strong>여러 개발자가 하나의 저장소를 사용하는 환경에서 저장소를 효과적으로 활용</strong> 하기 위한 work-flow
브랜치의 생성, 삭제, 병합 등의 git의 유연한 구조로 활용해서, 각 개발자들의 혼란을 최대한 줄이며 다앙한 방식으로 소스를 관리하는 역할
<strong>브랜치 생성에 규칙을 만들어서 협업을 유연하게 하는 방법론</strong></p>
</blockquote>
<h1 id="git-flow-전략">GIT-FLOW 전략</h1>
<hr>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/1ea1ea42-1f5a-47b4-bacc-0e67474998ba/image.png" alt=""></p>
</blockquote>
<ul>
<li>기본적인 가지의 이름은 아래의 5가지로 구분</li>
<li>feature &gt; develop &gt; release &gt; hotfix &gt; master</li>
<li>위 순서들은 왼쪽으로 갈수록 포괄적인 가지이며 master branch를 병합할 경우 그 왼쪽에 있는 hotfit 등 모든 가지들에 있는 커밋들도 병합하도록 구성</li>
<li>5가지 중, 항시 유지되는 메인 브랜치 master, develop 2가지와 merge 되면 사라지는 보조 브랜치 feature, release, hotfix 3가지로 구성</li>
</ul>
<h2 id="git-flow-브랜치-구조">Git-flow 브랜치 구조</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/17c2f772-389d-49b5-8b7f-35a1c66888e7/image.png" alt=""></p>
</blockquote>
<ul>
<li>master : 라이브 서버에 제품으로 출시되는 브랜치</li>
<li>develop : 다음 출시 버전을 대비하여 개발하는 브랜치</li>
<li>feature : 추가 기능 개발 브랜치, develop 브랜치에 들어간다.</li>
<li>release : 다음 버전 출시를 준비하는 브랜치, develop 브랜치를 release 브랜치로 옮긴 후 QA, 테스트를 진행하고 master 브랜치로 합친다.</li>
<li>hotfix : master 브랜치에서 발생한 버그를 수정하는 브랜치</li>
</ul>
<h3 id="메인-브랜치">메인 브랜치</h3>
<blockquote>
<p>메인 브랜치는 master 브랜치와 develop 브랜치 두 종류를 말한다.
<img src="https://velog.velcdn.com/images/mangez_js/post/7d4fc129-e038-43a3-b3e9-89eb80ce47d3/image.png" alt="">
master 브랜치는 배포 가능한 상태만을 관리하는 브랜치를 말하며,
develop 브랜치는 다음에 배포할 것을 개발하는 브랜치
즉, develop 브랜치는 통합 브랜치의 역할을 하며, 평소에는 이 브랜치를 기반으로 개발을 진행한다.</p>
</blockquote>
<h3 id="보조-브랜치">보조 브랜치</h3>
<blockquote>
<p>보조 브랜치는 피처 브랜치(feature branch) 또는 토픽 브랜치(topic branch)를 말한다.
<img src="https://velog.velcdn.com/images/mangez_js/post/47625290-5b73-4db8-8dae-5950b430c317/image.png" alt=""></p>
</blockquote>
<ul>
<li>가지가 뻗어나오는 곳 : develop</li>
<li>뻗어나갔던 가지가 다시 합쳐지는 곳 : develop</li>
<li>이름 설정 : master, develop, release-<em>, hotfix-</em>를 제외하기만 하면 자유롭게 이름 설정이 가능하다.</li>
<li>새로운 기능을 추가할 때 주로 사용하는 가지이다.
master 브랜치에서 develop 브랜치를 만들었고,
develop 브랜치에서 다시 feature 브랜치를 나눠 작업을 하고 있는 것을 그림을 통해 알 수 있다.</li>
</ul>
<p>develop 브랜치에는 기존에 잘 작동하는 개발코드가 담겨있으며, 보조 브랜치는 새로 변경될 개발코드를 분리하고 각각 보존하는 역할을 한다.
보조 브랜치는 <strong>기능을 다 완성할 때까지 유지하고, 다 완성되면 develop 브랜치로 merget하고 결과가 좋지 못하면 버리는 방향</strong>
보조 브랜치는 보통 개발자 저장소에만 있는 브랜치고, origin 에는 push하지 않는다.</p>
<h3 id="릴리즈-브랜치">릴리즈 브랜치</h3>
<blockquote>
<p>배포를 위한 최종적인 버그 수정 등의 개발을 수행하는 브랜치
<img src="https://velog.velcdn.com/images/mangez_js/post/6c5c4b51-b8f4-43b7-a84f-703354e1dea8/image.png" alt=""></p>
</blockquote>
<ul>
<li>가지가 뻗어나오는 곳 : develop</li>
<li>뻗어나갔던 가지가 다시 합쳐지는 곳 : develop, master</li>
<li>이름 설정 : release-*</li>
<li>새로운 제품을 배포하고자 할 때 사용하는 가지
develop 브랜체으는 버전에 포함되는 기능이 merge 되었다면 QA를 위해 develop 브랜치에서부터 release브랜치를 생성
배포 가능한 상태가 되면 master 브랜치로 병합시키고, 출시된 master 브랜치에 버전 태그(ex, v0.1, v0.2)를 추가</li>
</ul>
<h3 id="핫픽스-브랜치">핫픽스 브랜치</h3>
<blockquote>
<p>핫픽스 브랜치는 배포한 버전에서 긴급하게 수정할 필요가 있을 때 master 브랜치에서 분리하는 브랜치를 말한다.
<img src="https://velog.velcdn.com/images/mangez_js/post/efde6478-74b5-4140-990b-964262b107ee/image.png" alt=""></p>
</blockquote>
<ul>
<li>가지가 뻗어나오는 곳 : master</li>
<li>뻗어나갔던 가지가 다시 합쳐지는 곳 : develop, master</li>
<li>이름 설정 : hotfix-*</li>
<li>제품에서 버그가 발생했을 경우에는 처리를 위해 이 가지로 해당 정보들을 모아준다.
버그를 잡는 사람이 일하는 동안에도 다른 사람들은 develop 브랜치에서 하던 일을 계속할 수 있다.
이때 만든 hotfit 브랜치에서의 변경 사항은 develop 브랜치에도 merge하여 문제가 되는 부분을 처리해줘야 한다.</li>
</ul>
<h2 id="git-flow-흐름">Git flow 흐름</h2>
<h3 id="1-신규-기능-개발">1. 신규 기능 개발</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/0a757ced-96ac-4d08-9c8f-98624d409f76/image.png" alt=""></p>
</blockquote>
<ul>
<li>개발자는 develop 브랜치로부터 본인이 신규 개발할 기능을 위한 feature 브랜치를 생성</li>
<li>feature 브랜치에서 기능을 완성하면 develop 브랜치에 merge를 진행</li>
</ul>
<h3 id="2-라이브-서버로-배포">2. 라이브 서버로 배포</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/b7edfcf9-d086-4923-a663-9d4dea969dad/image.png" alt=""></p>
</blockquote>
<ul>
<li>feature 브랜치들이 모두 develop 브랜치에 merge 되었다면 QA를 위해 release 브랜치를 생성</li>
<li>release 브랜치를 통해 오류가 확인된다면 release 브랜치 내에서 수정을 진행</li>
<li>QA와 테스트를 모두 통과했다면, 배포를 위해 release 브랜치를 master 브랜치 쪽으로 merge하며,</li>
<li>만일 release 브랜치 내부에서 오류 수정이 진행되었을 경우 동기화를 위해 develop 브랜치 쪽에도 merge를 진행</li>
</ul>
<h3 id="3-배포-후-관리">3. 배포 후 관리</h3>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/dc868708-4b3e-477e-b95c-71669a05abc6/image.png" alt=""></p>
</blockquote>
<ul>
<li>만일 배포된 라이브 서버에서 버그가 발생된다면, hotfix 브랜치를 생성하여 버그 픽스를 진행</li>
<li>그리고 종료된 버그 픽스를 master와 develop 양 쪽에 merge하여 동기화</li>
</ul>
<h1 id="github-flow-전략">GITHUB-FLOW 전략</h1>
<hr>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/906320e7-5bc3-4eed-b481-3363a3654d09/image.png" alt=""></p>
</blockquote>
<ul>
<li>Git flow가 좋은 방식이지만 GitHub에 적용하기에는 복잡하다는 Scott Chacon의 판단에 따라 만들어진 새로운 깃 관리 방식</li>
<li>자동화 개념이 들어가 있다 라는 큰 특징이 존재하며 만일 장도화가 적용되어 있지 않은 곳에서만 수동으로 진행하면 된다</li>
<li>Git flow에 비해 흐름이 단순해짐에 따라 그 규칙도 단순</li>
<li>기본적으로 master branch에 대한 규칙만 정확하게 정립되어 있다면 나머지 가지들에 대해서는 특별한 관여를 하지 않으며 pull request 기능을 사용하도록 권장</li>
</ul>
<h2 id="github-flow-특징">GitHub-Flow 특징</h2>
<ul>
<li>release branch가 명확하게 구분되지 않은 시스템에서의 사용이 유용</li>
<li>GitHub 자체의 서비스 특성상 배포의 개념이 없는 시스템으로 되어있기 때문에 이 flow가 유용</li>
<li>웹 서비스들에 배포의 개념이 없어지고 있는 추세이기 때문에 앞으로도 Git flow에 비해 사용하기에 더 수월</li>
<li>hotfix와 가장 작은 기능을 구분하지 않는다.</li>
</ul>
<h1 id="github-flow-흐름">Github-Flow 흐름</h1>
<hr>
<h2 id="1-브랜치-생성">1. 브랜치 생성</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/f178c486-e96c-41c0-b54c-02b9980bb900/image.png" alt="">
Github-flow 전략은 기능 개발, 버그 픽스 등 어떤 이유로든 새로운 브랜치를 생성
이때 체계적인 분류 없이 브랜치 하나에 의존하기 때문에 브랜치 이름을 통해 의도를 명확하게 드러내는 것이 매우 중요</p>
</blockquote>
<h2 id="2-개발--커밋--푸쉬">2. 개발 &amp; 커밋 &amp; 푸쉬</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/172a2e13-e96d-453c-a2d6-d52060bb1971/image.png" alt="">
개발을 진행하면서 커밋을 남긴다.
이때도 브랜치와 같이 커밋 메시지에 의존해야 하기 때문에, 커밋 메시지를 최대한 상세하게 적어주는 것이 중요</p>
</blockquote>
<h2 id="3-prpull-request-생성">3. PR(Pull Request) 생성</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/7eae8a15-aef8-42dd-a86b-e00c0f0ff888/image.png" alt="">
피드백이나 도움이 필요할 때, 그리고 merge 준비가 완료되었을 때는 pull request를 생성</p>
</blockquote>
<h2 id="4-리뷰--토의">4. 리뷰 &amp; 토의</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/414c90b1-4b06-4fa9-a2fa-168ebd11a3b6/image.png" alt="">
Pull-Request가 master 브랜치 쪽에 합쳐진다면 곧장 라이브 서버에 배포되는 것과 다름 없으므로, 상세한 리뷰와 토의가 이루어져야 한다.</p>
</blockquote>
<h2 id="5-테스트">5. 테스트</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/0173d524-a484-4891-bbe4-5cfdc4a2528b/image.png" alt="">
리뷰와 토의가 끝났다면 해당 내용을 라이브 서버(혹은 테스트 환경)에 배포
배포 시 문제가 발생한다면 곧장 master 브랜치의 내용을 다시 배포하여 초기화</p>
</blockquote>
<h2 id="6-최종-merge">6. 최종 Merge</h2>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/1198dcb9-2e11-4fb4-87a4-b19337f44a63/image.png" alt="">
라이브 서버(혹은 테스트 환경)에 배포했음에도 문제가 발견되지 않았다면 그대로 master 브랜치에 푸시를 하고, 즉시 배포</p>
</blockquote>
<h1 id="github-flow-vs-git-flow">github flow VS git flow</h1>
<hr>
<blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/b21388de-bc84-4845-a6f8-8f41e8035afb/image.png" alt=""></p>
</blockquote>
<ul>
<li>1개월 이상의 긴 호흡으로 개발하여 주기적으로 배포, QA 및 테스트, hotfix 등 수행할 수 있는 여력이 있는 팀이라면 <code>git-flow</code>가 적합</li>
<li>수시로 릴리즈 되어야 할 필요가 있는 서비스를 지속적으로 테스트하고 배포하는 팀이라면 <code>github-flow</code> 와 같은 간단한 work-flow가 적합하다.</li>
</ul>
<blockquote>
<h6 id="참고문헌">참고문헌</h6>
<p><a href="https://inpa.tistory.com/entry/GIT-%E2%9A%A1%EF%B8%8F-github-flow-git-flow-%F0%9F%93%88-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EC%A0%84%EB%9E%B5#github-flow_%EC%A0%84%EB%9E%B5">https://inpa.tistory.com/entry/GIT-%E2%9A%A1%EF%B8%8F-github-flow-git-flow-%F0%9F%93%88-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EC%A0%84%EB%9E%B5#github-flow_%EC%A0%84%EB%9E%B5</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[GIT 개념 & 원리]]></title>
            <link>https://velog.io/@mangez_js/GIT-%EA%B0%9C%EB%85%90-%EC%9B%90%EB%A6%AC</link>
            <guid>https://velog.io/@mangez_js/GIT-%EA%B0%9C%EB%85%90-%EC%9B%90%EB%A6%AC</guid>
            <pubDate>Tue, 11 Feb 2025 14:51:16 GMT</pubDate>
            <description><![CDATA[<h1 id="git-이란-무엇인가">Git 이란 무엇인가?</h1>
<blockquote>
<p>Git이란 <strong>분산형 버전 관리 시스템(Version Control System)</strong>의 한 종류이며, 빠른 수행 속도에 중점을 둔다.</p>
</blockquote>
<h2 id="버전-관리란">버전 관리란?</h2>
<blockquote>
<p>버전관리 시스템은 파일 변화를 시간에 따라 기록했다가 나중에 <strong>특정시점의 버전을 다시 꺼내올 수 있는 시스템</strong></p>
</blockquote>
<ul>
<li>각 파일을 이전 상태로 되돌릴 수 있다.</li>
<li>프로젝트를 통째로 이전 상태로 되돌릴 수 있다.</li>
<li>시간에 따라 수정 내용을 비교해 볼 수 있다.</li>
<li>누가 문제를 일으켰는지도 추적할 수 있다.</li>
<li>누가언제만들어낸이슈인지도 알 수 있다.</li>
<li>파일을 잃어버리거나 잘못 고쳤을 때도 쉽게 복구할 수 있다.</li>
</ul>
<h2 id="git의-필요성">Git의 필요성</h2>
<blockquote>
<p>모두 같은 환경에서 개발하여 불필요한 시간을 없애고 서로 주고 받는 와중에 일어나는 충돌을 최소화 하는 것
프레임워크를 갖추고 공통으로 쓰는 코도들을 미리 넣어두고, 테스트 코드나 샘플코드들을 넣어주어서 프로젝트 개발 시작하기전에 팀원 모두 같은 코드로 테스트 할 수 있는 환경도 제공</p>
</blockquote>
<h2 id="git의-장점">Git의 장점</h2>
<blockquote>
<ul>
<li>여러 명이 동시에 작업하는 병렬 개발이 가능</li>
</ul>
</blockquote>
<ul>
<li>인터넷이 연결되지 않은 곳에서도 개발을 진행</li>
<li>개인 프로젝트일지라도 Git을 통해 관리를 하면 체계적인 개발이 가능해지고, 프로그램이나 패치를 배포하는 과정도 간단해진다.</li>
</ul>
<h2 id="git-작동-구조">Git 작동 구조</h2>
<blockquote>
<p>① 내가 작업한것들(로컬저장소)
② 원격저장소로 밀어내거나(push)
③ 원격저장소에서 최신 형상을 내 작업공간으로(로컬저장소) 당겨온다(pull)
<img src="https://velog.velcdn.com/images/mangez_js/post/521c3192-8ba7-4352-b27c-b1790b6b190f/image.png" alt=""></p>
</blockquote>
<h1 id="git-버전-관리-원리-이해하기">Git 버전 관리 원리 이해하기</h1>
<hr>
<h2 id="그림으로-이해하는-버전-관리-원리">그림으로 이해하는 버전 관리 원리</h2>
<blockquote>
<p>만일 도화지에 그림을 그리고, 각 그림 완성도 마다 버전 관리를 한다고 가정</p>
</blockquote>
<ul>
<li><p>먼저 그림을 그리고,
<img src="https://velog.velcdn.com/images/mangez_js/post/5fdf293a-3df7-4bcc-aad8-cee457c5c16f/image.png" alt=""></p>
</li>
<li><p>이렇게 사진첩 현재 상태를 저장
<img src="https://velog.velcdn.com/images/mangez_js/post/7754f09d-e388-4e90-a39a-101eaeb9e488/image.png" alt=""></p>
</li>
<li><p>그리고 내일 작업을 이어나가 눈코입을 그렸다고 하자
<img src="https://velog.velcdn.com/images/mangez_js/post/e52ad566-9562-412c-b636-66169b4603ad/image.png" alt=""></p>
</li>
<li><p>다시 작업한 내용을 사진첩에 추가로 저장했다.
<img src="https://velog.velcdn.com/images/mangez_js/post/0f1df833-a67f-464d-a727-799bd4b018b8/image.png" alt=""></p>
</li>
<li><p>머리와 수염을 그리고 이 역시 사진첩에 추가로 저장</p>
</li>
<li><p>사진첩에는 총 3개의 작업내용이 버전별로 저장된 것을 확인 할 수 있다.</p>
</li>
<li><p>각 작업들의 순서를 매겨줘서 버전 순서를 기억
<img src="https://velog.velcdn.com/images/mangez_js/post/62184b1a-f596-4f43-8353-69d6b62e40d1/image.png" alt=""></p>
</li>
<li><p>하지만 git은 숫자로 인덱싱하지않고, 해시값으로 인덱싱</p>
</li>
<li><p>해시값은 중복이 안된다고 봐도 무방</p>
</li>
<li><p>단, 해시값으로 순서를 알 수 없으니 트리처럼 부모를 각 노드마다 기록해주어 진행순서를 알 수 있게 한다.
<img src="https://velog.velcdn.com/images/mangez_js/post/decc151c-274d-4ec3-86dd-11f7cfef018b/image.png" alt=""></p>
</li>
<li><p>만일 머리를 다시 그리고 싶다면, 이전 버전인 해시값 AB9C8을 참조하여 다시 가져온다.
<img src="https://velog.velcdn.com/images/mangez_js/post/7c25355e-e09d-48f1-a322-74e364119740/image.png" alt=""></p>
</li>
<li><p>그리고 머리를 다시 그리고, 사진첩에 추가로 저장(B3A12)</p>
</li>
<li><p>작업순서를 기억하기 위해 부모를 기록
<img src="https://velog.velcdn.com/images/mangez_js/post/d97425a7-0ce4-428e-86c0-8ba5167ab4d0/image.png" alt=""></p>
</li>
<li><p>작업이 분기로 두가지로 나뉘어지니까</p>
</li>
<li><p>어느 작업이 무엇인지 알기 쉽게 작업명을 붙여준다.
<img src="https://velog.velcdn.com/images/mangez_js/post/c3be3e97-90a7-4d6c-a100-98532799bbf9/image.png" alt=""></p>
</li>
</ul>
<h2 id="git-기본-용어">Git 기본 용어</h2>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/c58e41d8-af8d-4e50-a818-6419ea5d4acf/image.png" alt=""></p>
<p><strong>Repository</strong></p>
<blockquote>
<p>스테이지에서 대기하고 있던 파일들을 버전으로 만들어 저장하는 곳
Git은 원격 저장소와 로컬 저장소 두 종류의 저장소를 제공</p>
</blockquote>
<p><strong>원격 저장소(Remote Repository)</strong></p>
<blockquote>
<p>파일이 원격 저장소 전용 서버에서 관리되며 여러 사람이 함께 공유하기 위한 저장소</p>
</blockquote>
<p><strong>로컬 저장소(Local Repository)</strong></p>
<blockquote>
<p>내 PC에 파일이 저장되는 개인 전용 저장소
아예 저장소를 새로 만들거나, 이미 만들어져 있는 원격 저장소를 로컬 저장소로 복사해 올 수 있다.
<img src="https://velog.velcdn.com/images/mangez_js/post/9b8190dc-09b5-483d-bdc1-5167fb963716/image.png" alt="">
스테이지 내용은 .git/index 파일에 저장되고, 저장소의 내용은 .git/HEAD 파일에 저장</p>
</blockquote>
<p><strong>Working Tree(Working Directory)</strong></p>
<blockquote>
<p>저장소를 어느 한 시점을 바라보는 작업자의 현재 시점
파일 수정, 저장 등의 작업을 하는 디렉토리로, 작업 디렉트로(working directory)라고도 한다.</p>
</blockquote>
<p><strong>SnapShot</strong></p>
<blockquote>
<p>특정 시점에서 파일, 폴더 또는 워크스페이스의 상태를 의미
스냅샷을 통해 특정 시점에 어떤 파일에 어떤 내용이 기록되어 있었는지, 폴더 구조는 어떠했는지, 어떤 파일이 존재했는지 등 저장소의 모든 정보를 확인</p>
</blockquote>
<p><strong>Checkout</strong></p>
<blockquote>
<p>이전 버전 작업을 불러오는 것</p>
</blockquote>
<p><strong>Staging Area</strong></p>
<blockquote>
<p>저장소에 커밋하기 전에 커밋을 준비하는 위치</p>
</blockquote>
<p><strong>Commit</strong></p>
<blockquote>
<p>현재 변경된 작업 상태를 점검을 마치면 확정하고 저장소에 저장하는 작업</p>
</blockquote>
<p><strong>Head</strong></p>
<blockquote>
<p>현재 작업중인 Branch를 가리킨다.</p>
</blockquote>
<p><strong>Branch</strong></p>
<blockquote>
<p>가지 또는 분기점을 의미하며, 작업을 할때에 현재 상태를 복사하여 Branch에서 작업을 한 후에 완전하다 싶을 때 Merge를 하여 작업을 한다.</p>
</blockquote>
<p><strong>Merge</strong></p>
<blockquote>
<p>다른 Branch의 내용을 현재 Branch로 가져와 합치는 작업을 의미</p>
</blockquote>
<blockquote>
</blockquote>
<h6 id="참고-문헌">참고 문헌</h6>
<p><a href="https://inpa.tistory.com/entry/GIT-%E2%9A%A1%EF%B8%8F-%EA%B0%9C%EB%85%90-%EC%9B%90%EB%A6%AC-%EC%89%BD%EA%B2%8C%EC%9D%B4%ED%95%B4#git_%EC%9E%91%EB%8F%99_%EA%B5%AC%EC%A1%B0">https://inpa.tistory.com/entry/GIT-%E2%9A%A1%EF%B8%8F-%EA%B0%9C%EB%85%90-%EC%9B%90%EB%A6%AC-%EC%89%BD%EA%B2%8C%EC%9D%B4%ED%95%B4#git_%EC%9E%91%EB%8F%99_%EA%B5%AC%EC%A1%B0</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[REST API]]></title>
            <link>https://velog.io/@mangez_js/REST-API</link>
            <guid>https://velog.io/@mangez_js/REST-API</guid>
            <pubDate>Tue, 11 Feb 2025 14:28:46 GMT</pubDate>
            <description><![CDATA[<h1 id="rest-api의-탄생">REST API의 탄생</h1>
<hr>
<blockquote>
<p>REST는 <code>Representational State Transfer</code>라는 용어의 약자로서 2000년도 로이 필딩의 박사학위 논문에서 최초로 소개되었습니다.
로이 필딩은 HTTP의 주요 저자 중 한 사람으로 그 당시 웹(HTTP) 설계의 우수성에 비해 제대로 사용되어지지 못하는 모습에 안타까워하며 웹의 장점을 최대한 활용할 수 있는 아키텍처로써 REST를 발표했다고 합니다.</p>
</blockquote>
<h1 id="rest-구성">REST 구성</h1>
<hr>
<blockquote>
<p>자원(RESOURCE) - URI
행위(Verb) - HTTP METHOD
표현(Representations)</p>
</blockquote>
<h3 id="http-uri">HTTP URI</h3>
<blockquote>
<p>Uniform Resource Identifier
<img src="https://velog.velcdn.com/images/mangez_js/post/2cb099dc-ddba-44ac-82d0-612549313239/image.png" alt=""></p>
</blockquote>
<p>** 구성 요소 **</p>
<ul>
<li>URL(Uniform Resource Locator)<ul>
<li>Scheme : 리소스에 접근하기 위한 프로토콜 기본은 https</li>
<li>Host : 리소스를 호스팅 하는 서버 이름</li>
<li>Port : 외부에서 서버의 리소스에 접근하기 위해 사용되는 게이트</li>
</ul>
</li>
<li>UBN(Uniform Resource Name)<ul>
<li>Path : 호스트 내 리소스의 위치</li>
<li>Query Parameters : 리소스에 전달되는 추가 정보</li>
<li>Fragment Identifier : 부가적인 식별자</li>
</ul>
</li>
</ul>
<h1 id="rest의-특징">REST의 특징</h1>
<hr>
<h2 id="1-uniform유니폼-인터페이스">1) Uniform(유니폼 인터페이스)</h2>
<blockquote>
<p>Uniform Interface는 <strong>바로 URI로 지정한 리소스에 대한 조작을 통일되고 한정적인 인터페이스로 수행하는 아키텍처 스타일</strong></p>
</blockquote>
<h2 id="2-stateless무상태성">2) Stateless(무상태성)</h2>
<blockquote>
<p>작업을 위한 상태정보를 따로 저장하고 관리하지 않습니다.
세션 정보나 쿠키정보를 별도로 저장하고 관리하지 않기 때문에 API 서버는 들어오는 요청만을 단순히 처리하면 됩니다.
때문에 <strong>서비스의 자유도가 높아지고 서버에서 불필요한 정보를 관리하지 않음으로써 구현이 단순해집니다.</strong></p>
</blockquote>
<h2 id="3-cacheable캐시-가능">3) Cacheable(캐시 가능)</h2>
<blockquote>
<p>가장 큰 특징 중 하나는 HTTP라는 기존 웹표준을 그대로 사용하기 때문에, 웹에서 사용하는 기존 인프라를 그대로 활용이 가능합니다. 
따라서, <strong>HTTP가 가진 캐싱 기능이 적용 가능합니다.</strong></p>
</blockquote>
<h2 id="4-self-descriptiveness자체-표현-구조">4) Self-descriptiveness(자체 표현 구조)</h2>
<blockquote>
<p>REST API 메시지만 보고도 이를 쉽게 이해 할 수 있는 자체 표현 구조이다</p>
</blockquote>
<h2 id="5-client-server-구조">5) Client-Server 구조</h2>
<blockquote>
<p>REST 서버는 API 제공
클라이언트는 사용자 인증이나 컨텍스트(세션, 로그인 정보) 등을 직접 관리하는 구조로 각각의 역할이 확실히 구분</p>
</blockquote>
<h2 id="6-계층형-구조">6) 계층형 구조</h2>
<blockquote>
<p>REST 서버는 다음 계층으로 구성될 수 있으며 보안, 로드 밸런싱, 암호화 계층을 추가해 구조상의 유연성을 둘 수 있다
a. 보안
b. 로드밸런싱 -&gt; 프록시
    로드밸런싱 : H/W, 트래픽 부하 조절
    프록시 : 경로 조절
로드밸런서가 부하에 따라 서버를 생성할 수도 종료할 수도 있다.</p>
</blockquote>
<h1 id="rest-api-디자인-가이드">REST API 디자인 가이드</h1>
<hr>
<blockquote>
<ol>
<li>URI는 <strong>정보의 자원을 표현</strong>해야 한다.</li>
<li>자원에 대한 행위는 HTTP Method<strong>(GET, POST, PUT, DELETE)</strong>로 표현한다.
<img src="https://velog.velcdn.com/images/mangez_js/post/79f20a32-a5f0-4474-b7b7-7683372763d7/image.png" alt=""></li>
</ol>
</blockquote>
<h1 id="rest-api-중심-규칙">REST API 중심 규칙</h1>
<hr>
<h2 id="1-uri는-정보의-자원을-표현해야-한다리소스명은-동사보다는-명사를-사용">1) URI는 정보의 자원을 표현해야 한다.(리소스명은 동사보다는 명사를 사용)</h2>
<p><code>GET /members/delete/1 &quot;헤더 라인을 표현한 겁니다.&quot;</code></p>
<blockquote>
<p>위와 같은 방식은 REST를 제대로 적용하지 않은 URI입니다.
URI는 자원을 표현하는데 중점을 두어야 합니다. delete와 같은 <strong>행위에 대한 표현</strong>이 들어가서는 안된다.</p>
</blockquote>
<h2 id="2-자원에-대한-행위는-http-methodget-post-put-delete-등로-표현">2) 자원에 대한 행위는 HTTP Method(GET, POST, PUT, DELETE 등)로 표현</h2>
<blockquote>
<p>위의 잘못된 URI를 HTTP Method를 통해 수정해 보안</p>
</blockquote>
<p><code>DELETE /members/1</code></p>
<blockquote>
<p>으로 수정할 수 있습니다.
회원정보를 가져올 때는 GET,
회원 추가 시의 행위를 표현하고자 할 때는 POST METHOD를 사용하여 표현</p>
</blockquote>
<p><strong>회원정보를 가져오는 URI</strong></p>
<pre><code>GET /members/show/1 (x) * show는 행위, 보겠다는 의도는 알겠지만 권장 X
GET /members/1 (o)</code></pre><p><strong>회원을 추가할 때</strong></p>
<pre><code>GET /members/insert/2 (x) * GET 메서드는 리소스 생성에 맞지 않습니다.
POST /members/2 (o)</code></pre><h1 id="uri-설계-시-주의할-점">URI 설계 시 주의할 점</h1>
<hr>
<h2 id="1-슬래시-구분자는-계층-관계를-나타내는데-사용">1) 슬래시 구분자(/)는 계층 관계를 나타내는데 사용</h2>
<pre><code>http://restapi.example.com/houses/apartments
http://restapi.example.com/animals/mammals/whales</code></pre><h2 id="2-uri-마지막-문자로-슬래시를-포함하지-않는다">2) URI 마지막 문자로 슬래시(/)를 포함하지 않는다.</h2>
<blockquote>
<p>URI에 포함되는 모든 글자는 리소스의 유일한 식별자로 사용되어야 하며 URI가 다르다는 것은 리소스가 다르다는 것이고, 역으로 리소스가 다르면 URI도 달라져야 합니다.</p>
</blockquote>
<blockquote>
<p>REST API는 분명한 URI를 만들어 통신을 해야 하기 때문에 혼동을 주지 않도록 URI 경로의 마지막에는 슬래시(/)를 사용하지 않습니다.</p>
</blockquote>
<pre><code>http://restapi.example.com/houses/apartments/ (X)
http://restapi.example.com/houses/apartments (O)</code></pre><h2 id="3-하이픈-은-uri-가독성을-높이는데-사용">3) 하이픈(-)은 URI 가독성을 높이는데 사용</h2>
<blockquote>
<p>URI를 쉽게 읽고 해석하기 위해, 불가피하게 긴 URI 경로를 사용하게 된다면 하이픈을 사용해 가독성을 높일 수 있습니다.</p>
</blockquote>
<h2 id="4-밑줄_은-uri에-사용하지-않는다">4) 밑줄(_)은 URI에 사용하지 않는다.</h2>
<blockquote>
<p>글꼴에 따라 다르긴 하지만 밑줄은 보기 어렵거나 밑줄 때문에 문자가 가려지기도 합니다.
이런 문제를 피하기 위해 밑줄 대신 하이픈(-)을 사용하는 것이 좋다.</p>
</blockquote>
<h2 id="5-uri-경로에는-소문자가-적합">5) URI 경로에는 소문자가 적합</h2>
<blockquote>
<p>URI 경로에 대문자 사용은 피하도록 해야 합니다. 대소문자에 따라 다른 리소스로 인식하기 때문이다</p>
</blockquote>
<h2 id="6-파일-확장자는-uri에-포함시키지-않는다">6) 파일 확장자는 URI에 포함시키지 않는다.</h2>
<p><code>http://restapi.example.com/members/soccer/345/photo.jpg (X)</code></p>
<blockquote>
<p>REST API에서는 메시지 바디 내용의 포멧을 나타내기 위한 파일 확장자를 URI 안에 포함시키지 않는다.
Accept Header를 사용</p>
</blockquote>
<pre><code>GET / members/soccer/345/photo HTTP/1.1
Host: restapi.example.com
Accept: image/jpg</code></pre><h1 id="리소스-간의-관계를-표현하는-방법">리소스 간의 관계를 표현하는 방법</h1>
<hr>
<blockquote>
<p>REST 리소스 간에는 연관 관계가 있을 수 있고, 이런 경우 다음과 같은 표현 방법을 사용</p>
</blockquote>
<pre><code>/리소스명/리소스 ID/관계가 있는 다른 리소스명
ex) GET : /users/{userid}/devices (일반적으로 소유 ‘has’의 관계를 표현할 때)</code></pre><blockquote>
<p>만약에 관계명이 복잡하다면 이를 서브 리소스에 명시적으로 표한하는 방법이 있다.
예를 들어 사용자가 &#39;좋아하는&#39; 디바이스 목록을 표현해야 할 경우 다음과 같은 형태로 사용</p>
</blockquote>
<p><code>GET : /users/{userid}/likes/devices (관계명이 애매하거나 구체적 표현이 필요할 때)</code></p>
<h1 id="자원을-표현하는-collection과-document">자원을 표현하는 Collection과 Document</h1>
<hr>
<blockquote>
<p><strong>Document</strong>는 단순히 문서로 이해해도 되고, 한 객체라고 이해하셔도 될 것 같습니다.
<strong>Collection</strong>은 문서들의 집합, 객체들의 집합이라고 생각</p>
</blockquote>
<p>컬렉션과 도큐먼트는 모두 리소스라고 표현할 수 있으며 URI에 표현
<code>http:// restapi.example.com/sports/soccer</code> 
위 URI를 보시면 sports라는 컬렉션과 soccer라는 도큐먼트로 표현되고 있다고 생각하면 된다.</p>
<h1 id="http-응답-상태-코드">HTTP 응답 상태 코드</h1>
<hr>
<blockquote>
<p>잘 설계된 REST API는 URI만 잘 설계된 것이 아닌 그 리소스에 대한 응답을 잘 내어주는 것까지 포함되어야 한다.</p>
</blockquote>
<p>정확한 응답의 상태코드만으로도 많은 정보를 전달할 수 있기 때문에 응답의 상태코드 값을 명확히 돌려주는 것은 생각보다 중요한 일이 될 수도 있다.</p>
<table>
<thead>
<tr>
<th>상태코드</th>
<th></th>
</tr>
</thead>
<tbody><tr>
<td>200</td>
<td>클라잉언트의 요청을 정상적으로 수행</td>
</tr>
<tr>
<td>201</td>
<td>클라이언트가 어떠한 리소스 생성을 요청, 해당 리소스가 성공적으로 생성됨(POST를 통한 리소스 작업 생성 시)</td>
</tr>
<tr>
<td>400</td>
<td>클라이언트의 요청이 부적절 할 경우 사용하는 응답 코드</td>
</tr>
<tr>
<td>401</td>
<td>클라이언트가 인증되지 않은 상태에서 보호된 리소스를 요청했을 때 사용하는 응답 코드</td>
</tr>
<tr>
<td>403</td>
<td>유저 인증상태와 관계 없이 응답하고 싶지 않은 리소스를 클라이언트가 요청했을 때 사용하는 응답 코드</td>
</tr>
<tr>
<td>405</td>
<td>클라이언트가 요청한 리소스에서는 사용 불가능한 Method를 이용했을 경우 사용하는 응답 코드</td>
</tr>
<tr>
<td>301</td>
<td>클라이언트가 요청한 리소스에 대한 URI가 변경 되었을 때 사용하는 응답 코드</td>
</tr>
<tr>
<td>500</td>
<td>서버에 문제가 있을 경우 사용하는 응답 코드</td>
</tr>
</tbody></table>
<blockquote>
</blockquote>
<h6 id="참고-문헌">참고 문헌</h6>
<p><a href="https://inpa.tistory.com/entry/WEB-%F0%9F%8C%90-REST-API-%EC%A0%95%EB%A6%AC">https://inpa.tistory.com/entry/WEB-%F0%9F%8C%90-REST-API-%EC%A0%95%EB%A6%AC</a>
<a href="https://thin-cupboard-d95.notion.site/REST-API-15e09d35c17e81888ce1d1d333a17bdf">https://thin-cupboard-d95.notion.site/REST-API-15e09d35c17e81888ce1d1d333a17bdf</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DP, 다이나믹 프로그래밍이란?]]></title>
            <link>https://velog.io/@mangez_js/DP-%EB%8B%A4%EC%9D%B4%EB%82%98%EB%AF%B9-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@mangez_js/DP-%EB%8B%A4%EC%9D%B4%EB%82%98%EB%AF%B9-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Mon, 10 Feb 2025 13:20:37 GMT</pubDate>
            <description><![CDATA[<h1 id="다이나믹-프로그래밍">다이나믹 프로그래밍</h1>
<blockquote>
<p>큰 문제를 작은 문제로 나누어 해결하고, 이를 저장하여 중복 계산을 방지하는 알고리즘 기법
일반적으로 최적 부분 구조, 중복 부분 문제를 만족하는 문제에서 사용</p>
</blockquote>
<ul>
<li>최적 부분 구조 : 문제의 최적 해가 부분 문제들의 최적 해로 구성될 수 있음</li>
<li>중복 부분 문제 : 동일한 작은 문제들이 반복해서 계산됨</li>
</ul>
<h1 id="해결-방식">해결 방식</h1>
<ol>
<li>Top-Down(메모이제이션, Memoization)<ul>
<li>재귀 + 캐싱 활용</li>
<li>큰 문제를 작은 문제로 쪼개어 해결</li>
<li>계산한 결과를 저장하여 동일한 연산을 반복하지 않음</li>
<li>보통 DP 배열을 선언하고, 재귀 호출 전에 이미 계산된 값인지 확인</li>
</ul>
</li>
<li>Bottom-Up(반복문, Tabulation)<ul>
<li>작은 문제를 먼저 해결한 후, 이를 조합해 큰 문제를 해결</li>
<li>보통 DP 배열을 만들어 순차적으로 채워감</li>
<li>재귀 호출이 없어 함수 호출 스택 오버헤드가 줄어듦</li>
<li>공간 최적화가 가능(배열 없이 변수만으로 해결 가능)</li>
</ul>
</li>
</ol>
<h1 id="대표적인-문제">대표적인 문제</h1>
<ol>
<li><p>파보나치 수열 -&gt; Top-Down 방식</p>
<blockquote>
<p>파보나치 수열은 이전 두 항의 합으로 이루어지는 수열</p>
</blockquote>
<pre><code class="language-java">public class FibonacciTopDown{
 static Map&lt;Integer, Integer&gt; memo = new HashMap&lt;&gt;();

 public static int fibonacci(int n){
     if(n &lt;= 1) return n;
     if(memo.containsKey(n)) return memo.get(n);

     int result = fibonacci(n - 1) + fibonacci(n - 2);
     memo.put(n, result);
     return result;
 }

 public static void main(String[] args){
     System.out.println(fibonacci(10));
 }
}</code></pre>
</li>
<li><p>배낭 문제 -&gt; Bottom-Up 방식</p>
<blockquote>
<p>주어진 가방의 용량에 최대한 가치가 높은 물건을 넣는 문제</p>
</blockquote>
<pre><code class="language-java">public class KnapsackBottomUp{
 public static int knapsack(int W, int[] weights, int[] values, int n){
     int[][] dp = new int[n + 1][w + 1];

     for(int i = 1; i &lt;= n; i++){
         for(int w = 0; w &lt;= W; w++){
             if(weights[i - 1] &lt;= w){
                 dp[i][w] = Math.max(dp[i - 1][w], dp[i - 1][w - weights[i - 1]] +values[i - 1]);
             } else {
                 dp[i][w] = dp[i - 1][w];
             }
         }
     }

     return dp[n][w];
 }

 public static void main(String[] args){
     int[] values = {60, 100, 120};
     int[] weights = {10, 20, 30};
     int W = 50;
     itn n = values.length;

     System.out.println(knapsack(W, weights, values, n));
 }
}</code></pre>
</li>
<li><p>최장 증가 부분 수열 &gt;  Bottom-Up 방식</p>
<blockquote>
<p>주어진 수열에서 순서를 유지하면서 가장 긴 부분 수열을 찾는 문제</p>
</blockquote>
<pre><code class="language-java">public class LISBottomUp{
 public static int longestIncreasingSubsequence(int[] nums){
     int n = nums.length;
     int[] dp = new int[n];
     Arrays.fill(dp, 1);

     int maxLength = 1;
     for(int i = 1; i &lt; n; i++){
         for(int j = 0; j &lt; i; j++){
             if(nums[i] &gt; nums[j]){
                 dp[i] = Math.max(dp[i], dp[j] + 1);
             }
         }
         maxLength = Math.max(maxLength, dp[i]);
     }

     return maxLength;
 }

 public static void main(String[] args){
     int[] nums = {10, 22, 9, 33, 21, 50, 41, 60);
     System.out.println(longestIncreasingSubsequence(nums));
 }
}</code></pre>
</li>
<li><p>최단 경로 문제 &gt; Bottom-Up 방식</p>
<blockquote>
<p>주어진 그래프에서 시작 노드부터 도착 노드까지의 최단 경로를 찾는 문제</p>
</blockquote>
<pre><code class="language-java">class DijkstraBottomUp {
 static class Node implements Comparable&lt;Node&gt; {
     int vertex, cost;
     Node(int vertex, int cost) {
         this.vertex = vertex;
         this.cost = cost;
     }
     public int compareTo(Node other) {
         return this.cost - other.cost;
     }
 }

 public static int[] dijkstra(int V, List&lt;List&lt;Node&gt;&gt; graph, int start) {
     int[] dist = new int[V];
     Arrays.fill(dist, Integer.MAX_VALUE);
     dist[start] = 0;

     PriorityQueue&lt;Node&gt; pq = new PriorityQueue&lt;&gt;();
     pq.add(new Node(start, 0));

     while (!pq.isEmpty()) {
         Node current = pq.poll();
         int u = current.vertex;

         for (Node neighbor : graph.get(u)) {
             int v = neighbor.vertex;
             int weight = neighbor.cost;

             if (dist[u] + weight &lt; dist[v]) {
                 dist[v] = dist[u] + weight;
                 pq.add(new Node(v, dist[v]));
             }
         }
     }
     return dist;
 }

 public static void main(String[] args) {
     int V = 5;
     List&lt;List&lt;Node&gt;&gt; graph = new ArrayList&lt;&gt;();
     for (int i = 0; i &lt; V; i++) {
         graph.add(new ArrayList&lt;&gt;());
     }

     graph.get(0).add(new Node(1, 10));
     graph.get(0).add(new Node(4, 3));
     graph.get(1).add(new Node(2, 2));
     graph.get(2).add(new Node(3, 1));
     graph.get(4).add(new Node(1, 4));
     graph.get(4).add(new Node(2, 8));

     int[] distances = dijkstra(V, graph, 0);
     System.out.println(Arrays.toString(distances)); // [0, 7, 10, 11, 3]
 }
}</code></pre>
</li>
<li><p>문자열 편집 거리 문제 &gt; Bottom-Up 방식</p>
<blockquote>
<p>두 문자열 사이의 최소 편집 거리를 찾는 문제</p>
</blockquote>
<pre><code>public class EditDistanceBottomUp {
 public static int editDistance(String str1, String str2) {
     int m = str1.length(), n = str2.length();
     int[][] dp = new int[m + 1][n + 1];

     for (int i = 0; i &lt;= m; i++) {
         for (int j = 0; j &lt;= n; j++) {
             if (i == 0) {
                 dp[i][j] = j; // 삭제만 가능
             } else if (j == 0) {
                 dp[i][j] = i; // 삽입만 가능
             } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                 dp[i][j] = dp[i - 1][j - 1]; // 같으면 그대로
             } else {
                 dp[i][j] = 1 + Math.min(dp[i - 1][j - 1], // 교체
                                 Math.min(dp[i - 1][j],   // 삭제
                                          dp[i][j - 1])); // 삽입
             }
         }
     }
     return dp[m][n];
 }

 public static void main(String[] args) {
     String str1 = &quot;horse&quot;;
     String str2 = &quot;ros&quot;;
     System.out.println(editDistance(str1, str2)); // 3
 }
}</code></pre></li>
</ol>
<h1 id="장단점">장단점</h1>
<p>장점</p>
<ul>
<li>중복 계산을 줄일 수 있다.</li>
<li>효율적인 시간 복잡도를 가질 수 있다.
단점</li>
<li>메모리 사용량이 크다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[스택 & 큐]]></title>
            <link>https://velog.io/@mangez_js/%EC%8A%A4%ED%83%9D-%ED%81%90</link>
            <guid>https://velog.io/@mangez_js/%EC%8A%A4%ED%83%9D-%ED%81%90</guid>
            <pubDate>Mon, 03 Feb 2025 23:38:14 GMT</pubDate>
            <description><![CDATA[<h1 id="스택">스택</h1>
<blockquote>
<p>데이터를 일시적으로 쌓아 놓는 자료구조로, 데이터의 입력과 출력 순서는 후입선출(LIFO: Last In First Out) 방식
가장 나중에 넣은 데이터를 가장 먼저 꺼냅니다. </p>
</blockquote>
<ul>
<li>스택에 데이터를 넣는 작업을 푸시(push)</li>
<li>데이터를 꺼내는 작업을 팝(pop)        </li>
<li>푸시와 팝이 이루어지는 쪽을 꼭대기(top)</li>
<li>가장 아랫부분을 바닥(bottom)</li>
</ul>
<pre><code class="language-java">public class IntStackTester{
    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);
        IntStack s = new IntStack(64);

        while(true){
            System.out.println();
            System.out.prinf(&quot;현재 데이터 개수: %d / %d\n&quot;, s.size(), s.getCapacity());
            System.out.printf(&quot;(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: &quot;);

            int menu = stdIn.nextInt();
            if(menu == 0) break;

            int x;
            switch(menu){
                case 1:
                    System.out.print(&quot;데이터: &quot;);
                    x = stdIn.nextInt();
                    try{
                        s.push(x);
                    }catch(IntStack.OverflowIntStackException e){
                        System.out.println(&quot;스택이 가득 찼습니다.&quot;);
                    }
                    break;

                case 2:
                    try{
                        x = s.pop();
                        System.out.println(&quot;팝한 데이터는 &quot; + x + &quot;입니다.&quot;);
                    }catch(IntStack.EmptyIntStackException e){
                        System.out.println(&quot;스택이 비어 있습니다.&quot;);&#39;
                    }
                    break;

                case 3:
                    try{
                        x = s.peek();
                        System.out.println(&quot;피크한 데이터는 &quot; + x + &quot;입니다.&quot;);
                    }catch(IntStack.EmptyIntStackException e){
                        System.out.println(&quot;스택이 비어 있습니다.&quot;);
                    }
                    break;

                case 4:
                    s.dump();
                    break;
            }
        }
    }
}</code></pre>
<p>실행 결과</p>
<pre><code>현재 데이터 개수: 0/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 1
데이터: 1

현재 데이터 개수: 1/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 1
데이터: 2

현재 데이터 개수: 2/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 1
데이터: 3

현재 데이터 개수: 3/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 1
데이터: 4

현재 데이터 개수: 4/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 3
피크한 데이터는 4입니다.

현재 데이터 개수: 4/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 4
1 2 3 4

현재 데이터 개수: 4/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 2
팝한 데이터는 4입니다.

현재 데이터 개수: 3/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 2
팝한 데이터는 3입니다.

현재 데이터 개수: 2/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 4
1 2

현재 데이터 개수: 2/64
(1) 푸시 (2) 팝 (3) 피크 (4) 덤프 (0) 종료: 0</code></pre><h1 id="큐">큐</h1>
<blockquote>
<p>데이터를 일시적으로 쌓아 두는 기본 자료구조
가장 먼저 넣은 데이터를 가장 먼저 꺼내는 (FIFO: First In First Out) 방식</p>
</blockquote>
<ul>
<li>큐에 데이터를 넣는 작업을 인큐(en-queue)</li>
<li>데이터를 꺼내는 작업을 디큐(de-queue)</li>
<li>데이터가 나오는 쪽을 프론트(front, 맨 앞)</li>
<li>데이터를 넣는 쪽을 리어(rear, 맨 뒤)</li>
</ul>
<pre><code class="language-java">class IntQueueTester {
    public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);
        IntQueue s = new IntQueue(54);

        while(true){
            System.out.println();
            System.out.print(&quot;현재 데이터 개수: %d / %d\n&quot;, s.size(), s.getCapacity));
            System.out.print(&quot;(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료 : &quot;);

            int menu = stdIn.nextInt();
            if(menu == 0) break;

            int x;
            switch(menu){
                case 1:
                    System.out.print(&quot;데이터: &quot;);
                    x = stdIn.nextInt();
                    try{
                        s.enque(x);
                    }catch(IntQueue.OverflowIntQueueException e){
                        System.out.println(&quot;큐가 가득 찼습니다.&quot;);
                    }
                    break;

                case 2:
                     try{
                        x = s.deque();
                        System.out.println(&quot;디큐한 데이터는 &quot; + x + &quot;입니다.&quot;);
                    }catch(IntQueue.EmptyIntQueueException e){
                        System.out.println(&quot;큐가 비어 있습니다.&quot;);
                    }
                    break;

                case 3:
                    try{
                        x=s.peek();
                        System.out.println(&quot;피크한 데이터는 &quot; + x +&quot;입니다.&quot;);
                    }catch(IntQueue.EmptyIntQueueException e){
                        System.out.println(&quot;큐가 비어 있습니다.&quot;);
                    }
                    break;

                case 4:
                    s.dump();
                    break;
            }
        }
    }
}</code></pre>
<p>실행 결과</p>
<pre><code>현재 데이터 개수: 0/64
(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료: 1
데이터: 1

현재 데이터 개수: 1/64
(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료: 1
데이터: 2

현재 데이터 개수: 2/64
(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료: 1
데이터: 1 2

현재 데이터 개수: 2/64
(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료: 2
디큐한 데이터는 1입니다.

현재 데이터 개수: 1/64
(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료: 4
데이터: 2

현재 데이터 개수: 1/64
(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료: 3
피크한 데이터는 2입니다.

현재 데이터 개수: 1/64
(1) 인큐 (2) 디큐 (3) 피크 (4) 덤프 (0) 종료: 0</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[검색 알고리즘]]></title>
            <link>https://velog.io/@mangez_js/%EA%B2%80%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</link>
            <guid>https://velog.io/@mangez_js/%EA%B2%80%EC%83%89-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98</guid>
            <pubDate>Mon, 03 Feb 2025 12:21:11 GMT</pubDate>
            <description><![CDATA[<h1 id="1-선형-탐색-알고리즘linear-search-algorith">1. 선형 탐색 알고리즘(Linear Search Algorith)</h1>
<blockquote>
<p>맨 앞 부터 순서대로 요소를 검색하는 알고리즘</p>
<ol>
<li>맨 끝부터 하나하나 원하는 값을 찾아본다.</li>
<li>원하는 값을 찾으면 탐색을 종료한다.
<img src="https://velog.velcdn.com/images/mangez_js/post/55c5a016-b7d2-43a2-9636-d67700ab0fd4/image.png" alt=""></li>
</ol>
</blockquote>
<p>a. 인덱스가 0인 요소 6을 선택, 검색하려는 값이 아닙니다.
b. 인덱스가 1인 요소 4을 선택, 검색하려는 값이 아닙니다.
c. 인덱스가 2인 요소 3을 선택, 검색하려는 값이 아닙니다.
d. 인덱스가 3인 요소 2을 선택, 검색하려는 값입니다. 검색 성공!</p>
<pre><code class="language-java">class LinearSearchAlg{
    static int LinearSearchAlg(int[] a, int n, int key) {
        int i = 0;

        while(true) {
            if(i==n)
                return -1;
            if(a[i] == key)
                return i;
            i++;
        }
    }

      public static void main(String[] args){
        Scanner stdIn = new Scanner(System.in);

        System.out.print(&quot;요솟수 : &quot;);
        int num = stdIn.nextInt();
        int[] x = new int[num];

        for(int i = 0; i &lt; num; i++){
            System.out.print(&quot;x[&quot; + i + &quot;]: &quot;);
            x[i] = stdIn.nextInt();
        }

        System.out.print(&quot;검색할 값:&quot;);
        int ky = stdIn.nextInt();
        int idx = seqSearch(x, num, ky);

        if(idx == -1)
            System.out.println(&quot;그 값의 요소가 없습니다.&quot;);
        else
            System.out.println?(&quot;그 값은 x[&quot; + idx + &quot;]에 있습니다.&quot;);
    }
}</code></pre>
<p>실행결과</p>
<pre><code>요솟수: 7
x[0]: 6
x[1]: 4
x[2]: 3
x[3]: 2
x[4]: 1
x[5]: 2
x[6]: 8
검색할 값 : 2
그 값은 x[3]에 있습니다.</code></pre><h2 id="시간-복잡도">시간 복잡도</h2>
<pre><code>static int LinearSearchAlg(int[] a, int n, int key) {
    ① int 1 = 0;

    ② while(i&lt;n) {
    ③     if(a[i] == key)
    ④        return i;
    ⑤    i++;
        }
    ⑥    return -1;
}</code></pre><table>
<thead>
<tr>
<th>단계</th>
<th>실행 횟수</th>
<th>복잡도</th>
</tr>
</thead>
<tbody><tr>
<td>①</td>
<td>1</td>
<td>O(1)</td>
</tr>
<tr>
<td>②</td>
<td>n/2</td>
<td>O(n)</td>
</tr>
<tr>
<td>③</td>
<td>n/2</td>
<td>O(n)</td>
</tr>
<tr>
<td>④</td>
<td>1</td>
<td>O(1)</td>
</tr>
<tr>
<td>⑤</td>
<td>n/2</td>
<td>O(n)</td>
</tr>
<tr>
<td>⑥</td>
<td>1</td>
<td>O(1)</td>
</tr>
</tbody></table>
<h1 id="2-이진-탐색-알고리즘binary-search-algorith">2. 이진 탐색 알고리즘(Binary Search Algorith)</h1>
<blockquote>
<p>중간지점을 기준으로 데이터를 반씩 나눠서 탐색하는 알고리즘</p>
<ol>
<li>중간지점을 선택한 뒤, 중간지점을 기준으로 왼쪽 혹은 오른쪽 부분만 남긴다.</li>
<li>남긴 부분 중에서 다시 중간지점을 선택한 뒤, 왼쪽 혹은 오른쪽만 남긴다.</li>
<li>위 과정을 원하는 값을 찾을 때 까지 반복한다.</li>
</ol>
</blockquote>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/d3d84987-2c1c-43dd-9950-40651f855271/image.png" alt=""></p>
<pre><code class="language-java">class BinSearch{
    static int binSearch(int[] a, int n, int key){
        int pl = 0;
        int pr = n-1;

        do{
            int pc = (pl+pr) / 2;
            if(a[pc] == key)
                return pc;
            else if(a[pc] &lt; key)
                pr = pc - 1;
        } while(pl &lt;= pr);

        return -1;
    }

    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        Sytstem.out.print(&quot;요솟수: &quot;);
        int num = stdIn.nextInt();
        int[] x = new int[num];

        System.out.println(&quot;오름차순으로 입력하세요.&quot;);

        System.out.print(&quot;x[0]: &quot;);
        x[0] = stdIn.nextInt();

        for(int i = 0; i &lt; num; i++){
            do{
                System.out.print(&quot;x[&quot;+ i +&quot;]:&quot;);
                x[i] = stdIn.nextInt();
            }while(x[i] &lt; x[i-1];
        }

    System.out.print(&quot;검색할 값: &quot;);
    int ky = stdIn.nextInt();

    int idx = binSearch(x, num, ky);

    if(idx == -1)
        System.out.println(&quot;그 값의 요소가 없습니다.&quot;);
    else
        System.out.println(&quot;그 값은 x[&quot;+idx+&quot;]에 있습니다.&quot;);
    }
}
</code></pre>
<p>실행 결과</p>
<pre><code>요솟수: 7
오름차순으로 입력하세요.
x[0]: 15
x[1]: 27
x[2]: 39
x[3]: 77
x[4]: 92
x[5]: 108
x[6]: 121
검색할 값: 39
그 값은 x[2]에 있습니다.</code></pre><h2 id="시간-복잡도-1">시간 복잡도</h2>
<pre><code class="language-java">static int binSearch(int[] a, int n, int key){
①    int pl = 0;
②    int pr = n -1;

    do{
③        int pc = (pl+pr)/2;
④        if(a[pc] == key)
⑤            return pc;
⑥        else if(a[pc] &lt; key)
⑦            pl = pc + 1;
        else
⑧            pr = pc - 1;
⑨    } while(pl &lt;= pr);

⑩    return -1;
}</code></pre>
<table>
<thead>
<tr>
<th>단계</th>
<th>실행 횟수</th>
<th>복잡도</th>
</tr>
</thead>
<tbody><tr>
<td>①</td>
<td>1</td>
<td>O(1)</td>
</tr>
<tr>
<td>②</td>
<td>log n</td>
<td>O(log n)</td>
</tr>
<tr>
<td>③</td>
<td>log n</td>
<td>O(log n)</td>
</tr>
<tr>
<td>④</td>
<td>1</td>
<td>O(1)</td>
</tr>
<tr>
<td>⑤</td>
<td>log n</td>
<td>O(log n)</td>
</tr>
<tr>
<td>⑥</td>
<td>log n</td>
<td>O(log n)</td>
</tr>
<tr>
<td>⑦</td>
<td>log n</td>
<td>O(log n)</td>
</tr>
<tr>
<td>⑧</td>
<td>log n</td>
<td>O(log n)</td>
</tr>
<tr>
<td>⑨</td>
<td>log n</td>
<td>O(log n)</td>
</tr>
<tr>
<td>⑩</td>
<td>1</td>
<td>O(1)</td>
</tr>
</tbody></table>
<h1 id="3-해시-탐색-알고리즘hash-search-algoritm">3. 해시 탐색 알고리즘(Hash Search Algoritm)</h1>
<blockquote>
<p>값과 index를 미리 연결해 둠으로써 짧은 시간에 탐색할 수 있는 알고리즘
함수를 사용하여 데이터를 보관 후 사용된 함수를 사용하여 한 번에 데이터를 탐색</p>
</blockquote>
<h1 id="아이디어">아이디어</h1>
<h3 id="1차-아이디어">1차 아이디어</h3>
<blockquote>
<p>처음에는 데이터와 같은 index에 저장
최소한 데이터의 종류 만큼의 index 필요</p>
</blockquote>
<h3 id="2차-아이디어">2차 아이디어</h3>
<blockquote>
<p>데이터에 함수(일정 계산)을 적용하여 나온 값을 index로 하여 보관하는 방법
해시 함수 : 어떤 값이 주어졌을 때, 그 값을 대표하는 값을 계산하는 함수
해시 값 : 해시 함수의 계산으로 나온 값</p>
</blockquote>
<h1 id="4-이진-탐색-트리bst-binary-search-tree">4. 이진 탐색 트리(BST/ Binary Search Tree)</h1>
<blockquote>
<p>트리 자료구조를 이용한 탐색 트리
왼쪽 서브트리의 키값들은 root의 키값보다 작다.
오른쪽 서브트리의 키값들은 root의 키값보다 크다.
왼쪽, 오른쪽 서브트리들을 각각 모두 BST 정의를 만족한다.
BST의 모든 node들의 키값은 unique
4가지를 모두 만족해야 한다.</p>
</blockquote>
<h3 id="탐색-알고리즘">탐색 알고리즘</h3>
<blockquote>
<p>어떠한 BST에서 원하는 값을 찾고자 할 때, root 값을 기준으로</p>
</blockquote>
<ul>
<li>원하는 값 &gt; root 키 값 : 오른쪽 서브트리로 이동</li>
<li>원하는 값 &lt; root 키 값 : 왼쪽 서브트리로 이동</li>
<li>원하는 값 = root 키 값 : 탐색 종료</li>
</ul>
<h3 id="삽입-알고리즘">삽입 알고리즘</h3>
<blockquote>
<p>어떠한 값을 삽입하고자 할 때</p>
</blockquote>
<ol>
<li>탐색 알고리즘을 먼저 수행</li>
<li>탐색 실패 시, 탐색이 종료된 위치에 해당 노드를 삽입</li>
<li>탐색 성공 시, 이미 저장되어있는 키값이므로 삽입에 실패</li>
</ol>
<h3 id="삭제-알고리즘">삭제 알고리즘</h3>
<blockquote>
<p>어떠한 값을 삭제하고자 할 때,</p>
</blockquote>
<ol>
<li><p>위의 탐색 알고리즘을 먼저 수행</p>
</li>
<li><p>삭제하려는 노드의 차수에 따라</p>
</li>
<li><p>차수 : 0(leaf node) - 그냥 삭제</p>
</li>
<li><p>차수 : 1(한 개의 자식 존재) : 삭제하고 자식을 삭제한 자리에 붙인다.</p>
</li>
<li><p>차수 : 2(자신의 대체할 노드를 찾는다) : </p>
<pre><code>     삭제할 노드의 왼쪽 서브트리에서 가장 큰 값
                 오른쪽 서브트리에서 가장 작은 값
     을 대체할 노드로 정한다.</code></pre></li>
</ol>
<blockquote>
<p>Reference
<a href="https://bba-dda.tistory.com/21">https://bba-dda.tistory.com/21</a>
<a href="https://product.kyobobook.co.kr/detail/S000001817897">https://product.kyobobook.co.kr/detail/S000001817897</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TMUX]]></title>
            <link>https://velog.io/@mangez_js/TMUX</link>
            <guid>https://velog.io/@mangez_js/TMUX</guid>
            <pubDate>Mon, 27 Jan 2025 12:46:55 GMT</pubDate>
            <description><![CDATA[<h1 id="tmuxtermianl-multiplexer">TMUX(Termianl Multiplexer)</h1>
<blockquote>
<p>단일 터미널 세션 내에서 여러 터미널 창을 실행하고 관리할 수 있도록 해주는 도구</p>
</blockquote>
<h1 id="주요-기능">주요 기능</h1>
<ol>
<li>여러 세션 관리<ul>
<li>하나의 tmux 세션에서 여러 창을 열고 각 창을 독립적으로 실행할 수 있음</li>
<li>각 창은 여러 개의 패널로 분할 가능</li>
<li>세션을 종료하지 않고 나중에 재접속 가능</li>
</ul>
</li>
<li>세션 유지 및 복구<ul>
<li>SSH 연결이 끊기더라도 tmux 세션은 백그라운드에서 계속 실행되므로 작업이 중단되지 않음</li>
<li>다시 접속하여 세션을 복구할 수 있음</li>
</ul>
</li>
<li>창 및 패널 분할<ul>
<li>하나의 화면에서 여러 개의 창을 세로 또는 가로로 분할해서 작업을 동시에 수행</li>
</ul>
</li>
</ol>
<h1 id="주요-tmux-명령어">주요 tmux 명령어</h1>
<h3 id="1-세션-관리">1. 세션 관리</h3>
<ul>
<li><p><code>tmux</code> : 새 tmux 세션 시작</p>
</li>
<li><p><code>tmux new -s [session_name]</code> : 이름이 지정된 세 새션 시작</p>
</li>
<li><p><code>tmux ls</code> : 현재 실행 중인 세션 목록 확인</p>
</li>
<li><p><code>tmux attach -t [session_name]</code> : 특정 세션에 재접속</p>
</li>
<li><p><code>tmux kill -session -t [session_name]</code> : 특정 세션 종료</p>
<h3 id="2-창-관리">2. 창 관리</h3>
</li>
<li><p><code>Ctrl+b c</code> : 새 창 생성</p>
</li>
<li><p><code>Ctrl+b n</code> : 다음 창으로 이동</p>
</li>
<li><p><code>Ctrl+b p</code> : 이전 창으로 이동</p>
</li>
<li><p><code>Ctrl+b w</code> : 창 목록 표시</p>
<h3 id="3-패널-관리">3. 패널 관리</h3>
</li>
<li><p><code>Ctrl+b %</code> : 창을 수직으로 분할</p>
</li>
<li><p><code>Ctrl+b &quot;</code> : 창을 수평으로 분할</p>
</li>
<li><p><code>Ctrl+b o</code> : 패널 간 이동</p>
</li>
<li><p><code>Ctrl+b x</code> : 현재 패널 닫기</p>
<h3 id="4-틀-관련">4. 틀 관련</h3>
</li>
<li><p><em>틀 나누기*</em></p>
</li>
<li><p><code>(Ctrl+b) %</code> : 좌우로 나누기</p>
</li>
<li><p><code>(Ctrl+b) *</code> : 위아래로 나누기</p>
</li>
<li><p><em>틀끼리 이동하기*</em></p>
</li>
<li><p><code>(Ctrl+b) 방향키</code></p>
</li>
<li><p><code>(Ctrl+b) q</code></p>
</li>
<li><p><code>(Ctrl+b) o</code> : 순서대로 이동</p>
</li>
<li><p><em>틀 삭제*</em></p>
</li>
<li><p><code>(Ctrl+d)</code></p>
</li>
<li><p><em>틀 사이즈 조정*</em></p>
</li>
<li><p><code>(Ctrl+b) : resize_pame -L 10</code> : L, R, U, D 입력하면 상하좌우로 조절</p>
</li>
<li><p><code>(Ctrl+b)(alt)</code> : 방향키</p>
</li>
<li><p><em>단축키 목록*</em></p>
</li>
<li><p><code>(Ctrl+b) ?</code></p>
</li>
</ul>
<h1 id="장점">장점</h1>
<ul>
<li>생산성 향상 : 여러 작업을 한 화면에서 효율적으로 수행</li>
<li>세션 복구 : 작업 중단 없이 연결 유지</li>
<li>강력한 커스터마이징 : tmux 설정 파일 (<code>~/.tmux.conf</code>)을 통해 키맵과 동작을 사용자 정의 가능    </li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Trouble Shooting :  웹소켓에서 채팅 읽음 기능을 처리해야 하는데, 읽음 처리가 아닌 전송 로직이 실행]]></title>
            <link>https://velog.io/@mangez_js/Trouble-Shooting-%EC%9B%B9%EC%86%8C%EC%BC%93%EC%97%90%EC%84%9C-%EC%B1%84%ED%8C%85-%EC%9D%BD%EC%9D%8C-%EA%B8%B0%EB%8A%A5%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EB%8D%B0-%EC%9D%BD%EC%9D%8C-%EC%B2%98%EB%A6%AC%EA%B0%80-%EC%95%84%EB%8B%8C-%EC%A0%84%EC%86%A1-%EB%A1%9C%EC%A7%81%EC%9D%B4-%EC%8B%A4%ED%96%89</link>
            <guid>https://velog.io/@mangez_js/Trouble-Shooting-%EC%9B%B9%EC%86%8C%EC%BC%93%EC%97%90%EC%84%9C-%EC%B1%84%ED%8C%85-%EC%9D%BD%EC%9D%8C-%EA%B8%B0%EB%8A%A5%EC%9D%84-%EC%B2%98%EB%A6%AC%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EB%8D%B0-%EC%9D%BD%EC%9D%8C-%EC%B2%98%EB%A6%AC%EA%B0%80-%EC%95%84%EB%8B%8C-%EC%A0%84%EC%86%A1-%EB%A1%9C%EC%A7%81%EC%9D%B4-%EC%8B%A4%ED%96%89</guid>
            <pubDate>Thu, 23 Jan 2025 11:40:55 GMT</pubDate>
            <description><![CDATA[<h1 id="원인-분석">원인 분석</h1>
<blockquote>
<p>웹소켓에서 메시지를 처리할 때 메시지의 목적을 구분하지 않았기 때문에 모든 메시지가 전송 로직으로만 처리되었습니다.</p>
</blockquote>
<h1 id="해결-방법">해결 방법</h1>
<pre><code> @Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
    try {
        // 클라이언트 메시지 페이로드 파싱
        String payload = message.getPayload();
        ChatMessageDTO chatMessageDTO = objectMapper.readValue(payload, ChatMessageDTO.class);

        // 메시지 타입에 따라 처리 로직 분기
        switch (chatMessageDTO.getMessageType()) {
            case &quot;CHAT&quot;:
                handleChatMessage(session, chatMessageDTO); // 채팅 메시지 처리
                break;

            case &quot;UNREAD_COUNT&quot;:
                handleUnreadCountRequest(chatMessageDTO, session); // 읽음 처리
                break;

            default:
                sendError(session, &quot;알 수 없는 messageType입니다.&quot;); // 예외 처리
        }
    } catch (Exception e) {
        log.error(&quot;메시지 처리 중 오류 발생: {}&quot;, e.getMessage(), e);
        sendError(session, &quot;메시지 처리 중 오류가 발생했습니다.&quot;);
    }
}</code></pre><blockquote>
<p>messageType으로 메시지 타입 구분</p>
</blockquote>
<h1 id="배운-점">배운 점</h1>
<blockquote>
<ul>
<li>메시지 타입 기반 설계 : 메시지의 목적에 따라 타입을 구분함으로써 코드의 명확성과 가독성을 크게 향상 시킬 수 있다.</li>
</ul>
</blockquote>
<ul>
<li>확장성 : 새로운 메시지 타입이 추가되더라도, 스위치 구문에 케이스를 추가하는 방식으로 간단히 확장 가능합니다.</li>
<li>안전한 예외 처리 : 잘못된 메시지 요청이나 시스템 오류에 대해 명확한 에러 메시지를 반환하여 디버깅이 용이해졌습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Trouble Shooting : MongoDB 저장 시 그리니치 표준시로 저장되는 이유?]]></title>
            <link>https://velog.io/@mangez_js/Trouble-Shooting-MongoDB-%EC%A0%80%EC%9E%A5-%EC%8B%9C-%EA%B7%B8%EB%A6%AC%EB%8B%88%EC%B9%98-%ED%91%9C%EC%A4%80%EC%8B%9C%EB%A1%9C-%EC%A0%80%EC%9E%A5%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</link>
            <guid>https://velog.io/@mangez_js/Trouble-Shooting-MongoDB-%EC%A0%80%EC%9E%A5-%EC%8B%9C-%EA%B7%B8%EB%A6%AC%EB%8B%88%EC%B9%98-%ED%91%9C%EC%A4%80%EC%8B%9C%EB%A1%9C-%EC%A0%80%EC%9E%A5%EB%90%98%EB%8A%94-%EC%9D%B4%EC%9C%A0</guid>
            <pubDate>Thu, 23 Jan 2025 11:35:43 GMT</pubDate>
            <description><![CDATA[<h1 id="문제-정의">문제 정의</h1>
<blockquote>
<p>MongoDB에 데이터를 저장할 때 시간이 GMT로 저장되는 것은 정상적인 동작이다.
내부적으로 UTC를 사용하여 날짜와 시간을 저장하는데 이를 조회하거나 표시할 때 로컬 시간대로 변환할 수 있습니다.</p>
</blockquote>
<h1 id="원인-분석">원인 분석</h1>
<blockquote>
<p>MongoDB는 모든 날짜를 UTC로 저장하며, Spring의 LocalDateTime은 타임존 정보를 포함하지 않아 저장 시 UTC로 변환되며 MongoDB 자체적으로 타임존 설정 기능이 없어 애플리케이션에서 변환 처리가 필요합니다.</p>
</blockquote>
<h1 id="내가-사용한-해결-방법">내가 사용한 해결 방법</h1>
<blockquote>
<p>Spring에서 @WritingConverter와 @ReadingConverter를 사용하여 변환기(Converter)를 적용할 수 있습니다.
<img src="https://velog.velcdn.com/images/mangez_js/post/b0ef78c3-dc22-4c80-bb8f-3787592710f3/image.png" alt=""></p>
</blockquote>
<p>LocalDateTime을 ZoneId.of(&quot;Asia/Seoul&quot;)로 변환 후 UTC 기준 Instant로 변환하고 MongoDB에 저장될 때 KST 기준 시간이 적용된 UTC 값으로 저장됩니다.</p>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/ff8138b1-e770-40bc-83be-c5f64fae571e/image.png" alt="">
Date 타입으로 저장된 UTC 시간을 가져올 때 KST로 변환하여 반환 후 클라이언트에서는 KST로 변환된 시간 확인 가능합니다.</p>
<p><img src="https://velog.velcdn.com/images/mangez_js/post/9fc973fd-1d2e-4ed7-8a7d-40477aaa8763/image.png" alt="">
Spring Boot에서 MongoDB에 변환기를 적용하려면 MongoCustomConversions를 설정해야 합니다.</p>
<p>MongoCustomConversions를 이용해 변환기(Converter)를 등록 합니다.
MongoDB 저장 시 KST → UTC로 변환
MongoDB 조회 시 UTC → KST로 변환
됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[MongoDB]]></title>
            <link>https://velog.io/@mangez_js/MongoDB</link>
            <guid>https://velog.io/@mangez_js/MongoDB</guid>
            <pubDate>Thu, 16 Jan 2025 08:36:02 GMT</pubDate>
            <description><![CDATA[<h1 id="mongodb란">MongoDB란?</h1>
<blockquote>
<p>NoSQL 데이터베이스의 대표적인 예로, 전통적인 관계형 데이터베이스와는 다른 방식으로 데이터를 저장하고 관리합니다.
JSON과 유사한 문서(Document) 형태로 데이터를 저장하며, 높은 확장성과 유연성을 제공합니다.</p>
</blockquote>
<h1 id="주요-개념">주요 개념</h1>
<ul>
<li>문서 지향(Document-Oriented) 
∘ 데이터를 JSON과 유사한 BSON(Binary JSON)형식으로 저장합니다. 
∘ 각 문서는 다양한 속성을 가질 수 있으며, 구조가 유연하여 스키마리스(Schema-less)데이터베이스로도 불립니다.</li>
<li>컬렉션(Collection)
∘ 문서는 컬렉션이라는 컨테이너에 저장됩니다.
∘ 컬렉션은 RDBMS의 테이블과 유사하지만, 컬렉션 안의 문서들은 서로 다른 구조를 가질 수 있습니다.</li>
<li>스키마 유연성(Schema Flexibility)
∘ 고정된 스키마를 요구하지 않으므로, 데이터를 저장할 때 각 문서의 필드와 구조를 자유롭게 정의할 수 있습니다.</li>
<li>수평적 확장성 (Horizontal Scalability)
∘ 샤딩(Sharding)을 통해 데이터를 여러 서버에 분산 저장하여 대규모 데이터를 처리할 수 있습니다.</li>
</ul>
<h1 id="장점">장점</h1>
<ul>
<li>유연한 데이터 모델
∘ 다양한 형식의 데이터를 손쉽게 저장하고 관리할 수 있습니다.
∘ 이를 통해 비정형 데이터와 반정형 데이터를 효율적으로 처리할 수 있습니다.</li>
<li>높은 확장성
∘ 데이터 증가에 따라 서버를 추가하는 방식으로 성능을 확장할 수 있습니다.</li>
<li>빠른 데이터 처리 속도
∘ 인덱싱 및 샤딩 기능 덕분에 대용량 데이터에 대한 읽기 및 쓰기 작업을 빠르게 수행할 수 있습니다.</li>
<li>개발 생산성 향상
∘ 직관적인 쿼리 언어와 JSON 기반 데이터 저장 방식은 개발자들이 데이터를 더 쉽게 다를 수 있습니다.</li>
</ul>
<h1 id="핵심-기능">핵심 기능</h1>
<ul>
<li>CRUD Operations
∘ 데이터를 생성, 읽기, 업데이트, 삭제 할 수 있는 기본적인 데이터 조작 기능을 제공합니다.</li>
<li>인덱싱
∘ 필드에 인덱스를 생성하여 쿼리 성능을 향상시킬 수 없습니다.</li>
<li>샤딩
∘ 데이터를 여러 샤드로 분할하여 데이터베이스 성능을 확장합니다.</li>
<li>복제
∘ 데이터를 여러 노드에 복제하여 고가용성과 내결함성을 제공합니다.</li>
<li>집계 프레임워크
∘ 데이터 분석 및 자리를 위한 강력한 집계 기능을 제공합니다. 복잡한 데이터 처리를 파이프라인 방식으로 구현할 수 있습니다.</li>
<li>트랜잭션 지원
∘ 다중 문서 연산에서도 일관성을 유지할 수 있습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Trouble Shooting : 순환 참조 문제]]></title>
            <link>https://velog.io/@mangez_js/Trouble-Shooting-%EC%88%9C%ED%99%98-%EC%B0%B8%EC%A1%B0-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@mangez_js/Trouble-Shooting-%EC%88%9C%ED%99%98-%EC%B0%B8%EC%A1%B0-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Mon, 13 Jan 2025 10:07:24 GMT</pubDate>
            <description><![CDATA[<h1 id="순환-참조-문제">순환 참조 문제</h1>
<blockquote>
<p>Spring Boot나 Hibernate를 사용하여 양방향 연관 관계를 정의했을 때 직렬화 과정에서 문제가 발생할 수 있습니다.
순환 참조는 객체 A가 객체 B를 참조하고, 객체 B가 다시 객체 A를 참조하는 상황을 의미합니다.</p>
</blockquote>
<pre><code>@Entity
public class ChatRoom {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToMany(mappedBy = &quot;chatRoom&quot;)
    private List&lt;Message&gt; messages;
}

@Entity
public class Message {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = &quot;chat_room_id&quot;)
    private ChatRoom chatRoom;
}</code></pre><h1 id="해결-방법">해결 방법</h1>
<h3 id="jsonmanagedreference와-jsonbackreference">@JsonManagedReference와 @JsonBackReference</h3>
<blockquote>
<p>Jackson 라이브러리가 제공하는 @JsonManagedReference와 @JackBackReference를 활용</p>
</blockquote>
<ol>
<li>@JsonManagedReference<ul>
<li>부모 역할의 필드에 붙입니다.</li>
<li>역할 : JSON 직렬화 시 포함할 필드로 저장합니다.</li>
</ul>
</li>
<li>@JsonBackReference<ul>
<li>자식 역할의 필드에 붙입니다.</li>
<li>역할 : JSON 직렬화 시 제외될 필드로 저장합니다.</li>
</ul>
</li>
</ol>
<h1 id="효과">효과</h1>
<ul>
<li>문제 해결 : 순환 참조로 인한 스택 오버플로우 문제가 해결되었습니다.</li>
<li>정확한 직렬화 : 부모-자식 관계를 유지하면서 JSON 데이터를 직렬화 할 수 있습니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[기본 프로토콜]]></title>
            <link>https://velog.io/@mangez_js/%EA%B8%B0%EB%B3%B8-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</link>
            <guid>https://velog.io/@mangez_js/%EA%B8%B0%EB%B3%B8-%ED%94%84%EB%A1%9C%ED%86%A0%EC%BD%9C</guid>
            <pubDate>Thu, 02 Jan 2025 12:30:41 GMT</pubDate>
            <description><![CDATA[<h1 id="1-http-hypertext-transfer-protocol">1. HTTP (Hypertext Transfer Protocol)</h1>
<ul>
<li>역할 : 웹 브라우저와 웹 서버 간에 데이터를 전송하는 프로토콜</li>
<li>특징
∘ 클라이언트-서버 모델
∘ 상태 비저장(stateless) : 각 요청은 독립적으로 처리되며, 서버는 요청 간의 상태를 유지하지 않음.</li>
<li>주요 메서드
∘ GET : 데이터 요청
∘ POST : 데이터 전송
∘ PUT : 데이터 업데이트
∘ DELETE : 데이터 삭제</li>
<li>HTTP/2
∘ 멀티플렉싱으로 요청-응답 효율성 개선
∘ 헤더 압축 지원</li>
</ul>
<hr>
<h1 id="2-httpshttp-secure">2. HTTPS(HTTP Secure)</h1>
<ul>
<li>역할 : HTTP에 보안 계층(SSL/TLS)을 추가한 프로토콜</li>
<li>특징
∘ 데이터 암호화 : 클라이언트와 서버 간 데이터가 암호화되어 전송
∘ 인증 : 신뢰할 수 있는 인증서를 통해 서버 신뢰성을 확인
∘ 데이터 무결성 : 데이터가 전송 중 변경되지 않았음을 보장</li>
<li>사용 사례
∘ 온라인 쇼핑몰, 은행 등 민감한 데이터를 다루는 웹사이트</li>
</ul>
<hr>
<h1 id="3-ssltlssecure-sockets-layer-transport-layer-security">3. SSL/TLS(Secure Sockets Layer/ Transport Layer Security)</h1>
<ul>
<li>역할 : 데이터 암호화 및 안전한 통신을 제공</li>
<li>SSL과 TLS의 차이
∘ SSL은 초기 암호화 프로토콜, TLS는 SSL의 개선 버전</li>
<li>작동 방식
∘ 핸드셰이크 과정에서 클라이언트와 서버가 암호화 알고리즘과 키를 협상
∘ 데이터를 암호화하여 안전한 전송 보장</li>
<li>주요 암호화 기술
∘ 대칭 키 암호화 : 데이터 전송 시 사용
∘ 비대칭 키 암호화 : 키 교환 시 사용</li>
</ul>
<hr>
<h1 id="4-dnsdomain-name-system">4. DNS(Domain Name System)</h1>
<ul>
<li>역할 : 도메인 이름(ex: <a href="http://www.mangez.com)%EC%9D%84">www.mangez.com)을</a> IP 주소(ex:123.456.7.890)로 변환</li>
<li>작동 방식<ol>
<li>사용자가 URL 입력</li>
<li>브라우저가 DNS 서버에 IP 주소 요청</li>
<li>DNS 서버가 IP 주소 반환</li>
</ol>
</li>
<li>구성 요소
∘ DNS 리졸버 : 클라이언트 측에서 동작
∘ 권한 있는 DNS 서버 : 도메인 정보를 저장
∘ DNS 캐시 : 최근 조회 기록을 저장하여 속도 향상</li>
<li>DNS 관련 문제
∘ DNS 캐시 중독 : 악성 IP 주소가 캐시에 저장되는 문제
∘ DNS Propagation : 도메인 변경 시 반영에 시간 소요</li>
</ul>
<hr>
<h1 id="5-smtpsimple-mail-transfer-protocol">5. SMTP(Simple Mail Transfer Protocol)</h1>
<ul>
<li>역할 : 이메일 전송을 위한 포로토콜</li>
<li>작동 방식<ol>
<li>이메일 클라이언트가 SMTP 서버에 메시지 전송</li>
<li>SMTP 서버가 수신자의 이메일 서버에 메시지 전달</li>
</ol>
</li>
<li>보안
∘ SMTP는 원래 암호화가 없으므로 TLS를 통해 보안을 강화</li>
<li>포트
∘ 25 : 기본 포트
∘ 465 : SSL/TLS 암호화 사용
∘ 587 : 암호화된 SMTP 사용</li>
</ul>
<hr>
<h1 id="6-ipv4internet-protocol-version-4">6. IPv4(Internet Protocol version 4)</h1>
<ul>
<li>역할 : 인터넷에서 장치 간 데이터를 전송하는 기본 프로토콜</li>
<li>특징 
∘ 32비트 주소 체계 : 최대 약 43억 개의 주소
∘ 네트워크 계층에서 작동
∘ 패킷 기반 데이터 전송</li>
<li>제한
∘ IP 주소 부족 문제로 인해 IPv6로의 전환 필요</li>
</ul>
<hr>
<h1 id="7-ipv6internet-protocol-version-6">7. IPv6(Internet Protocol version 6)</h1>
<ul>
<li>역할 : IPv4의 주소 부족 문제를 해결한 차세대 인터넷 프로토콜</li>
<li>특징
∘ 128비트 주소 체계 : 사실상 무한대의 주소 제공
∘ 향상된 보안 : IPsec 기본 지원
∘ 간소화된 헤더 구조로 라우팅 효율성 향상</li>
<li>주소 표현
∘ 콜론(:)으로 구분된 8개의 16진수 그룹
∘ ex : <code>2001:0db8:85a3:0000:0000:8a2e:0370:7334</code></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Nginx]]></title>
            <link>https://velog.io/@mangez_js/Nginx</link>
            <guid>https://velog.io/@mangez_js/Nginx</guid>
            <pubDate>Wed, 01 Jan 2025 05:39:06 GMT</pubDate>
            <description><![CDATA[<h1 id="nginx란">Nginx란?</h1>
<blockquote>
<p>고성능의 HTTP 및 역방향 프록시 서버, 메일 프록시 서버, 일반 TCP/UDP 로드 밸런서로 사용되는 오픈 소스 소프트웨어</p>
</blockquote>
<h1 id="주요-기능">주요 기능</h1>
<p>1) HTTP 웹 서버</p>
<ul>
<li><p>정적 콘텐츠 제공에 최적화 되어 있습니다.</p>
</li>
<li><p>동적 콘텐츠는 외부 애플리케이션 서버와의 연동을 통해 처리
2) 역방향 프록시(Reverse Proxy)</p>
</li>
<li><p>클라이언트 요청을 백엔드 서버로 전달하고 응답을 변환합니다.</p>
</li>
<li><p>백엔드 서버의 부하를 분산하거나 보안을 강화할 수 있습니다.
3) 로드 밸런싱</p>
</li>
<li><p>다수의 서버에 트래픽을 분산하여 부하를 줄이고 고가용성을 제공합니다.</p>
</li>
<li><p>여러 로드 밸런싱 알고리즘 지원:</p>
<ul>
<li>Round Robin(기본)</li>
<li>Least Connections(가장 적은 연결)</li>
<li>IP Hash(클라이언트 IP 기반)
4) 캐싱</li>
<li>정적 콘텐츠 또는 백엔드 서버의 동적 콘텐츠를 캐싱하여 성능을 향상시킵니다.
5) SSL/TLS 지원</li>
<li>HTTPS를 지원하며, SSL/TLS 인증서를 쉽게 설정할 수 있습니다.</li>
<li>HTTP/2와 같은 최신 프로토콜 지원
6) TCP/UDP 로드 밸런싱</li>
<li>HTTP가 아닌 일반 네트워크 프로토콜(TCP, UDP)에 대한 부하 분산 기능
7) 매일 프록시</li>
<li>IMAP, POP3, SMTP와 같은 이메일 프로토콜을 지원<h1 id="특징">특징</h1>
1) 고성능</li>
<li>이벤트 기반(비차단 I/O) 아키텍처를 사용하여 동시 연결 수를 효율적으로 처리</li>
<li>기존의 프로세스 기반 서버(Apache) 보다 적은 리소스로 더 많은 요청 처리 가능
2) 경량성</li>
<li>메모리 사용량이 적으며, 설정 파일이 간단하고 가볍습니다.
3) 확장성</li>
<li>모듈화된 구조로 추가 기능을 쉽게 확장 기능</li>
<li>동적 모듈 로드를 지원
4) 안정성</li>
<li>높은 안정성과 가용성, 적은 다운타임을 제공
5) 다기능</li>
<li>다양한 역할(웹 서버, 프록시 서버, 로드 밸런스)을 수행</li>
</ul>
<h1 id="nginx-vs-apache">Nginx VS Apache</h1>
<table>
<thead>
<tr>
<th>특징</th>
<th>Nginx</th>
<th>Apache</th>
</tr>
</thead>
<tbody><tr>
<td>처리 방식</td>
<td>이벤트 기반(비차단 I/O)</td>
<td>프로세스/스레드 기반</td>
</tr>
<tr>
<td>동시 처리</td>
<td>높은 동시 연결 처리 가능</td>
<td>많은 열결 시 리소스 소비 증가</td>
</tr>
<tr>
<td>정적 콘텐츠</td>
<td>빠르고 효율적</td>
<td>비교적 느림</td>
</tr>
<tr>
<td>동적 콘텐츠</td>
<td>별도의 애플리케이션 서버와 연동</td>
<td>모듈(PHP,Python 등)로 직접 처리 가능</td>
</tr>
<tr>
<td>설정 파일</td>
<td>간단하고 가독성이 좋음</td>
<td>더 세분화된 설정 가능</td>
</tr>
</tbody></table>
<h1 id="주요-구성-요소">주요 구성 요소</h1>
<p>1) Worker Process </p>
<ul>
<li>클라이언트 요청을 처리하며, 비차단 이벤트 기반으로 작동합니다.</li>
<li>병렬로 여러 요청을 효율적으로 처리
2) Master Process</li>
<li>Worker 프로세스를 관리하고 설정 파일 변경을 감지하며 로그를 관리
3) Configuration</li>
<li>설정 파일은 /etc/nginx/nginx.conf에 위치</li>
<li>설정 파일 구조
∘ Main : 글로벌 설정(worker 프로세스 수, 로그 위치 등)
∘ HTTP : HTTP 관련 설정(서버, 로드 밸런싱 등)
∘ Server : 도메인 별 가상 호스트 설정
∘ Location : 요청 URI에 따라 처리 규칙 지정</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>