<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>yune._.log</title>
        <link>https://velog.io/</link>
        <description>yune's coding</description>
        <lastBuildDate>Tue, 26 Sep 2023 10:44:42 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>yune._.log</title>
            <url>https://velog.velcdn.com/images/yune_/profile/567dbede-c532-4c36-b5ea-cd08326b3180/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. yune._.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/yune_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[Back-end] Spring - Interceptor(Servlet)에서 @PathVariable값 가져오기]]></title>
            <link>https://velog.io/@yune_/Back-end-Spring-InterceptorServlet%EC%97%90%EC%84%9C-PathVariable%EA%B0%92-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0</link>
            <guid>https://velog.io/@yune_/Back-end-Spring-InterceptorServlet%EC%97%90%EC%84%9C-PathVariable%EA%B0%92-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0</guid>
            <pubDate>Tue, 26 Sep 2023 10:44:42 GMT</pubDate>
            <description><![CDATA[<p>request url이 다음과 같다면</p>
<pre><code class="language-java">@RequestMapping(&quot;/{id}&quot;)</code></pre>
<br>

<p>Spring Controller에서는 <code>@PathVariable</code>로 값을 가져올 수 있다. 하지만 Interceptor는 Servlet 기반으로 코드를 작성해야 하기 때문에 해당 어노테이션을 사용하지 못한다.</p>
<pre><code class="language-java">@PathVariable(&quot;id&quot;) String blogId</code></pre>
<br>

<p>Servlet 기반 코드에서 <code>@PathVariable</code> 데이터를 가져오고 싶다면??? 이렇게 가져오면 된다!!</p>
<pre><code class="language-java">public class AdminInterceptor extends HandlerInterceptorAdapter{
    @Override
      public boolean preHandle(final HttpServletRequest request,final HttpServletResponse response,final Object handler)
          throws Exception {

            Map&lt;String, String&gt; pathVariables = (Map&lt;String, String&gt;) request
                                                .getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);

          }
}</code></pre>
<p>Map에 PathVariable의 name과 value를 자동으로 매핑해줌!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] BigDecimal]]></title>
            <link>https://velog.io/@yune_/Java-BigDecimal</link>
            <guid>https://velog.io/@yune_/Java-BigDecimal</guid>
            <pubDate>Mon, 28 Aug 2023 10:42:27 GMT</pubDate>
            <description><![CDATA[<h2 id="📌-bigdecimal-사용-이유">📌 BigDecimal 사용 이유</h2>
<h3 id="java의-실수-자료형">Java의 실수 자료형</h3>
<table>
<thead>
<tr>
<th>타입</th>
<th>범위</th>
</tr>
</thead>
<tbody><tr>
<td><code>long</code></td>
<td>1.4E-45 ~ 3.4028235E38</td>
</tr>
<tr>
<td><code>double</code></td>
<td>4.9E-324 ~ 1.7976931348623157E308</td>
</tr>
</tbody></table>
<p>Java의 <code>long</code>, <code>double</code> 자료형은 부동 소수점을 사용하기 때문에 내부적으로 수를 저장할 때 이진수의 근사치를 저장한다. 따라서 소수점 이하 사칙연산 시 오차가 발생하여 정확한 값을 보장하지 않는다.</p>
<pre><code class="language-java">double value1 = 12.23;
double value2 = 34.45;

// 기대값 : 46.68
System.out.println(value1 + value2);  // 46.68000000000001</code></pre>
<p>위의 예제에서도 결과값으로 <code>46.68</code>이 출력될 것 같지만 실제로 <code>46.68000000000001</code>이 출력된다. 소수점을 정확하게 표현하는 것이 아니라 근사값으로 처리하기 때문이다. 이렇듯, 컴퓨터에서의 실수 표현은 근사값을 표현하는 것으로 이해해야 한다.</p>
<br>

<p>→ 이러한 문제 때문에 <strong>숫자에 민감한 금융 거래</strong>, <strong>소수점 단위의 정확한 연산</strong>이 필요할 때는 <strong><code>BigDecimal</code></strong>을 사용한다.</p>
<br>


<h2 id="📌-bigdecimal">📌 BigDecimal</h2>
<h3 id="특징">특징</h3>
<ul>
<li>참조 타입(Reference Type)이기 때문에 연산자 사용이 불가능하다.</li>
<li>소수를 사용하지 않고 내부적으로  정수*$$10^x$$ 로 표현하므로 정확한 숫자 표현이 가능하다.</li>
<li>불변성(Immutable) : 연산 메서드 사용 시 객체 내부의 값이 변경되는 것이 아니라 연산 결과값을 갖는 새로운 객체가 생성되어 반환된다.</li>
<li>원시 타입(Primitive Type)에 비해 사용이 불편하고 속도가 느리다는 단점이 있지만, 소수 계산의 정확도를 위해 <code>BigDecimal</code>을 사용해야 한다.</li>
</ul>
<br>

<h3 id="주의사항">주의사항</h3>
<blockquote>
<p><code>BigDecimal</code> 객체 생성 시 <strong><code>String</code>으로 생성</strong>해야 한다.</p>
</blockquote>
<ul>
<li><code>double</code>로 생성하면 Java가 <code>double</code> 근사치를 <code>BigDecimal</code>에 넘겨주게 되어 오차가 발생할 수 있다.</li>
</ul>
<br>

<h3 id="사용-방법">사용 방법</h3>
<h4 id="생성">생성</h4>
<pre><code class="language-java">import java.math.BigDecimal; // math 클래스 import

// 문자열로 생성
BigDecimal bigDecimal = new BigDecimal(&quot;123.45678&quot;);

// double 타입으로 초기화하는 방법 - valueOf
// 내부적으로 생성자 + 문자열을 사용한다.
BigDecimal bigDecimal2 = BigDecimal.valueOf(123.456);


// 아래처럼 사용하지 말것!!!!
// 12.230000000000000426325641456060111522674560546875
BigDecimal bigDecimal3 = new BigDecimal(12.23);</code></pre>
<br>

<h4 id="연산">연산</h4>
<p><code>BigDecimal</code>은 문자열이기에 사칙연산이 불가능하다. 따라서 <code>BigDecimal</code> 클래스의 메서드를 사용해야 한다.</p>
<table>
<thead>
<tr>
<th>연산</th>
<th>메서드</th>
</tr>
</thead>
<tbody><tr>
<td>+</td>
<td>bigDecimal.add(BigDecimal val)</td>
</tr>
<tr>
<td>-</td>
<td>bigDecimal.subtract(BigDecimal val)</td>
</tr>
<tr>
<td>*</td>
<td>bigDecimal.multiply(BigDecimal val)</td>
</tr>
<tr>
<td>/</td>
<td>bigDecimal.divide(BigDecimal val)</td>
</tr>
<tr>
<td>%</td>
<td>bigDecimal.remainder(BigDecimal val)</td>
</tr>
</tbody></table>
<br>

<h4 id="지수e-제거">지수(E) 제거</h4>
<blockquote>
<p><code>toPlainString()</code> 메서드를 통해 <code>2.0E7</code>과 같은 지수(E) 표현을 제거할 수 있다.</p>
</blockquote>
<pre><code class="language-java">// toPlainString() : 생성자로 전달받은 값을 지수 표현없이 반환한다.

public void toPlainString() {
    System.out.println(new BigDecimal(&quot;2564000&quot;).toPlainString());  // 2564000
    System.out.println(new BigDecimal(&quot;2.564E6&quot;).toPlainString());  // 2564000
}</code></pre>
<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p>*<em>Q. *</em></p>
<p>*<em>A. *</em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] Java의 메모리 구조]]></title>
            <link>https://velog.io/@yune_/Java-Java%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@yune_/Java-Java%EC%9D%98-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Thu, 01 Jun 2023 10:42:05 GMT</pubDate>
            <description><![CDATA[<h2 id="📌jvm">📌JVM</h2>
<p>앞서 JVM에 대해 알아본 것처럼,
Java 프로그램이 실행되면 JVM(자바 가상 머신)이 OS로부터 메모리를 할당받고 이를 용도에 따라 여러 영역으로 나누어 관리한다.</p>
<h3 id="프로그램-실행-과정">프로그램 실행 과정</h3>
<ol>
<li>JVM : OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다.</li>
<li>자바 컴파일러 : 자바 파일(.java)을 자바 바이트 코드(.class)로 변환한다.</li>
<li>Class Loader : 바이트 코드를 런타임 데이터 영역에 배치하여 JVM의 메모리에 올리고, 실질적인 수행이 이루어진다.</li>
<li>실행과정에서 필요에 따라 GC와 같은 관리 작업을 수행한다.</li>
</ol>
<p>이 중, JVM의 <strong>런타임 데이터 영역(Runtime Data Area)은 JVM의 메모리 영역</strong>으로, <strong>자바 프로그램을 실행할 때 사용되는 데이터들을 적재</strong>하는 영역이다.
런타임 데이터 영역을 더 자세히 알아보자</p>
<br>

<h2 id="📌런타임-데이터-영역runtime-data-area---java의-메모리-구조">📌런타임 데이터 영역(Runtime Data Area) - Java의 메모리 구조</h2>
<blockquote>
</blockquote>
<p>JVM의 런타임 데이터 영역은 JVM이 프로그램을 수행하기 위해 OS로부터 할당받은 메모리 영역으로, 자바 프로그램 실행을 위한 데이터들을 적재한다.</p>
<p><img src="https://velog.velcdn.com/images%2Fshin_stealer%2Fpost%2F024b42b8-85fa-4393-9668-6ef15227a0d0%2Fimage.png" width="100%"></p>

<p>자바의 메모리 공간은 크게 Method 영역, Heap 영역, Stack 영역으로 구분되고, 데이터 타입에 따라 할당된다.</p>
<p><strong>1. 메소드 영역 (Method Area)</strong></p>
<ul>
<li>전역변수와 static변수를 저장하며, Method영역은 프로그램의 시작부터 종료까지 메모리에 남아있다.</li>
</ul>
<p><strong>2. 힙 영역 (Heap)</strong></p>
<ul>
<li>new 키워드로 생성되는 객체(인스턴스), 배열 등과 같이 동적으로 생성된 데이터가 Heap 영역에 저장되며, 가비지 컬렉션에 의해 메모리가 관리된다.</li>
</ul>
<p><strong>3. 스택 영역 (Stack)</strong></p>
<ul>
<li>지역변수와 매개변수 데이터 값이 저장되는 공간이며, 메소드가 호출될 때 메모리에 할당되고 종료되면 메모리가 해제된다. </li>
<li>LIFO(Last In First Out), 나중에 들어온 데이터가 먼저 나가는 구조를 가진다.</li>
<li>변수에 새로운 데이터가 할당되면 이전 데이터는 지워진다.</li>
</ul>
<p><strong>4. PC 레지스터 (PC Register)</strong></p>
<ul>
<li>현재 실행되는 부분의 주소와 명령을 저장한다.</li>
</ul>
<p><strong>5. 네이티브 메서드 스택 (Native Method Stack)</strong></p>
<ul>
<li>자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역으로, 보통 C/C++등의 코드를 수행하기 위한 스택이다.</li>
</ul>
<br>

<h3 id="공유-범위">공유 범위</h3>
<ul>
<li>모든 스레드가 공유해서 사용 (GC의 대상)<ul>
<li>힙 영역 (Heap Area)</li>
<li>메서드 영역 (Method Area)<br></li>
</ul>
</li>
<li>스레드(Thread) 마다 하나씩 생성<ul>
<li>스택 영역 (Stack Area)</li>
<li>PC 레지스터 (PC Register)</li>
<li>네이티브 메서드 스택 (Native Method Stack)</li>
</ul>
</li>
</ul>
<br>

<h3 id="각-메모리-영역이-할당되는-시점">각 메모리 영역이 할당되는 시점</h3>
<ol>
<li>Method 영역 : JVM이 동작해서 클래스가 로딩될 때 생성 (JVM이 실행되면서 생기는 공간)</li>
<li>Stack 영역 : 컴파일 타임 시 할당</li>
<li>Heap 영역 : 런타임시 할당</li>
</ol>
<blockquote>
</blockquote>
<ul>
<li>컴파일 타임 : 소스 코드가 기계어로 변환되어 실행 가능한 프로그램이 되는 과정</li>
<li>런타임 : 컴파일 타임 이후 프로그램이 실행되는 때</li>
</ul>
<br>

<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p><strong>Q. Java의 메모리 구조에 대해 설명해주세요</strong></p>
<p>*<em>A. *</em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Back-End] MyBatis, JPA (SQL Mapper, ORM)]]></title>
            <link>https://velog.io/@yune_/Back-End-MyBatis-JPA-SQL-Mapper-ORM</link>
            <guid>https://velog.io/@yune_/Back-End-MyBatis-JPA-SQL-Mapper-ORM</guid>
            <pubDate>Wed, 31 May 2023 12:45:42 GMT</pubDate>
            <description><![CDATA[<h2 id="🤔mybatis-vs-jpa">🤔MyBatis vs JPA</h2>
<blockquote>
</blockquote>
<p><strong>MyBatis</strong> : Java에서 SQL Mapper를 지원해주는 프레임워크
<strong>JPA</strong> : Java ORM 기술 표준</p>
<br>

<h2 id="✅sql-mapper">✅SQL Mapper</h2>
<ul>
<li>Object와 SQL의 필드를 매핑하여 데이터를 객체화 하는 기술</li>
<li>SQL문을 이용하여 DB에 접근한다.</li>
<li><strong>SQL문을 직접 작성하고 쿼리 수행 결과를 객체와 매핑</strong>하는 방법이다.</li>
<li>DB에 종속적인 문제 (DB에 따라 SQL 문법이 다름)</li>
</ul>
<h2 id="✅orm-object-relational-mapping">✅ORM (Object-Relational Mapping)</h2>
<ul>
<li>Object와 DB테이블을 매핑하여 데이터를 객체화하는 기술</li>
<li><strong>SQL문이 아니라 DB의 데이터 자체와 매핑하기 때문에 SQL문을 직접 작성하지 않는다.</strong> (매핑에 필요한 SQL문을 자동으로 만들어줌)</li>
<li>개발자가 반복적인 SQL을 직접 작성하지 않는다.</li>
<li>DB에 종속적이지 않다.</li>
</ul>
<br>

<h2 id="📌mybatis-sql-mapper">📌MyBatis (SQL Mapper)</h2>
<blockquote>
<p>Java에서 SQL Mapper를 지원해주는 프레임워크</p>
</blockquote>
<ul>
<li>SQL문을 이용하여 DB에 접근한다.</li>
<li>SQL문을 직접 작성하고 쿼리 수행 결과를 객체와 매핑한다.</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li><strong>SQL문을 작성</strong>하기 때문에 join같은 <strong>복잡한 SQL문을 더 쉽게 작성</strong>할 수 있다.</li>
<li>쿼리문을 xml로 분리하기 때문에 관리하기 쉽다.</li>
<li>러닝커브가 낮다.</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li><strong>DB에 종속적</strong>인 문제 (DB에 따라 SQL 문법이 다름)</li>
<li>기본적인 CRUD 모두 직접 작성해야 한다.</li>
<li>객체와 쿼리문 모두 관리해야 한다.</li>
</ul>
<br>

<h2 id="📌jpa-orm">📌JPA (ORM)</h2>
<blockquote>
<p>Java ORM의 기술 표준</p>
</blockquote>
<ul>
<li>인터페이스이므로 Hibernate, OpenJPA 등이 JPA를 구현함</li>
</ul>
<h3 id="장점-1">장점</h3>
<ul>
<li><p>SQL문이 아니라 <strong>DB의 데이터 자체와 매핑</strong>하기 때문에 <strong>SQL문을 직접 작성하지 않음</strong>
(매핑에 필요한 SQL문을 자동으로 만들어줌)</p>
</li>
<li><p>CRUD 메소드 기본 제공</p>
</li>
<li><p>SQL문이 아닌 Method를 통해 DB를 조작할 수 있기 때문에 <strong>객체 중심의 개발이 가능</strong>하다.</p>
</li>
<li><p><strong>DB에 종속적이지 않음</strong> → DB의 종류에 관계없이 사용할 수 있다.</p>
</li>
<li><p>유지보수, 리팩토링에 용이하다.</p>
</li>
<li><p><strong>동일한 쿼리에 대한 캐시 기능</strong>을 사용하기 때문에 더욱 높은 성능을 낼 수 있다.</p>
</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li>러닝커브가 높다.</li>
<li>프로젝트 규모가 커서 설계를 잘못했을 경우 성능 저하가 발생할 수 있다.</li>
<li>복잡한 쿼리에 약하다.
→ 따라서 <strong>복잡한 쿼리의 경우 JPQL, QueryDSL을 사용하거나 SQL Mapper를 혼용하여 사용</strong>할 수 있다.</li>
</ul>
<br>

<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p><strong>Q. MyBatis, JPA의 차이점에 대해 설명해주세요.</strong></p>
<p>*<em>A. *</em> MyBatis는 SQL Mapper, JPA는 ORM(Object-Relational Mapping)입니다. 
MyBatis는 SQL Mapper이기 때문에 SQL문을 사용하여 DB에 접근합니다. SQL문을 개발자가 직접 작성하기 때문에 복잡한 SQL문을 더 쉽게 작성할 수 있고, SQL문을 xml파일로 분리하기 때문에 관리하기 쉽다는 장점이 있습니다. 그러나 DB에 따라 SQL 문법이 다르기 때문에 DB 종류를 바꿀 경우 문제가 될 수 있습니다.
JPA는 ORM으로, SQL문이 아니라 DB의 데이터 자체와 매핑합니다. CRUD 메소드를 기본으로 제공하고 SQL문을 자동으로 만들어주기 때문에 개발자는 Method를 사용하며 객체 중심으로 개발할 수 있습니다. SQL문을 직접 작성하는게 아니라서 DB 종류에 관계 없이 사용할 수 있고 캐시 기능도 제공합니다. 그러나 러닝커브가 높고 복잡한 쿼리에 약하기 때문에 추가로 JPQL, QueryDSL을 사용하거나 SQL Mapper를 혼용해서 사용해야 할 수 있습니다.</p>
<p><strong>Q. JPA를 사용한 이유가 무엇인가요?</strong></p>
<p>*<em>A. *</em> JPA의 가장 큰 장점은 반복적인 CRUD SQL을 작성할 필요가 없다는 점이라고 생각합니다. 특히 프로젝트 규모가 커질수록 이런 CRUD SQL이 더 많이 필요하게 됩니다. JPA를 사용하게 되면 이런 간단한 작업은 JPA에게 맡기고 개발자는 다른 일에 집중할 수 있습니다. 제가 진행한 프로젝트는 규모가 크지는 않았지만 이런 JPA의 장점을 느껴보고 싶어서 JPA를 사용하여 프로젝트를 진행하였습니다. 또한 JPA는 러닝커브가 높은데 JPA를 공부하고 사용하면서 다음에 JPA를 사용하게 될 때 도움이 될것이라고 생각하여 미리 공부하고 싶었습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Back-End] REST, REST API, RESTful API]]></title>
            <link>https://velog.io/@yune_/Back-End-RESTful-API</link>
            <guid>https://velog.io/@yune_/Back-End-RESTful-API</guid>
            <pubDate>Fri, 26 May 2023 08:54:57 GMT</pubDate>
            <description><![CDATA[<h2 id="🤔rest-vs-rest-api-vs-restful-api">🤔REST vs REST API vs RESTful API</h2>
<blockquote>
</blockquote>
<p><strong>REST</strong> : 자원을 이름으로 구분해 해당 자원의 상태(정보)를 주고 받는 모든 것
<strong>REST API</strong> : REST를 기반으로 서비스 API를 구현한 것
<strong>RESTful API</strong> : REST의 설계 규칙을 잘 지켜서 설계된 API (REST의 원리를 잘 따르는 시스템)</p>
<h3 id="api-application-programming-interface">API (Application Programming Interface)</h3>
<ul>
<li>응용 프로그램에서 사용할 수 있도록 운영체제나 프로그래밍 언어가 제공하는 기능을 제어할 수 있게 만든 인터페이스</li>
<li>응용프로그램에서 데이터를 주고 받기 위한 방법으로, 어떤 사이트에서 데이터를 공유할 경우 어떠한 방식으로 정보를 요청해야 하는지, 어떠한 데이터를 제공 받을 수 있을지에 대한 규격</li>
</ul>
<br>

<h2 id="📌rest-representational-state-transfer">📌REST (Representational State Transfer)</h2>
<ul>
<li><p>REST는 자원을 이름으로 구분하여 해당 자원의 상태를 주고받는 모든 것을 의미한다.</p>
</li>
<li><p>HTTP URI(Uniform Resource Identifier)를 통해 자원(Resource)을 명시하고
HTTP Method(POST, GET, PUT, DELETE, PATCH 등)를 통해
해당 자원(URI)에 대한 CRUD Operation을 적용하는 것</p>
<blockquote>
</blockquote>
</li>
<li><p><em>Create*</em> : 데이터 생성 (POST)</p>
</li>
<li><p><em>Read*</em> : 데이터 조회 (GET)</p>
</li>
<li><p><em>Update*</em> : 데이터 수정 (PUT, PATCH)</p>
</li>
<li><p><em>Delete*</em> : 데이터 삭제 (DELETE)</p>
</li>
</ul>
<h3 id="구성-요소">구성 요소</h3>
<ol>
<li>자원(Resource) : HTTP URI<ul>
<li>Client는 URI를 이용해 자원을 지정하고 해당 자원의 상태(정보)에 대한 조작을 Server에 요청한다.</li>
<li>ex) &#39;/member/:member_id&#39;</li>
</ul>
</li>
<li>자원에 대한 행위(Verb) : HTTP Method</li>
<li>표현 (Representations) : HTTP Message PayLoad<ul>
<li>Client와 Server가 데이터를 주고받는 형태</li>
<li>JSON, XML을 통해 데이터를 주고 받는 것이 일반적</li>
</ul>
</li>
</ol>
<h3 id="특징">특징</h3>
<p><strong>1. Server-Client (서버-클라이언트 구조)</strong></p>
<ul>
<li>자원이 있는 쪽이 Server, 자원을 요청하는 쪽이 Client<ul>
<li>Server : API 제공, 비즈니스 로직 처리 및 저장</li>
<li>Client : 사용자 인증, context (세션, 로그인 정보) 등을 관리</li>
</ul>
</li>
<li>역할을 구분함으로써 서로 간의 의존성을 줄인다.</li>
</ul>
<p><strong>2. Stateless (무상태)</strong></p>
<ul>
<li>HTTP 프로토콜은 기본적으로 무상태이다. REST 역시 HTTP를 기본으로 하기 때문에 무상태이다.</li>
<li>무상태란 클라이언트의 상태(State)를 서버에 저장하지 않는다는 뜻<ul>
<li>Client의 context를 Server에 저장하지 않는다.</li>
<li>Server는 각각의 요청을 완전히 별개의 것으로 인식하고 처리한다.</li>
<li>각 API 서버는 Client의 요청만을 단순 처리한다.</li>
<li>이전 요청이 다음 요청의 처리에 연관되지 않는다.</li>
<li>Server의 처리 방식에 일관성을 부여하고 부담이 줄어든다.</li>
</ul>
</li>
</ul>
<p><strong>3. Cacheable (캐시 처리 기능)</strong></p>
<ul>
<li>HTTP 프로토콜을 그대로 사용하므로 캐싱 기능을 적용할 수 있다.</li>
<li>대량의 요청을 효율적으로 처리할 수 있다.</li>
<li>캐시 사용을 통해 응답 시간이 빨라지고 성능, 서버의 자원 이용률을 향상시킬 수 있다.</li>
</ul>
<p><strong>4. Layered System (계층 구조)</strong></p>
<ul>
<li>Client는 REST API Server만 호출한다.</li>
<li>REST Server는 다중 계층으로 구성될 수 있다.</li>
<li>보안, 로드 밸런싱, 암호화 등을 위한 계층을 추가하여 구조를 변경할 수 있다.</li>
<li>Proxy, Gateway와 같은 네트워크 기반의 중간매체를 사용할 수 있다.</li>
</ul>
<p><strong>5. Code-On-Demand (Optional)</strong></p>
<ul>
<li>Server로부터 스크립트를 받아서 Client에서 실행한다.</li>
<li>반드시 충족할 필요는 없다.</li>
</ul>
<p><strong>6. Uniform Interface (인터페이스 일관성)</strong></p>
<ul>
<li>URI로 지정한 Resource에 대한 요청을 통일되고 한정적인 인터페이스로 수행한다.</li>
<li>HTTP 표준 프로토콜에 따르는 모든 플랫폼에서 사용이 가능하다. 따라서 특정 언어나 기술에 종속되지 않는다.</li>
</ul>
<br>

<h2 id="📌rest-api">📌REST API</h2>
<ul>
<li>REST를 기반으로 서비스 API를 구현한 것</li>
<li>최근 OpenAPI(누구나 사용할 수 있도록 공개된 API: 구글 맵, 공공 데이터 등), 마이크로 서비스(하나의 큰 어플리케이션을 여러 개의 작은 어플리케이션으로 쪼개어 변경과 조합이 가능하도록 만든 아키텍처) 등을 제공하는 기업 대부분은 REST API를 제공한다.</li>
</ul>
<h3 id="특징-1">특징</h3>
<ul>
<li>각 요청이 어떤 동작이나 정보를 위한 것인지를 그 요청의 모습 자체로 추론이 가능하다.</li>
</ul>
<h3 id="기본-규칙">기본 규칙</h3>
<ol>
<li>URI는 정보의 자원을 표현해야 한다.</li>
<li>자원에 대한 행위는 HTTP Method(GET, POST, PUT, PATCH, DELETE)로 표현한다.</li>
<li>행위(Method)는 URI에 포함하지 않는다.</li>
</ol>
<h3 id="설계-규칙">설계 규칙</h3>
<ol>
<li>URI는 명사를 사용한다. (동사 사용 X)</li>
<li>슬래시( / )로 계층 관계를 표현한다.</li>
<li>URI 마지막에 슬래시 ( / )를 사용하지 않는다.</li>
<li>언더바( _ ) 대신 하이픈( - )을 사용한다.</li>
<li>URI는 소문자로만 구성한다.</li>
<li>파일확장자는 URI에 포함하지 않는다.</li>
<li>행위를 포함하지 않는다. (Bad ex. &quot;<a href="http://y.com/delete-post/1&quot;">http://y.com/delete-post/1&quot;</a>)</li>
<li>HTTP 응답 상태 코드 사용</li>
</ol>
<br>

<p><strong>💡 URI는 정보의 자원만 표현해야 하며, 자원의 행위는 HTTP Method에 명시한다!</strong></p>
<br>

<h2 id="📌restful-api">📌RESTful API</h2>
<p>RESTful이란 REST의 설계 규칙을 잘 지켜서 설계된 API로, REST의 원리를 따르는 시스템을 의미한다.</p>
<p>REST를 사용했다 하여 모두가 RESTful 한 것이 아니라 <strong>REST API의 설계 규칙을 올바르게 지킨 시스템</strong>을 RESTful하다 말할 수 있다.</p>
<pre><code>- CRUD 기능을 모두 POST로 처리 하는 API
- URI 규칙을 올바르게 지키지 않은 API</code></pre><p>위의 예시처럼 REST API의 설계 규칙을 올바르게 지키지 못한 시스템은 REST API를 사용하였지만 RESTful 하지 못한 시스템이라고 할 수 있다.</p>
<h3 id="목적">목적</h3>
<ul>
<li>이해하기 쉽고 사용하기 쉬운 REST API를 만드는 것</li>
</ul>
<p>→ 성능이 중요한 상황에서는 굳이 RESTful한 API를 구현할 필요는 없다!</p>
<br>

<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p><strong>Q. RESTful API란 무엇인가요?</strong></p>
<p>*<em>A. *</em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] JDK, JRE]]></title>
            <link>https://velog.io/@yune_/Java-JDK-JRE</link>
            <guid>https://velog.io/@yune_/Java-JDK-JRE</guid>
            <pubDate>Wed, 24 May 2023 16:16:42 GMT</pubDate>
            <description><![CDATA[<h2 id="📌jre-java-runtime-environment">📌JRE (Java Runtime Environment)</h2>
<blockquote>
<p>자바 실행 환경(Java Runtime Environment)의 약자로, 자바 프로그램을 실행시킬 때 필요한  라이브러리, API, 그리고 JVM이 포함되어 있다.</p>
</blockquote>
<p>예를 들어, 우리가 자바의 자료구조 기능들을 사용할 수 있는 이유는 해당 기능들을 일일이 다 구현했기 때문이 아니라 그것들이 바이트코드로 컴파일된 클래스로 제공되기 때문이다. (.class 파일)
이처럼 널리 쓰이는, JVM에서 도는 라이브러리들을 JVM과 세트로 묶어서 다운받아 설치할 수 있도록 한 것이 JRE이다.</p>
<p>어떤 컴퓨터든 JRE만 설치되어 있으면 자바 프로그램을 실행시킬 수 있다!
<br>
*<em>💡 JRE는 Java로 개발(쓰기)은 안되고 실행(읽기)만 된다!
*</em></p>
<br>

<h2 id="📌jdk-java-development-kit">📌JDK (Java Development Kit)</h2>
<blockquote>
<p>자바 개발 키트(Java Development Kit)의 약자로, 개발자들이 자바로 개발할 때 필요한 라이브러리, 개발 도구들, 그리고 JRE가 포함되어 있다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/yune_/post/c0766fea-64de-4f6b-9bd6-da2f2585723e/image.png" width="70%"></p>

<p>위 그림을 보면 JDK는 JVM, JRE를 모두 포함하고, 이외에 자바로 개발하는데 필요한 development tools도 포함하고 있는 걸 알 수 있다.</p>
<p>JDK안에는 자바로 개발 시 필요한 라이브러리들과 javac, javadoc 등의 개발 도구들을 포함되어 있고, 개발을 하려면 자바 프로그램을 실행도 시켜줘야 하기 때문에 JRE도 함께 포함되어 있다.
따라서 <strong>JDK &gt; JRE &gt; JVM</strong> 의 포함관계가 성립된다.</p>
<p>Java 언어 자체는 무료지만, JDK는 무료인 것도 있고 유료인 것도 있다. 
Oracle JDK가 상업적 이용에 한해서 유료(개인은 무료).
Oracle의 OpenJDK, Azul의 Zulu, Amazon의 Coretto 등은 무료.
유료버전은 성능, 안정성, 최신 기능 등에서 낫다.</p>
<br>

<p>*<em>💡 Java로 프로그램을 직접 개발하려면 JDK가 필요하고 Java로 만들어진 프로그램을 실행시키려면 JRE가 필요하다!
*</em>
<br></p>
<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p><strong>Q. JDK, JRE의 차이점이 무엇인가요?</strong></p>
<p>*<em>A. *</em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Algorithm] 유클리드 호제법]]></title>
            <link>https://velog.io/@yune_/Algorithm-%EC%9C%A0%ED%81%B4%EB%A6%AC%EB%93%9C-%ED%98%B8%EC%A0%9C%EB%B2%95</link>
            <guid>https://velog.io/@yune_/Algorithm-%EC%9C%A0%ED%81%B4%EB%A6%AC%EB%93%9C-%ED%98%B8%EC%A0%9C%EB%B2%95</guid>
            <pubDate>Wed, 24 May 2023 10:22:04 GMT</pubDate>
            <description><![CDATA[<h2 id="📌유클리드-호제법">📌유클리드 호제법</h2>
<blockquote>
<p>2개의 자연수의 <strong>최대공약수(GCD)</strong>를 구하는 알고리즘</p>
</blockquote>
<br>

<h3 id="원리">원리</h3>
<ul>
<li>두 개의 자연수 a, b (a &gt; b)에 대하여, a를 b로 나눈 나머지 = r 이라고 한다면 GCD(a, b) = GCD(b, r)이다.
(a,b의 최대공약수와 b,r의 최대공약수가 같다)</li>
<li>이 성질에 따라 a를 b로 나눈 나머지 = r을 구하고, b를 r로 나눈 나머지 = r’ 를 구해간다.</li>
<li>나머지가 0이 될 때 나눈 수가 a, b의 최대공약수이다.</li>
</ul>
<br>

<h3 id="최대공약수로-최소공배수-구하는-법">최대공약수로 최소공배수 구하는 법</h3>
<ul>
<li>최소공배수 = (a * b) / (최대공약수)</li>
</ul>
<br>

<h3 id="예시">예시</h3>
<pre><code>ex) 60, 48 의 최대공약수, 최소공배수?
    60 % 48 = 12
    48 % 12 = 0
    → 최대 공약수 : 12

    → 최소 공배수 : (60 * 48) / 12 = 240</code></pre><br>

<h3 id="java-코드">Java 코드</h3>
<pre><code class="language-java">private static int gcd(int a, int b) {
        while(b != 0) {
            int r = a % b;
            a = b;
            b = r;
        }
        return a;
    }</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Java] JVM이란?]]></title>
            <link>https://velog.io/@yune_/Java-JVM%EC%9D%98-%EA%B0%9C%EB%85%90-%EA%B8%B0%EB%8A%A5</link>
            <guid>https://velog.io/@yune_/Java-JVM%EC%9D%98-%EA%B0%9C%EB%85%90-%EA%B8%B0%EB%8A%A5</guid>
            <pubDate>Tue, 23 May 2023 10:18:18 GMT</pubDate>
            <description><![CDATA[<h2 id="📌java-프로그램-실행-과정">📌Java 프로그램 실행 과정</h2>
<p><img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrJYLO%2Fbtq4DhpO8YM%2Fhh2afYsQro6dLyuzpNshPk%2Fimg.png" width="80%"></p>

<ol>
<li>프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다. (JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.)</li>
<li>자바 컴파일러가 자바 파일(.java)을 자바 바이트 코드(.class)로 변환한다.</li>
<li>Class Loader를 통해 자바 바이트 코드를 JVM으로 로딩한다.</li>
<li>해석된 바이트 코드는 런타임 데이터 영역에 배치되어 JVM의 메모리에 올라가고, 실질적인 수행이 이루어지게 된다.</li>
<li>실행 과정 속에서 JVM은 필요에 따라 GC와 같은 관리 작업을 수행한다.</li>
</ol>
<br>

<h2 id="📌jvm-java-vertual-machine">📌JVM (Java Vertual Machine)</h2>
<blockquote>
</blockquote>
<ul>
<li>Java로 작성된 프로그램을 실행시켜주기 위한 가상 컴퓨터라고 할 수 있다.</li>
<li>JVM이 OS와 프로그램 사이에 위치하여 <strong>OS, HW의 종류에 상관 없이 프로그램을 실행</strong>할 수 있도록 도와준다.</li>
</ul>
<br>

<h3 id="특징">특징</h3>
<p>JVM 덕분에
&#39;한 번 작성하면 모든 곳에서 실행한다&#39;,
Write Once Run Anywhere(W-O-R-A)가 자바의 원칙이 될 수 있다.</p>
<ul>
<li>Java는 OS에 종속적이지 않다는 특징을 가지고 있다.
→ JVM이 OS와 프로그램 사이에 위치하여 OS, HW의 종류에 상관 없이 프로그램을 실행할 수 있도록 도와준다.</li>
<li>JVM을 사용하면 하나의 바이트 코드(<code>.class</code>)로 모든 플랫폼에서 동작하도록 할 수 있다.</li>
</ul>
<blockquote>
<p><strong>Byte Code(<code>.class</code> 파일)?</strong></p>
</blockquote>
<ul>
<li>JVM이 이해할 수 있는 언어로 변환된 자바 소스코드</li>
<li>사람이 쓰는 자바 코드와 컴퓨터가 읽는 기계어의 중간 단계</li>
<li>기계어가 아니기 때문에 OS에서 바로 실행되지 않음</li>
<li>OS가 Byte Code를 이해할 수 있도록 JVM이 해석해줌</li>
</ul>
<br>

<h3 id="구조">구조</h3>
<p>자바 컴파일러가 바이트 코드로 변환하는 과정을 거치면 JVM 내부의 클래스 로더로 들어오게 된다.</p>
<h4 id="1-자바-인터프리터interpreter">1. 자바 인터프리터(Interpreter)</h4>
<p>Java 컴파일러에 의해 변환된 바이트 코드를 읽고 한 줄씩 기계어로 해석하는 역할</p>
<h4 id="2-클래스-로더class-loader">2. 클래스 로더(Class Loader)</h4>
<p>Java는 동적으로 클래스를 읽어오기 때문에 런타임에서 JVM과 연결된다.
클래스 로더(class loader)는 한 번에 메모리에 모든 클래스를 로드하는 것이 아닌, 필요한 순간에 해당 클래스(.class) 파일을 찾아 메모리에 로딩해주는 역할을 한다.</p>
<h4 id="3-jit-컴파일러just-in-time-compiler">3. JIT 컴파일러(Just-In Time compiler)</h4>
<p>코드를 실행 시점(런타임)에 그때그때 기계어로 통번역 해주는 방식이다.
자주 사용되는 메소드의 경우, 컴파일하고 기계어를 캐싱하여 해당 메소드가 여러 번 호출될 때 매번 해석하는 것을 방지한다.</p>
<h4 id="4-가비지-컬렉터garbage-collector">4. 가비지 컬렉터(Garbage Collector)</h4>
<p>사용하지 않거나 필요없는 객체들을 메모리에서 소멸시키는 역할을 한다. 메모리 관리를 자동으로 해줘서 개발자가 비즈니스 로직에 더 집중할 수 있게 도와준다.</p>
<h4 id="5-런타임-데이터-영역runtime-data-area">5. 런타임 데이터 영역(Runtime Data Area)</h4>
<p>JVM의 메모리 영역으로, 자바 프로그램을 실행할 때 사용되는 데이터들을 적재하는 영역이다.</p>
<br>

<h2 id="📌c언어-vs-java">📌C언어 vs Java</h2>
<h3 id="c언어">C언어</h3>
<p><img src="https://velog.velcdn.com/images/yune_/post/d7d17d68-25ad-466f-bd62-8ba829e785a0/image.png" width="60%"></p>

<ul>
<li>C언어로 작성한 소스를 다른 기종의 컴퓨터에서 실행하려면 소스와 각 기종용 컴파일러를 준비해야 한다.</li>
<li>C언어로 프로그램을 짜고 윈도우 버전, 맥 버전, 리눅스 버전을 만들기 위해서 각각의 컴파일러로 3번 컴파일을 해야 한다.
→ 프로그램 규모가 큰 경우에 부담이 될 수 있으며, 수정할 때마다 3번씩 컴파일해야 한다.</li>
</ul>
<br>

<h3 id="java">Java</h3>
<p><img src="https://user-images.githubusercontent.com/57086195/101237378-829e7700-371b-11eb-8aba-8aeee80afe52.png" width="70%"></p>

<h4 id="실행-과정">실행 과정</h4>
<ol>
<li>Java 컴파일러는 소스코드(<code>.java</code> 파일)를 컴파일해서 <strong>바이트 코드(Byte Code)</strong>(<code>.class</code>)를 생성한다.
 (OS가 인식할 수 있는 기계어로 바로 컴파일 되는게 아니라 JVM이 인식할 수 있는 바이트 코드(<code>.class</code>)로 변환된다.)</li>
<li>JVM은 이 바이트 코드를 사용하고 있는 운영체제에 맞는 실행 파일로 바꿔서 실행시킨다.</li>
</ol>
<h4 id="특징-1">특징</h4>
<ul>
<li>Java는 크로스 플랫폼을 지원하는 언어이며, 이는 Java 프로그램이 컴퓨터 안에서 바로 실행되지 않고, <strong>JVM(Java Virtual Machine)</strong>이라는 가상의 공간에서 실행되기 때문에 가능하다.</li>
<li>하나의 바이트 코드로 JVM이 설치되어 있는 모든 플랫폼에서 동작이 가능하다.</li>
<li>Java 소스코드를 한번만 컴파일 해도 되기 때문에 유지 보수 면에서, 그리고 다양한 운영체제를 지원하는데 있어서 훨씬 편리하다.</li>
</ul>
<br>

<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p><strong>Q. JVM에 대해 말씀해주세요</strong></p>
<p>*<em>A. *</em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[운영체제] 뮤텍스, 세마포어]]></title>
            <link>https://velog.io/@yune_/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EB%AE%A4%ED%85%8D%EC%8A%A4-vs-%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4</link>
            <guid>https://velog.io/@yune_/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%EB%AE%A4%ED%85%8D%EC%8A%A4-vs-%EC%84%B8%EB%A7%88%ED%8F%AC%EC%96%B4</guid>
            <pubDate>Thu, 18 May 2023 13:00:38 GMT</pubDate>
            <description><![CDATA[<h2 id="🤔뮤텍스세마포어-왜-필요할까">🤔뮤텍스&amp;세마포어, 왜 필요할까?</h2>
<blockquote>
<p>뮤텍스, 세마포어는 공유 자원과 임계 영역에 여러 개의 프로세스와 스레드가 접근하는 것을 막는 동기화 도구이다.</p>
</blockquote>
<p>*임계영역(Critical Section)?
여러 프로세스 혹은 스레드가 작업을 수행하면서 공유된 자원을 건드리게 될 수 있는데, 이때 프로그램 코드 상에서 공유 자원에 접근하는 부분을 임계영역이라고 한다.</p>
<br>

<h2 id="📌뮤텍스-mutex">📌뮤텍스 (Mutex)</h2>
<blockquote>
</blockquote>
<p>임계영역(Critical Section)을 가진 프로세스나 스레드들의 실행시간이 서로 겹치지 않고 각각 단독으로 실행(상호배제)되도록 하는 기술 <strong>(동기화 대상이 하나)</strong></p>
<p><img src="https://velog.velcdn.com/images/heetaeheo/post/993d9d0a-bd05-40a3-a4ed-ed45fb84d8ca/image.png" width="70%"></p>

<p>뮤텍스는 보통 한칸만 있는 화장실에 비유한다.
화장실 칸에 들어가기 위해서 <strong>열쇠</strong>가 필요하고, 카운터에 열쇠가 있다면 화장실 칸에 사람이 없으므로 들어갈 수 있다는 뜻이다. 이 열쇠를 가지고 화장실에 들어갈 수 있다.
카운터에 열쇠가 없다면, 화장실에 사람이 있다는 뜻이므로 사람이 나와서 키를 반납할 때까지 기다려야 한다.
(기다리는 사람 중 맨 앞에 있는 사람이 키를 받아 화장실에 간다)</p>
<p><strong>→ 뮤텍스는 Key를 기반으로 동작하며 이 Key에 해당하는 객체를 소유한 프로세스, 스레드만 공유 자원에 접근할 수 있다.</strong></p>
<h3 id="특징">특징</h3>
<ul>
<li>뮤텍스 객체를 두 개 이상의 프로세스/스레드가 동시에 사용할 수 없다.</li>
<li>다중 프로세스들의 공유 리소스에 대한 접근을 조율하기 위해 동기화 또는 락을 사용한다.</li>
<li>이진 세마포어 라고도 한다. (세마포어 초기값이 1이고, 0과 1의 값만 가지는 세마포어)</li>
<li>자원을 소유할 수 있고 책임을 가진다.</li>
<li>뮤텍스는 프로세스의 범위를 가지기 때문에 프로세스가 종료될 때 자동으로 Clean up 된다.</li>
<li>뮤텍스는 소유하고 있는 프로세스만이 뮤텍스를 해제할 수 있다.</li>
</ul>
<br>

<h2 id="📌세마포어-semaphore">📌세마포어 (Semaphore)</h2>
<blockquote>
<p>공유 자원 또는 임계영역(Critical Section)에 여러 프로세스나 스레드가 접근하는 것을 막아줌 <strong>(동기화 대상이 하나 이상)</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/heetaeheo/post/bf4ae4d4-33fa-420a-8d1f-1e43a9b63704/image.png" width="70%"></p>

<p>세마포어는 칸이 여러 개 있는 화장실에 비유할 수 있다.
칸이 3개 존재하고 화장실 입구에 빈칸 개수가 적혀있다고 가정했을 때, 화장실에 가려면 빈칸 개수가 1 이상이어야 들어갈 수 있다. 
이 때 빈칸 개수를 하나 감소시키고 화장실로 입장하고, 나올 때 빈칸 개수를 하나 증가시킨다.
빈칸 개수가 0 또는 음수일 경우에는 해당 숫자만큼의 사람이 대기중인 것이므로 빈칸 개수가 양수로 바뀔 때까지 대기해야 한다.</p>
<p><strong>→ 세마포어는 공유 자원에 접근할 수 있는 프로세스의 허용치만큼 프로세스, 스레드가 동시에 접근할 수 있다. 하나의 세마포어 값을 통해 사용하고 있는 프로세스의 수를 공통으로 관리하며 각각의 프로세스는 세마포어의 값을 확인하고 변경할 수 있다.</strong></p>
<h3 id="세마포어의-연산">세마포어의 연산</h3>
<ul>
<li>세마포어 값이 양수 : 그 숫자만큼의 프로세스가 임계영역에 진입 가능</li>
<li>세마포어 값이 0 / 음수 : 그 숫자만큼의 프로세스가 블록 중</li>
</ul>
<ol>
<li><p>세마포어 초기화 : 세마포어 값을 음이 아닌 값으로 초기화</p>
</li>
<li><p>P 연산</p>
<ul>
<li>해당 세마포어 S값을 감소(진입 여부에 상관 없이 연산 불려지면 무조건 감소)
→ 감소된 값이 음수 : 호출한 프로세스는 블록
→ 감소된 값이 0 / 양수 : 프로세스는 임계영역에 진입해서 수행</li>
</ul>
</li>
<li><p>V 연산</p>
<ul>
<li>세마포어 S값을 증가(자원 사용을 끝내는 프로세스가 연산 호출, 호출 시 무조건 증가)
→ 증가된 값이 0 / 음수(블록된 프로세스 존재) : 블록된 프로세스를 깨워 준비큐로 보냄
→ 증가된 값이 양수 : 블록된 프로세스가 없으므로 종료</li>
</ul>
</li>
</ol>
<h3 id="특징-1">특징</h3>
<ul>
<li>자원 소유가 불가능</li>
<li>세마포어는 시스템 범위에 걸쳐 있고 시스템 상의 파일로 존재한다.</li>
<li>세마포어를 소유하지 않은 프로세스도 세마포어를 해제할 수 있다.</li>
<li>한 프로세스가 특정 시그널(신호)을 수신할 때까지 정해진 위치에서 중지하도록 강제함 → 임계영역에 들어갈 수 없으면 대기<ul>
<li>P연산(수면, 잠자기)과 V연산(깨움)을 이용</li>
<li>사용 가능한 공유 자원의 수를 나타내는 변수 사용</li>
</ul>
</li>
</ul>
<br>

<h2 id="✅뮤텍스-vs-세마포어">✅뮤텍스 vs 세마포어</h2>
<ol>
<li><p><strong>동기화 대상의 개수</strong></p>
<ul>
<li>뮤텍스는 동기화 대상이 1개일 때 사용</li>
<li>세마포어는 동기화 대상이 1개 이상일 때 사용</li>
</ul>
</li>
<li><p>세마포어는 뮤텍스가 될 수 있지만 뮤텍스는 세마포어가 될 수 없다. 뮤텍스는 0,1의 값을 가지는 이진 세마포어라고도 불린다.</p>
</li>
<li><p>뮤텍스 : 자원 소유 가능 + 책임을 가짐
세마포어 : 자원 소유 불가능</p>
</li>
<li><p>뮤텍스 : 소유하고 있는 프로세스만이 뮤텍스 해제 가능
세마포어 : 세마포어를 소유하지 않는 프로세스도 세마포어 해제 가능</p>
</li>
<li><p>뮤텍스 : 프로세스의 범위를 가지며 프로세스 종료될 때 자동으로 Clean up됨
세마포어 : 시스템 범위에 걸쳐 있고 파일 시스템 상의 파일로 존재</p>
</li>
</ol>
<p>뮤텍스와 세마포어는 모두 완벽한 기법은 아니므로 데이터 무결성을 보장할 수 없으며 모든 교착 상태를 해결하지는 못한다.</p>
<br>

<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p><strong>Q. 뮤텍스와 세마포어의 차이점이 무엇인가요?</strong></p>
<p>*<em>A. *</em> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[운영체제] 프로세스, 스레드]]></title>
            <link>https://velog.io/@yune_/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-vs-%EC%8A%A4%EB%A0%88%EB%93%9C</link>
            <guid>https://velog.io/@yune_/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C-%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4-vs-%EC%8A%A4%EB%A0%88%EB%93%9C</guid>
            <pubDate>Wed, 17 May 2023 14:41:14 GMT</pubDate>
            <description><![CDATA[<h2 id="🤔프로세스-vs-스레드">🤔프로세스 vs 스레드?</h2>
<blockquote>
</blockquote>
<p><strong>프로세스</strong> : 운영체제로부터 자원을 할당받는 작업의 단위
<strong>스레드</strong> : 프로세스 내에서의 실행 흐름의 단위</p>
<br>

<h2 id="📌프로세스-process">📌프로세스 (Process)</h2>
<p><img src="https://velog.velcdn.com/images/yune_/post/a721dac5-a32b-42ff-8c9c-b3f0767356aa/image.png" width="50%" height="40%"></p>

<p>위의 그림처럼 프로그램이 메모리에 올라가면 인스턴스화되어 프로세스가 된다.
이후 운영체제의 CPU 스케줄러에 따라 CPU가 프로세스를 실행한다.</p>
<h3 id="특징">특징</h3>
<ul>
<li>프로세스마다 Stack, Heap, Data, Code의 구조로 되어있는 <strong>독립된 메모리 영역을 할당받는다.</strong>
(스택,힙 : 동적 영역 / 데이터,코드 : 정적 영역)</li>
<li>최소 하나의 스레드를 가지고 있다.</li>
<li>멀티프로세스 과정에서 Context Switching(컨텍스트 스위칭)을 통해 프로세스를 교체한다.</li>
<li>각 프로세스는 별도의 주소 공간에서 실행되기 때문에, 한 프로세스는 다른 프로세스의 변수나 자료구조에 접근할 수 없다.</li>
<li>한 프로세스가 다른 프로세스의 자원에 접근하려면 프로세스 간의 통신(IPC, Inter-Process Communication)을 사용해야 한다.
ex) 파이프, 파일, 소켓 등을 이용한 통신 방법</li>
</ul>
<h3 id="단점">단점</h3>
<ul>
<li>프로세스는 Context Switching 과정에서 독립된 메모리 영역 전체를 교체해야하기 때문에 오버헤드가 발생할 수 있다.
→ 효율적인 자원 사용을 위해 멀티 스레드를 사용</li>
</ul>
<br>

<h2 id="📌스레드-thread">📌스레드 (Thread)</h2>
<p><img src="https://velog.velcdn.com/images/hwarang/post/f204a752-9588-4864-814b-de52f7812a2d/image.png" width="60%"></p>

<p>스레드는 프로세스 내에서의 실행 흐름의 단위이고 위 그림과 같이 프로세스는 여러 스레드를 가질 수 있다.
유튜브를 예로 들자면, 동영상을 재생하면서 다른 페이지들을 돌아다니며 데이터들을 받아올 수 있다. 이렇게 한 개의 프로세스(유튜브) 안에서도 여러 가지 일을 동시에 할 필요성이 있고 이를 위해 스레드가 존재하는 것이다.</p>
<h3 id="특징-1">특징</h3>
<ul>
<li><strong>Code, Data, Heap, Stack을 각각 생성하는 프로세스</strong>와 달리,</li>
<li><em>스레드는 프로세스 내에서 Stack 영역만 따로 할당받고 Code, Data, Heap 영역은 스레드끼리 공유*</em>한다.</li>
<li>같은 프로세스 안에 있는 스레드들은 같은 Heap 공간을 공유한다. (프로세스는 다른 프로세스의 메모리에 접근할 수 없음)</li>
</ul>
<h3 id="장점">장점</h3>
<ul>
<li>Code, Data, Heap 영역의 자원을 공유하기 때문에 멀티스레딩을 할 때 효율성이 높고 응답 시간이 단축된다.</li>
<li>동시성에도 큰 장점을 가진다.
(*동시성 : 서로 독립적인 작업들을 작은 단위로 나누고 동시에 실행되는 것처럼 보여주는 것)</li>
</ul>
<h3 id="단점-1">단점</h3>
<ul>
<li>한 스레드에 문제가 생기면 다른 스레드에도 영향을 미친다.</li>
<li>여러 스레드가 동시에 작업을 하면 공유된 영역의 데이터를 동시에 사용하다가 충돌이 날 가능성이 있으므로 주의해야 한다.
(이러한 충돌을 막기 위해 세마포어, 뮤텍스를 사용한다)</li>
</ul>
<br>

<hr>
<br>

<h2 id="📝면접-대비">📝면접 대비</h2>
<p><strong>Q. 프로세스와 스레드의 차이점이 무엇인가요?</strong></p>
<p>*<em>A. *</em> 프로세스는 운영체제로부터 자원을 할당받는 작업의 단위이고, 스레드는 프로세스 내의 실행 흐름입니다. 스레드 덕분에 유튜브에서 동영상을 재생하며 다른 페이지들을 돌아다닐 수 있습니다.</p>
<p>둘의 가장 큰 차이점은 구조일 것 같습니다.
프로세스는 Code, Data, Heap, Stack의 구조를 독립적으로 할당받지만 스레드는 프로세스 내에서 Stack부분만 새로 할당받고 Code, Data, Heap 영역은 공유합니다.</p>
<p>멀티프로세스란 하나 이상의 일을 여러 프로세스에서 병렬로 처리하는 것을 말하는데, 기존에 실행되던 프로세스를 중단하고 다른 프로세스를 실행하는 Context Switching이 일어납니다. 프로세스는 각각 독립된 메모리 영역이기 때문에 4가지 영역 전체를 변경해야 하므로 Context Switching 과정에서 오버헤드가 발생할 수 있다는 단점이 있습니다.</p>
<p>이러한 단점을 해결하기 위해 멀티스레드를 사용합니다.
스레드는 프로세스 내에서 Stack 영역만 따로 할당받고 Code, Data, Heap 영역은 공유하기 때문에 멀티스레드를 할 때 효율성이 높고 응답 시간이 단축됩니다. 멀티프로세스의 단점인 오버헤드 또한 해결해줍니다.</p>
<p>이렇게 보면 멀티스레드이 좋아보이지만 한 스레드에 문제가 생기면 다른 스레드에도 영향을 미친다는 단점이 있습니다. 또한 여러 스레드가 동시에 작업을 하면 공유된 영역의 데이터를 동시에 사용하다가 충돌이 날 가능성이 있으므로 주의해야 합니다.
(이러한 충돌을 막기 위해 세마포어, 뮤텍스를 사용합니다)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[SQL] 'GROUP BY' 동작 방식 (프로그래머스 SQL.GROUP BY - 즐겨찾기가 가장 많은 식당 정보)]]></title>
            <link>https://velog.io/@yune_/SQL-GROUP-BY-%EC%93%B8-%EB%95%8C-%EC%A3%BC%EC%9D%98%ED%95%A0-%EC%A0%90-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-SQL-%EC%A6%90%EA%B2%A8%EC%B0%BE%EA%B8%B0%EA%B0%80-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%80-%EC%8B%9D%EB%8B%B9-%EC%A0%95%EB%B3%B4</link>
            <guid>https://velog.io/@yune_/SQL-GROUP-BY-%EC%93%B8-%EB%95%8C-%EC%A3%BC%EC%9D%98%ED%95%A0-%EC%A0%90-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-SQL-%EC%A6%90%EA%B2%A8%EC%B0%BE%EA%B8%B0%EA%B0%80-%EA%B0%80%EC%9E%A5-%EB%A7%8E%EC%9D%80-%EC%8B%9D%EB%8B%B9-%EC%A0%95%EB%B3%B4</guid>
            <pubDate>Fri, 14 Apr 2023 09:15:10 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/131123">https://school.programmers.co.kr/learn/courses/30/lessons/131123</a></p>
<br>
프로그래머스에서 위 SQL 문제를 푸는 도중 문제가 발생했다...
<br><br>


<pre><code class="language-sql">SELECT FOOD_TYPE, REST_ID, REST_NAME, MAX(FAVORITES) FAVORITES
FROM REST_INFO
GROUP BY FOOD_TYPE
ORDER BY FOOD_TYPE DESC;</code></pre>
<p>쿼리를 이렇게 작성했는데 <code>FOOD_TYPE</code> 카테고리 별로     MAX값이 잘 나오지 않은 것.
뭐가 문제인가 찾아보니 <code>GROUP BY</code> 절의 동작 방식의 이해가 부족했다</p>
<hr>
<p><code>GROUP BY</code>를 사용하면 그룹 별로 가장 상단에 있는 데이터들을 임의로 가져온다.</p>
<pre><code class="language-sql">+-----------+---------+-------------+-----------+
| FOOD_TYPE | REST_ID | REST_NAME    | FAVORITES |
+-----------+---------+-------------+-----------+
| 일식        | 00002   | 하이가쯔네    | 112        |
| 일식        | 00023   | 싹쓰리         | 42        |
| 일식        | 00005   | 코슌스        | 123        |
| 일식        | 00004   | 스시사카우스    | 230        |
+-----------+---------+-------------+-----------+</code></pre>
<p>예를 들어, <code>FOOD_TYPE</code>이 일식인 데이터들이 위와 같을 때, 내가 작성했던 쿼리를 적용한다면 </p>
<pre><code class="language-sql">+-----------+---------+-------------+-----------+
| FOOD_TYPE | REST_ID | REST_NAME    | FAVORITES |
+-----------+---------+-------------+-----------+
| 일식        | 00002   | 하이가쯔네    | 230        |
| 일식        | 00023   | 싹쓰리         | 230        |
| 일식        | 00005   | 코슌스        | 230        |
| 일식        | 00004   | 스시사카우스    | 230        |
+-----------+---------+-------------+-----------+</code></pre>
<p>SQL 내부적으로 이렇게 <code>FAVORITES</code>를 전체적으로 MAX값으로 적용하여 맨 위에 있는 컬럼을 가져오게 된다.
따라서 <code>FAVORITES</code>은 원하는 값이 맞고 <code>FOOD_TYPE</code>도 그룹화하여 전부 동일하므로 문제가 없지만, <code>REST_ID</code>, <code>REST_NAME</code> 은 다른 데이터의 값으로 나오게 되는 것이다.</p>
<p><br><br></p>
<pre><code class="language-sql">SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM REST_INFO
GROUP BY FOOD_TYPE
HAVING FAVORITES = MAX(FAVORITES)
ORDER BY FOOD_TYPE DESC;</code></pre>
<p>이 SQL문을 실행하면 문제가 되는 일식 카테고리 자체가 출력이 되지 않는데,
GROUP BY로 카테고리별 맨 첫번째 데이터들을 가져온 후에 HAVING이 실행되기 때문에
가져온 맨 첫번째 데이터가 일식 카테고리의 MAX값이 아니라 출력이 되지 않은 것 같다.
<br></p>
<hr>
<br>

<pre><code class="language-sql"># 1
SELECT A.FOOD_TYPE, A.REST_ID, A.REST_NAME, A.FAVORITES
FROM REST_INFO A, (SELECT MAX(FAVORITES) MAX 
                   FROM REST_INFO 
                   GROUP BY FOOD_TYPE) B
WHERE A.FAVORITES = B.MAX
GROUP BY FOOD_TYPE
ORDER BY FOOD_TYPE DESC;


# 2
SELECT FOOD_TYPE, REST_ID, REST_NAME, FAVORITES
FROM REST_INFO
WHERE FAVORITES IN (SELECT MAX(FAVORITES)
                    FROM REST_INFO 
                    GROUP BY FOOD_TYPE)
GROUP BY FOOD_TYPE
ORDER BY FOOD_TYPE DESC;</code></pre>
<p>이를 해결하기 위해 서브쿼리를 사용하여</p>
<ol>
<li>B 테이블에 <code>FOOD_TYPE</code> 별로 <code>FAVORITES</code>의 MAX값들을 가져와서</li>
<li>A 테이블에서 <code>FAVORITES</code>로 해당 MAX값을 가진 데이터를 가져오고</li>
<li><code>FOOD_TYPE</code> 별로 그룹화하여 정렬한 후 출력해주었다
(1, 2번 둘 다 같은 로직이다)</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[MySQL] Column in field list is ambiguous 에러]]></title>
            <link>https://velog.io/@yune_/MySQL-Column-in-field-list-is-ambiguous-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@yune_/MySQL-Column-in-field-list-is-ambiguous-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Fri, 14 Apr 2023 08:40:35 GMT</pubDate>
            <description><![CDATA[<blockquote>
</blockquote>
<pre><code class="language-sql">Column &#39;REST_ID&#39; in field list is ambiguous</code></pre>
<p>위 에러는 <code>REST_ID</code> 라는 컬럼을 가진 테이블이 많다는 것을 의미한다.
따라서 어느 테이블의 <code>REST_ID</code> 를 사용할 것인지 지정해주면 된다.
<br></p>
<hr>
<br>

<pre><code class="language-sql">SELECT A.REST_ID
FROM REST_INFO A, (SELECT REST_ID, MAX(FAVORITES)
                   MAX FROM REST_INFO 
                   GROUP BY FOOD_TYPE) B</code></pre>
<br>

<p>위의 예시에서 A테이블에도 <code>REST_ID</code>가 존재하고, B테이블에도 <code>REST_ID</code>가 존재하기 때문에 SELECT 절에서 <code>REST_ID</code>라고 하면 위 에러가 발생할 것이다. 
<code>A.REST_ID</code>라고 설정하여 A테이블에서 가져온다는 것을 명시하자</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Github] remote: fatal error in commit_refs 에러]]></title>
            <link>https://velog.io/@yune_/Github-remote-fatal-error-in-commitrefs-%EC%97%90%EB%9F%AC</link>
            <guid>https://velog.io/@yune_/Github-remote-fatal-error-in-commitrefs-%EC%97%90%EB%9F%AC</guid>
            <pubDate>Mon, 27 Mar 2023 13:02:15 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/yune_/post/e76085fe-6d7f-4e09-a8c7-d20feaf3946c/image.png" alt=""></p>
<p>깃허브에 파일을 올리려고 push하는데 에러가 발생했다.
구글링하여 강제 push도 여러번 시도해봤지만 같은 에러로 실패...
결국 깃허브 자체 문제라는 것을 발견하였다,,</p>
<p><a href="https://www.githubstatus.com/">https://www.githubstatus.com/</a></p>
<p>위 사이트에서 깃허브 상태를 알 수 있다!
<img src="https://velog.velcdn.com/images/yune_/post/619ac7d1-0498-465c-9708-5eaccca0feba/image.png" alt="">
현재는 이 상태로 push가 불가능한 상태ㅠㅠ
조금 더 기다려봐야겠다..</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 9095. 1, 2, 3 더하기]]></title>
            <link>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-9095.-1-2-3-%EB%8D%94%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-9095.-1-2-3-%EB%8D%94%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sun, 26 Mar 2023 09:09:16 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/9095">https://www.acmicpc.net/problem/9095</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.</p>
<pre><code>1+1+1+1
1+1+2
1+2+1
2+1+1
2+2
1+3
3+1</code></pre><p>정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.</p>
</br>

<h3 id="풀이">풀이</h3>
<ul>
<li><p><code>dp</code> 배열을 선언하여 구현, <code>dp[i]</code>에는 i를 만들 수 있는 개수가 저장된다.</p>
</li>
<li><p><code>dp[1] = 1</code>, <code>dp[2] = 2</code>, <code>dp[3] = 4</code> 로 초기화한다.
(<code>1</code> / <code>1+1</code>, <code>2</code> / <code>1+1+1</code>, <code>1+2</code>, <code>2+1</code>, <code>3</code>)</p>
</li>
<li><p>밑의 내용처럼 진행되므로 점화식은 <code>dp[i] = dp[i-1] + dp[i-2] + dp[i-3]</code></p>
<pre><code>n=4 일때
- 1+3 -&gt; 1 + 3만들수 있는 개수(dp[3])
- 2+2 -&gt; 2 + 2만들수 있는 개수(dp[2])
- 3+1 -&gt; 3 + 1만들수 있는 개수(dp[1])
n=5 일때
- 1+4 -&gt; 1 + 4만들수 있는 개수(dp[4])
- 2+3 -&gt; 2 + 3만들수 있는 개수(dp[3])
- 3+2 -&gt; 3 + 2만들수 있는 개수(dp[2])
n=6 일때
- 1+5 -&gt; 1 + 5만들수 있는 개수(dp[5])
- 2+4 -&gt; 2 + 4만들수 있는 개수(dp[4])
- 3+3 -&gt; 3 + 3만들수 있는 개수(dp[3])</code></pre></li>
</ul>
</br>

<h3 id="코드">코드</h3>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main_S3_9095_123더하기 {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();

        int T = Integer.parseInt(br.readLine());
        for (int t = 0; t &lt; T; t++) {
            int n = Integer.parseInt(br.readLine());
            int[] dp = new int[n+1];

            for (int i = 1; i &lt; n+1; i++) {
                if(i==1) dp[i] = 1;
                else if(i==2) dp[i] = 2;
                else if(i==3) dp[i] = 4;
                else {
                    dp[i] = dp[i-1] + dp[i-2] + dp[i-3];
                }
            }
            sb.append(dp[n]+&quot;\n&quot;);
        }

        System.out.println(sb);
    }

}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 16926. 배열 돌리기 1]]></title>
            <link>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-16926.-%EB%B0%B0%EC%97%B4-%EB%8F%8C%EB%A6%AC%EA%B8%B0-1</link>
            <guid>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-16926.-%EB%B0%B0%EC%97%B4-%EB%8F%8C%EB%A6%AC%EA%B8%B0-1</guid>
            <pubDate>Sat, 04 Mar 2023 08:34:55 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/16926">https://www.acmicpc.net/problem/16926</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>크기가 N×M인 배열이 있을 때, 배열을 돌려보려고 한다. 배열은 다음과 같이 반시계 방향으로 돌려야 한다.</p>
<pre><code>A[1][1] ← A[1][2] ← A[1][3] ← A[1][4] ← A[1][5]
   ↓                                       ↑
A[2][1]   A[2][2] ← A[2][3] ← A[2][4]   A[2][5]
   ↓         ↓                   ↑         ↑
A[3][1]   A[3][2] → A[3][3] → A[3][4]   A[3][5]
   ↓                                       ↑
A[4][1] → A[4][2] → A[4][3] → A[4][4] → A[4][5]</code></pre><p>예를 들어, 아래와 같은 배열을 2번 회전시키면 다음과 같이 변하게 된다.</p>
<pre><code>1 2 3 4       2 3 4 8       3 4 8 6
5 6 7 8       1 7 7 6       2 7 8 2
9 8 7 6   →   5 6 8 2   →   1 7 6 3
5 4 3 2       9 5 4 3       5 9 5 4
 &lt;시작&gt;         &lt;회전1&gt;        &lt;회전2&gt;</code></pre><p>배열과 정수 R이 주어졌을 때, 배열을 R번 회전시킨 결과를 구해보자.</p>
</br>

<h3 id="풀이">풀이</h3>
<ul>
<li><code>rotate</code> 함수에 배열을 전체적으로 한 번 돌리는 코드를 4방을 이용하여 구현하였다.</li>
<li>배열의 제일 바깥줄부터 안쪽까지 따로따로 돌려줘야 하기 때문에 회전해줘야 하는 직사각형? 개수를 세어 각각 돌려줬다.<ul>
<li>각 직사각형의 출발점은 <code>map[i][i]</code>가 될 것이다.</li>
<li>정사각형이 아니라 직사각형 배열이기 때문에 
돌려줘야 하는 횟수는 <code>Math.min(N, M) / 2</code>가 된다.</li>
</ul>
</li>
<li>4방을 하, 우, 상, 좌로 선언하여 이 순서대로 이동하며 값을 바꿔준다.
값을 바꾸기 전에, 내가 이동할 위치에 있던 값을 <code>cur</code>에 저장해두고
이전 값인 <code>prev</code>를 해당 자리에 넣어주면서 갱신했다.
  값을 바꿔줬으니 이후 <code>prev = cur</code>로 바꾼다.</li>
</ul>
</br>

<h3 id="코드">코드</h3>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main_S1_16926_배열돌리기1 {

    static int N, M, R;
    static int[][] map;
    static int[] dr = { 1, 0, -1, 0 };  // 하 우 상 좌
    static int[] dc = { 0, 1, 0, -1 };

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        N = Integer.parseInt(st.nextToken());
        M = Integer.parseInt(st.nextToken());
        R = Integer.parseInt(st.nextToken());
        map = new int[N][M];

        for (int i = 0; i &lt; N; i++) {
            st = new StringTokenizer(br.readLine());
            for (int j = 0; j &lt; M; j++) {
                map[i][j] = Integer.parseInt(st.nextToken());
            }
        }

        for (int i = 0; i &lt; R; i++) {
            rotate();
        }

        for (int i = 0; i &lt; N; i++) {
            for (int j = 0; j &lt; M; j++) {
                System.out.print(map[i][j]+&quot; &quot;);
            }
            System.out.println();
        }

    }

    private static void rotate() {
        int x = Math.min(N, M);

        for (int i = 0; i &lt; x/2; i++) {
            int r = i;
            int c = i;
            int d = 0;

            int cur = 0;
            int prev = map[i][i];
            while(d&lt;4) {
                int nr = r + dr[d];
                int nc = c + dc[d];

                if(!(nr&gt;=0+i &amp;&amp; nc&gt;=0+i &amp;&amp; nr&lt;N-i &amp;&amp; nc&lt;M-i)) {
                    d++;
                    continue;
                }

                cur = map[nr][nc];
                map[nr][nc] = prev;
                prev = cur;
                r = nr;
                c = nc;
            }    
        }
    }

}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] 모델링, 데이터모델링]]></title>
            <link>https://velog.io/@yune_/SQLD-1-1.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4</link>
            <guid>https://velog.io/@yune_/SQLD-1-1.-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81%EC%9D%98-%EC%9D%B4%ED%95%B4</guid>
            <pubDate>Thu, 23 Feb 2023 10:49:08 GMT</pubDate>
            <description><![CDATA[<h2 id="📌모델링">📌모델링</h2>
<h3 id="개념">개념</h3>
<p>현실세계를 단순하게 표현하는 것</p>
<h3 id="특징">특징</h3>
<ul>
<li>추상화 : 일정한 형식에 맞추어 표현</li>
<li>단순화 : 복잡한 현실을 제한된 언어나 표기법을 통해 이해하기 쉽게 표현</li>
<li>정확화 : 애매모호함을 배제하고 누구나 이해가 가능하도록 정확하게 현상을 기술</li>
</ul>
<p>*시스템 구현, 업무분석 및 업무형상화의 목적
<br></p>
<hr>
<h2 id="📌데이터-모델링">📌데이터 모델링</h2>
<h3 id="개념-1">개념</h3>
<ul>
<li>현실세계의 데이터에 대해 약속된 표기법에 의해 표현하는 과정</li>
<li>데이터베이스를 구축하기 위한 분석/설계의 과정</li>
</ul>
<h3 id="목적">목적</h3>
<ul>
<li>일정한 표기법으로 표현함으로써 업무 내용을 정확하게 분석</li>
<li>분석된 모델로 실제 DB를 생성</li>
</ul>
<p>→ 업무를 설명하고 분석하는 부분에서 의미를 가짐</p>
<h3 id="유의점">유의점</h3>
<ul>
<li><p>중복(Duplication)</p>
<ul>
<li>데이터 중복 저장 방지</li>
</ul>
</li>
<li><p>비유연성(Inflexibility)</p>
<ul>
<li>데이터 정의와 데이터 사용 프로세스를 분리 
→ 작은 변화가 큰 변화를 일으킬 수 있는 가능성 줄임</li>
</ul>
</li>
<li><p>비일관성(Inconsistency)</p>
<ul>
<li>데이터 간 상호 연관 관계에 대해 명확하게 정의하여 일관성 유지<br>
### 종류

</li>
</ul>
<ol>
<li>개념적 데이터 모델링<ul>
<li>추상화 수준 높음, 업무중심적, 포괄적인 수준의 모델링</li>
<li>엔터티와 속성 도출, ERD 작성</li>
<li>전사적 데이터 모델링, EA 수립에 많이 사용</li>
</ul>
</li>
</ol>
</li>
</ul>
<ol start="2">
<li><p>논리적 데이터 모델링</p>
<ul>
<li>구축하고자 하는 업무에 대해 Key, 속성, 관계 등을 표현 (식별자 도출, 속성과 관계 정의)</li>
<li>정규화 수행 → 독립성, 재사용성</li>
<li>데이터 모델링 완료 상태임</li>
</ul>
</li>
<li><p>물리적 데이터 모델링</p>
<ul>
<li>실제 DB에 이식할 수 있도록 성능, 저장 등 물리적인 성격 고려<br>
### DB 스키마 구조 3단계</li>
</ul>
</li>
<li><p>외부스키마(External Schema)</p>
<ul>
<li>각 사용자 단계의 개인적 DB 스키마</li>
<li>사용자 관점, 응용 프로그램이 접근하는 DB를 정의 </li>
</ul>
</li>
<li><p>개념스키마(Conceptual Schema)</p>
<ul>
<li>조직 전체의 통합된 관점으로 표현</li>
<li>데이터 모델링은 통합관점의 개념 스키마를 만들어 가는 과정임</li>
<li>설계자 관점 데이터 모델링의 지향점 </li>
</ul>
</li>
<li><p>내부스키마(Internal Schema)</p>
<ul>
<li>물리적으로 데이터가 저장되는 방법을 표현</li>
<li>개발자 관점, 물리적 저장 구조</li>
</ul>
</li>
</ol>
<br>

<h3 id="erdentity-relationship-model">ERD(Entity-Relationship Model)</h3>
<h4 id="표현-방식">표현 방식</h4>
<ul>
<li>엔터티 : 사각형</li>
<li>관계 : 마름모</li>
<li>속성 : 타원형</li>
</ul>
<p>→ 현실의 데이터 모두 표현 가능</p>
<h4 id="작성-순서">작성 순서</h4>
<ol>
<li>엔터티 도출</li>
<li>엔터티 배치</li>
<li>엔터티 간 관계 설정</li>
<li>관계명 기술</li>
<li>관계차수 표현: 1:1, 1:N, M:N</li>
<li>관계 참여도 기술</li>
<li>관계 필수여부 기술</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 1719. 택배]]></title>
            <link>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-1719.-%ED%83%9D%EB%B0%B0</link>
            <guid>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-1719.-%ED%83%9D%EB%B0%B0</guid>
            <pubDate>Thu, 23 Feb 2023 09:04:18 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/1719">https://www.acmicpc.net/problem/1719</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>명우기업은 2008년부터 택배 사업을 새로이 시작하기로 하였다. 우선 택배 화물을 모아서 처리하는 집하장을 몇 개 마련했지만, 택배 화물이 각 집하장들 사이를 오갈 때 어떤 경로를 거쳐야 하는지 결정하지 못했다. 어떤 경로를 거칠지 정해서, 이를 경로표로 정리하는 것이 여러분이 할 일이다.
<img src="https://velog.velcdn.com/images/yune_/post/82f14857-376e-4378-b421-1b23b0f60b6f/image.png" style="width: 20%; margin: auto">
예시된 그래프에서 굵게 표시된 1, 2, 3, 4, 5, 6은 집하장을 나타낸다. 정점간의 간선은 두 집하장간에 화물 이동이 가능함을 나타내며, 가중치는 이동에 걸리는 시간이다. 이로부터 얻어내야 하는 경로표는 다음과 같다.
<img src="https://velog.velcdn.com/images/yune_/post/5afcf95e-cf93-4f2a-877a-80a4176e660d/image.png" style="margin: auto">
경로표는 한 집하장에서 다른 집하장으로 최단경로로 화물을 이동시키기 위해 가장 먼저 거쳐야 하는 집하장을 나타낸 것이다. 예를 들어 4행 5열의 6은 4번 집하장에서 5번 집하장으로 최단 경로를 통해 가기 위해서는 제일 먼저 6번 집하장으로 이동해야 한다는 의미이다.</p>
<p>이와 같은 경로표를 구하는 프로그램을 작성하시오.</p>
</br>

<h3 id="풀이">풀이</h3>
<p>입력 받을 때 연결되어있는 노드들을 first 배열에 저장한다
1번 2번 노드가 3의 비용으로 연결되어 있으면 <code>fist[1][2] = 2</code>
(1번노드에서 2번노드로 가려면 처음으로 2번 노드를 방문하면 되므로)</p>
<p>이후 플로이드 워셜로 최단거리를 갱신할 때 first배열도 같이 갱신해준다
처음에 <code>first[i][j] = k</code>라고 갱신하였더니 예제에서 <code>first[1][6]</code>에 2가 있어야 하지만 5가 들어 있었다.. 
마지막으로 갱신되는 곳이 5를 경유할 때라서 이런 결과가 나온 것.
따라서 <code>first[i][j] = first[i][k]</code>로 하여, <code>k</code>를 경유하는 최단거리가 갱신될 때 <code>k</code>를 처음으로 방문하는 <code>first[i][k]</code>값으로 넣어줬다</p>
</br>

<h3 id="코드">코드</h3>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main_G3_1719_택배 {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        StringBuilder sb = new StringBuilder();

        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());
        int[][] map = new int[n+1][n+1];
        int[][] first = new int[n+1][n+1];        

        for (int i = 1; i &lt;= n; i++) {
            for (int j = 1; j &lt;= n; j++) {
                if(i==j) continue;
                map[i][j] = 987654321;
            }
        }

        for (int i = 1; i &lt;= m; i++) {
            st = new StringTokenizer(br.readLine());
            int a = Integer.parseInt(st.nextToken());
            int b = Integer.parseInt(st.nextToken());
            int c = Integer.parseInt(st.nextToken());

            map[a][b] = c;
            map[b][a] = c;

            first[a][b] = b;
            first[b][a] = a;
        }

        for (int k = 1; k &lt;= n; k++) {
            for (int i = 1; i &lt;= n; i++) {
                for (int j = 1; j &lt;= n; j++) {
                    if(k==i || i==j) continue;
                    if(map[i][j] &gt; map[i][k]+map[k][j]) {
                        map[i][j] = map[i][k]+map[k][j];
                        first[i][j] = first[i][k];
                    }
                }
            }
        }

        for (int i = 1; i &lt;= n; i++) {
            for (int j = 1; j &lt;= n; j++) {
                if(i==j) sb.append(&quot;- &quot;);
                else sb.append(first[i][j]+&quot; &quot;);
            }
            sb.append(&quot;\n&quot;);
        }

        System.out.println(sb);

    }

}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준] 10986. 나머지합]]></title>
            <link>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-10986.-%EB%82%98%EB%A8%B8%EC%A7%80%ED%95%A9</link>
            <guid>https://velog.io/@yune_/%EB%B0%B1%EC%A4%80-10986.-%EB%82%98%EB%A8%B8%EC%A7%80%ED%95%A9</guid>
            <pubDate>Wed, 22 Feb 2023 13:33:24 GMT</pubDate>
            <description><![CDATA[<p><a href="https://www.acmicpc.net/problem/10986">https://www.acmicpc.net/problem/10986</a></p>
<h3 id="문제-설명">문제 설명</h3>
<p>수 N개 A1, A2, ..., AN이 주어진다. 이때, 연속된 부분 구간의 합이 M으로 나누어 떨어지는 구간의 개수를 구하는 프로그램을 작성하시오.</p>
<p>즉, Ai + ... + Aj (i ≤ j) 의 합이 M으로 나누어 떨어지는 (i, j) 쌍의 개수를 구해야 한다.</p>
<p>($1 ≤ N ≤ 10^6, 2 ≤ M ≤ 10^3$)</p>
<p>N개의 수 A1, A2, ..., AN ($0 ≤ Ai ≤ 10^9$)</p>
<h3 id="풀이">풀이</h3>
<p>누적합을 배열에 저장해놓고 <code>nums[j]-nums[i-1] % M  == 0</code>으로 하였더니 시간 초과 (데이터 범위도 long으로 해야 한다)
<code>nums[j] % M - nums[i-1] % M == 0</code> → <code>nums[j] % M == nums[i-1] % M</code>이면 구간합이 M으로 나누어 떨어진다.
따라서 누적합을 M으로 나눈 나머지를 배열에 저장하고, remain[나머지]++ 하여 나머지의 개수를 세어준다.
나머지 개수가 2개 이상인 것들만 무작위로 2개 뽑아 개수를 세어주고,
나머지가 0인 애들은 2개를 뽑지 않아도 이미 조건을 만족하므로 추가로 카운트해준다.</p>
<h3 id="코드">코드</h3>
<pre><code class="language-java">import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main_G3_10986_나머지합 {

    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());

        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
        long[] nums = new long[N+1];
        long[] remain = new long[M];

        st = new StringTokenizer(br.readLine());
        for (int i = 1; i &lt;= N; i++) {
            nums[i] = (nums[i-1] + Integer.parseInt(st.nextToken())) % M;
            remain[(int)nums[i]]++;
        }

        long count = remain[0];
        for (int i = 0; i &lt; M; i++) {
            if(remain[i] &gt;= 2) {
                long n = remain[i];
                count += n*(n-1)/2;
            }
        }

        System.out.println(count);
    }

}
</code></pre>
]]></description>
        </item>
    </channel>
</rss>