<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Dyunge_100.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 26 Apr 2024 04:53:15 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Dyunge_100.log</title>
            <url>https://images.velog.io/images/dyunge_100/profile/c32749b0-6d4a-47c3-bf72-bb88695e0405/social.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Dyunge_100.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dyunge_100" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[번역] MySQL vs PostgreSQL in 2024]]></title>
            <link>https://velog.io/@dyunge_100/%EB%B2%88%EC%97%AD-MySQL-vs-PostgreSQL-in-2024</link>
            <guid>https://velog.io/@dyunge_100/%EB%B2%88%EC%97%AD-MySQL-vs-PostgreSQL-in-2024</guid>
            <pubDate>Fri, 26 Apr 2024 04:53:15 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>원문 링크: <a href="https://medium.com/dbconvert/mysql-vs-postgres-in-2024-ba44cc07234a">https://medium.com/dbconvert/mysql-vs-postgres-in-2024-ba44cc07234a</a></p>
</blockquote>
<blockquote>
<p>본 글은 원문 내용을 전달하기 쉽게 하고자 원문 내용과 일부 다를 수도 있습니다. 오역이나 잘못된 부분이 있다면 아래 댓글로 달아주세요.</p>
</blockquote>
<p>PostgreSQL과 MySQL은 클라우드 채택으로 인한 쉬운 배포로 인해 급부상하게 되었습니다.
PostgreSQL이 2023년을 지배했지만, 여전히 MySQL은 학습자들에게 매력적입니다.
2024년에 PostgreSQL은 <code>sharding</code>, <code>logical replication</code> 등을 개선하는 것을 목표로 하고 있고, MySQL은 <code>availability</code>, <code>security</code>, <code>analytics</code> 에 초점을 두고 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/c6ad6a1e-e618-4d31-ba41-de6eca4b268a/image.png" alt=""></p>
<p><strong>PostgreSQL과 MySQL의 인기가 급증한 것은 주요 클라우드 업체들에서 이들을 채택한 덕분입니다.</strong> Amazon Web Services, Microsoft Azure, 그리고 Google Cloud까지 다양한 클라우드 업체가 PostgreSQL과 MySQL 서비스를 제공하며, 데이터베이스 배포와 관리를 간소화해주고 있습니다. AWS는 2021년에 Amazon Aurora의 PostreSQL와의 호환 서비스에 대한 급속한 성장을 강조한 바 있습니다.</p>
<p>2010년 오라클이 MySQL을 인수하면서 오픈 소스 데이터베이스 사용자들 사이에서 MySQL의 미래에 대한 우려가 쏟아져 나왔습니다. 그도 그럴 것이 많은 사람들은 오라클이 상업적 이익으로 인해 MySQL의 오픈 소스 정신에 타격을 줄 것이라 우려했습니다. 이러한 불확실성 때문에 일부 사용자들은 강력한 기능과 견고한 오픈 소스 커뮤니티 지원을 받고 있는 PostgreSQL을 대안으로 삼기 시작했습니다.</p>
<h2 id="db-engines-winners">DB-Engines winners</h2>
<p>PostgreSQL은 2023년 <a href="https://db-engines.com/en/blog_post/106?ref=dbconvert.com">DB-Engines</a>에서 발표한 올해의 데이터베이스 관리 시스템으로 선정되었습니다. 지난 10년 동안 PostgreSQL은 DB-Engines DBMS 올해의 수상자로 가장 자주 선정되며, 데이터베이스 커뮤니티 내에서도 지속적인 인기를 과시하고 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/da8a6d7a-d934-4fe3-aba8-38221d490e99/image.png" alt=""></p>
<p>작년 “<a href="https://dbconvert.com/blog/mysql-vs-postgresql/">MySQL vs PostgreSQL in 2023</a>” 가이드는 이 두 인기 있는 RDBMS 사이의 기본적인 유사성, 성능, 유연성, 규모 그리고 사용 용이성을 분석합니다.
MySQL과 PostgreSQL을 비교하는 표는 <a href="https://db-engines.com/en/system/MySQL%3BPostgreSQL?ref=dbconvert.com">db-engines.com</a>에서 찾아보실 수 있습니다.</p>
<h3 id="역사와-발전history-and-development">역사와 발전(History and Development)</h3>
<p>PostgreSQL은 1996년에 처음 출시되었으며 널리 사용되는 오픈 소스 RDBMS가 되었습니다. <strong>SQL 표준을 강력히 준수하고, 강력한 성능과 데이터 무결성 및 보안에 중점을 두고 있는 것으로 잘 알려져 있습니다.</strong></p>
<p>반면 MySQL은 1995년 처음 출시되어 <strong>높은 성능과 사용 편의성으로 인해 웹 애플리케이션에 널리 사용되었습니다.</strong> 2008년에는 썬 마이크로시스템즈에게 인수되었고, 이후 2010년에 오라클이 MySQL을 인수되었습니다.</p>
<h3 id="특징features">특징(Features)</h3>
<p>PostgreSQL과 MySQL은 모두 관계형 데이터베이스 관리 시스템으로서 광범위한 기능을 제공하지만 둘 사이에는 몇 가지 주요한 차이점이 존재합니다.</p>
<ol>
<li><p><strong>데이터 타입(Data Types)</strong> </p>
<ul>
<li>PostgreSQL은 <code>array</code>(배열), <code>hstore</code>(key-value 저장소), <code>JSONB</code>(바이너리 JSON)를 포함한 다양한 고급 데이터 유형을 지원합니다. </li>
<li>반면, MySQL은 더 제한된 데이터 유형 세트를 가지고 있으며, 보다 단순한 웹 애플리케이션을 위해 구성되어 있습니다. </li>
<li>MySQL의 JSON 바이너리 저장 포맷은 PostgreSQL의 <code>JSONB</code>와 비교할 수 있으며, 단순한 JSON 구조와 직관적인 웹 애플리케이션에 적합합니다.</li>
</ul>
</li>
<li><p><strong>지리 공간 데이터 지원(Geospatial Support)</strong> </p>
<ul>
<li>PostgreSQL은 지리적 데이터를 다루기 위한 풍부한 데이터 유형, 함수 및 연산자를 포함하여 지리 공간 데이터를 강력하게 지원합니다. (<a href="https://postgis.net/">PostGIS</a>) </li>
<li>MySQL도 일부만 지원하지만 이 분야에서 더 강력할 수도 있습니다. (<code>R-tree</code> 인덱스 등)</li>
</ul>
</li>
<li><p><strong>인덱싱(Indexing)</strong></p>
<ul>
<li>MySQL에서는 대부분의 사용 사례에 적합한 <code>B-tree</code> 타입이 기본 인덱스 유형입니다. 그 밖에도 <code>Hash</code>, <code>R-tree</code>, <code>Full-text</code>와 같은 인덱스를 지원합니다.</li>
<li>PostgreSQL은 <code>B-tree</code>, <code>Hash</code>, <code>GisT(Generalized Search Tree)</code>, <code>GIN(Generalized Inverted Index)</code>, <code>BRIN(Blocking Range Indexes)</code>와 같은 인덱스들을 포함하여 MySQL보다 더 세밀한 인덱싱 시스템을 가지고 있습니다. 이는 쿼리 성능 최적화 및 데이터 검색을 위한 더 많은 옵션을 제공합니다.</li>
</ul>
</li>
<li><p><strong>그룹 복제(Replication)</strong></p>
<ul>
<li>PostgreSQL과 MySQL은 둘 다 <code>master-slave</code> 형식의 데이터베이스 복제를 수행하지만, 복제 방법과 옵션이 다릅니다. </li>
<li>PostgreSQL은 서드파티 확장을 사용하여 <code>multi-master</code> 복제를 지원합니다.</li>
<li>MySQL은 최근 그룹 복제(Group Replication)라는 새로운 복제 모델을 도입했지만, 아직은 새로운 기능으로 일부 제한이 있습니다.</li>
</ul>
</li>
<li><p><strong>트랜잭션(Transactions)</strong></p>
<ul>
<li>PostgreSQL과 <a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-multi-versioning.html?ref=dbconvert.com">MySQL InnoDB</a>는 MVCC(다중 버전 동시성 제어)를 사용하여 동시 데이터 접근을 처리합니다. </li>
<li>PostgreSQL은 트랜잭션 격리 수준(<code>transaction isolation levels</code>), 원자 트랜잭션(<code>atomic transactions</code>), 세이브포인트(<code>savepoints</code>)와 같은 발전된 트랜잭션 관리 기능을 제공합니다.</li>
<li>반면, MySQL의 트랜잭션 관리 옵션은 더 제한적입니다. 높은 동시성 또는 복잡한 트랜잭션 로직이 필요한 애플리케이션에는 PostgreSQL이 더 적합할 수 있습니다.</li>
</ul>
</li>
<li><p><strong>저장 프로시저(Stored Procedures)</strong></p>
<ul>
<li>PostgreSQL과 MySQL은 저장 프로시저를 지원하지만, 저장 프로시저의 언어와 기능이 다릅니다. </li>
<li>PostgreSQL은 <code>PL/pgSQL</code>, <code>PL/Tcl,</code> <code>PL/Perl</code> 등 다양한 언어로 작성된 저장 프로시저를 지원합니다. </li>
<li>반면, MySQL은 주로 SQL로 작성된 저장 프로시저를 지원합니다.</li>
</ul>
</li>
<li><p><strong>확장 기능(Extensions)</strong></p>
<ul>
<li>PostgreSQL은 개발자가 사용자 정의 기능을 추가하고 데이터베이스의 핵심 기능을 확장할 수 있는 강력한 확장 프레임워크를 갖고 있습니다.</li>
<li>MySQL도 일부 확장 지원을 제공하지만, PostgreSQL과는 다른 수준의 확장성을 가지고 있습니다.</li>
</ul>
</li>
</ol>
<h3 id="데이터-캡처-변경change-data-capture">데이터 캡처 변경(Change Data capture)</h3>
<p><code>CDC</code>(change data capture) 측면에서 MySQL 바이너리 로그(binary logs)와 PostgreSQL의 <code>WALs</code>(write-ahead logs)는 모두 데이터베이스에 대한 변경 사항을 캡처할 수 있습니다. 그러나 CDC의 구체적인 기능과 용도는 다를 수 있습니다.</p>
<p>DBConvert Streams는 MySQL 및 PostgreSQL 트랜잭션 로그를 읽고 레코드를 다른 DB의 SQL(원문은 dialect이라고 적혀있음)로 변환할 수 있는 소프트웨어로, 실시간으로 다른 종류의 데이터베이스 복제에 적합합니다.</p>
<h3 id="성능performance">성능(Performance)</h3>
<p><strong>MySQL은 높은 성능을 자랑하며 대량의 데이터 처리 능력이 탁월합니다. MySQL은 읽기 중심의 작업에 최적화되어 있으며 빠른 인덱싱 시스템을 통해 쿼리 성능을 향상시키는데 도움을 줍니다.</strong> 그러나 쓰기 작업과 결합될 때 lock 경합(<code>lock contention</code>)과 같은 동시성 문제가 발생할 수 있으며, 이는 성능 저하로 이어질 수 있습니다. 테이블 수준에서 lock을 구현함으로써 발생한 문제로, 프로세스 중 쓰기 작업이 진행되는 동안 모든 작업을 중단합니다.</p>
<p>이러한 테이블 수준의 locking 문제를 해결하기 위해 <code>InnoDB</code> 스토리지 엔진이 사용됩니다. <code>InnoDB</code>는 MySQL 생태계에서 가장 인기 있고 널리 사용되는 스토리지 엔진 중 하나로, 행 수준(row-level) locking을 지원하여 쓰기와 읽기가 혼합된 작업에 대한 동시성을 향상시킵니다.</p>
<p>또한, 최근 개발된 고성능 스토리지 엔진인 <code>MyRocks</code>는 쓰기 중심의(write-intensive) 작업을 처리하는 MySQL의 능력을 더욱 향상시켰습니다.</p>
<p><strong>PostgreSQL은 읽기 중심과 쓰기 중심 작업 모두를 처리하도록 설계되었지만, 읽기 중심 작업에 최적화된 MySQL보다 약간 낮은 성능을 보입니다. 그러나 PostgreSQL은 최근 버전에서 복잡한 쿼리 및 데이터 처리와 관련하여 성능을 향상시켰습니다.</strong> </p>
<p>게다가 PostgreSQL은 MySQL에 비해 더 세밀한 인덱싱 시스템을 가지고 있으며, 이는 복잡한 쿼리에 대한 성능을 향상시킬 수 있습니다. 또한, PostgreSQL은 배열과 JSONB와 같은 고급 데이터 유형을 지원하여 데이터 저장 및 검색을 더 효율적으로 할 수 있습니다.</p>
<p>결국, PostgreSQL과 MySQL의 성능은 하드웨어, 데이터 크기, 쿼리 복잡도와 같은 여러 요소에 따라 달라질 수 있습니다.</p>
<p>두 데이터베이스 중에서 선택할 때는 애플리케이션의 특정 요구 사항을 고려하고, 데이터 및 작업 부하와 함께 성능 테스트를 수행하여 가장 적합한 선택을 결정해야 합니다.
→ 즉, 성능 테스트를 수행하여 개발자의 판단 하에 더 적합한 RDBMS를 선택하면 됩니다.</p>
<h3 id="확장성scalability">확장성(Scalability)</h3>
<p>MySQL과 PostgreSQL 모두 확장 가능하지만, 확장성에 있어서 각각 장단점이 존재합니다.</p>
<p><strong>MySQL은 주로 수평적 확장성이 뛰어나다고 알려져 있습니다.</strong> 이는 데이터베이스 클러스터에 노드를 추가함으로써 확장할 수 있다는 의미로, 동시에 많은 연결(a large number of concurrent connections)을 처리해야 하는 웹 애플리케이션에 이상적입니다.</p>
<p><strong>반면, PostgreSQL은 수직적 확장성이 뛰어나다고 알려져 있습니다.</strong> 이는 단일 노드에 메모리와 CPU와 같은 자원을 추가함으로써 대량의 데이터 및 처리 능력을 다룰 수 있다는 의미입니다. 또한 샤딩(sharding)과 같은 기술을 통해 수평적 확장도 지원합니다. 샤딩은 대규모 데이터 세트를 여러 노드로 분할할 수 있게 해줍니다. 복잡한 쿼리와 트랜잭션을 요구하는 애플리케이션, 데이터 웨어하우스 및 비즈니스 인텔리전스 작업에는 PostgreSQL이 선호됩니다.</p>
<p>확장성 측면에서는 애플리케이션의 특정 요구 사항을 고려해야 합니다. 많은 수의 동시 연결을 처리해야 하고 수평적 확장성이 필요한 경우, MySQL이 더 나은 선택일 수 있습니다. 그러나 복잡한 트랜잭션과 쿼리가 필요한 경우에는 PostgreSQL이 더 적합할 수 있습니다.</p>
<h3 id="비용cost">비용(Cost)</h3>
<p>2023년 현재, PostgreSQL은 여전히 완전한 오픈 소스이며 커뮤니티 주도로 운영되고 있는 반면, MySQL은 라이선싱과 관련하여 좀 더 복잡합니다. MySQL은 원래 MySQL AB에 의해 상업 제품으로 개발되었으며, 무료 및 유료 버전이 제공되었습니다. 그러다 2010년 오라클이 MySQL AB을 인수하면서 개발자들 사이에서는 오픈 소스 유료화에 대한 우려가 많았습니다. 그러나 원본 MySQL의 여러 오픈 소스 포크 버전들, 특히 MariaDB와 Percona는 이러한 우려를 완화하는 데 도움을 주었습니다.</p>
<h3 id="mysql을-사용하는-경우는-언제일까요when-to-use-mysql">MySQL을 사용하는 경우는 언제일까요?(When to Use MySQL?)</h3>
<p>PostgreSQL은 많은 최첨단 기능을 가지고 있으며 종종 MySQL보다 더 발전된 복잡한 데이터베이스 관리 시스템으로 간주되지만, 단점도 있습니다.</p>
<p>PostgreSQL의 일반적인 약점은 다음과 같습니다:</p>
<ol>
<li><p>PostgreSQL은 고급 기능과 능력에도 불구하고 MySQL만큼의 인기와 널리 사용되는 수준에 도달하지 못했습니다. 이로 인해 PostgreSQL 생태계에서 경험 많은 개발자나 데이터베이스 관리자가 적고, 지원하는 서드파티 툴의 수도 적습니다. → <strong>한 마디로 생태계 자체가 MySQL에 비해 작습니다.</strong></p>
</li>
<li><p>고급 기능 때문에 PostgreSQL은 MySQL보다 설정 및 관리가 더 복잡할 수 있어, 경험 많은 데이터베이스 관리자와 개발자에게 더 적합합니다. → <strong>사용자 편의상 MySQL은 간단하지만 그에 비해 성능은 강력합니다.</strong> </p>
</li>
<li><p>더 복잡한 구조와 기능 때문에 특정 상황에서 PostgreSQL은 MySQL보다 느릴 수 있습니다. PostgreSQL은 특히 메모리와 CPU 사용 측면에서 MySQL보다 더 많은 자원을 요구할 수 있습니다.</p>
</li>
<li><p>PostgreSQL은 오픈 소스이지만, 고급 기능과 증가된 자원 요구로 인해 구현 및 유지 관리 비용이 여전히 높을 수 있습니다.</p>
</li>
<li><p>PostgreSQL은 새로운 클라이언트 연결마다 새로운 프로세스를 포킹하며, 일반적으로 연결 당 약 10MB의 메모리를 할당합니다. 그러나 이러한 아키텍처는 서로 다른 클라이언트 간에 향상된 보안 및 격리 기능을 제공하도록 설계되었으며, 일반적으로 더 나은 성능, 신뢰성 및 확장성을 위한 절충안으로 간주됩니다.</p>
</li>
<li><p>PostgreSQL은 확장성, 표준 준수, 데이터 무결성을 우선시하도록 설계되었습니다. 이러한 기능들은 특히 단순 읽기 중심의 작업에서 MySQL에 비해 성능을 저하시킬 수 있습니다. 그러나 정확한 성능 차이는 데이터의 크기, 쿼리의 복잡성 및 사용되는 하드웨어와 같은 다양한 요소에 따라 달라집니다.</p>
</li>
</ol>
<h3 id="어떤-마이그레이션이-더-일반적인가which-migration-is-more-common-mysql-to-postgresql-or-postgresql-to-mysql">어떤 마이그레이션이 더 일반적인가?(Which migration is more common: MySQL to PostgreSQL or PostgreSQL to MySQL?)</h3>
<p>MySQL → PostgreSQL 또는 PostgreSQL → MySQL로의 마이그레이션은 각 조직의 필요와 요구에 따라 다릅니다. 일부 조직은 고급 기능, 더 나은 SQL 준수 및 오픈 소스 호환성을 활용하기 위해 MySQL에서 PostgreSQL로 이전([[MySQL에서 PostgreSQL로 마이그레이션하는 방법]])할 수 있습니다. 또한, PostgreSQL은 금융 서비스, 정부, 데이터 웨어하우징과 같이 성능, 확장성 및 보안이 중요한 특정 산업에서 더 널리 사용됩니다.</p>
<p>반면에, 어떤 회사들은 구현 비용이 낮고, 넓은 커뮤니티 지원 및 MySQL 그 자체로의 간편함 때문에 PostgreSQL에서 MySQL로 이전할 수도 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/95ee98e9-9af3-4f51-8f0e-80a5f6c306cb/image.png" alt=""></p>
<p>마이그레이션 트렌드는 다양한 이유로 MySQL에서 PostgreSQL로 이동하는 방향입니다. 이러한 지표들은 MySQL에서 PostgreSQL로 전환하는 사람들이 그 반대보다 많다는 것을 의미합니다.</p>
<ol>
<li><p><strong>마이그레이션 도구의 가용성</strong>
MySQL에서 PostgreSQL로 데이터를 이전하는 데 도움이 되는 오픈 소스 및 상업용 마이그레이션 툴이 많이 있습니다. 반면에 PostgreSQL에서 MySQL로 데이터를 마이그레이션을 도와주는 툴이 상대적으로 적습니다.</p>
</li>
<li><p><strong>온라인 자료</strong>
MySQL → PostgreSQL로 마이그레이션에 대한 온라인 튜토리얼과 자료가 더 많습니다.</p>
</li>
<li><p><strong>커뮤니티 성장</strong>
PostgreSQL 커뮤니티는 MySQL 커뮤니티보다 빠르게 성장하고 있으며, 이는 PostgreSQL에 대한 관심도가 MySQL보다 증가하고 있음을 나타냅니다.</p>
</li>
<li><p><strong>오픈 소스 기여</strong>
PostgreSQL에 대한 오픈 소스 기여의 수가 증가하고 있으며, 이는 더 많은 사람들이 이 기술에 시간과 자원을 투자하고 자신의 필요에 유용하다고 판단하고 있음을 나타냅니다.</p>
</li>
<li><p><strong>기업들의 채택</strong>
NASA, Fujitsu, 미국 연방 항공청(FAA)(<a href="https://finance.yahoo.com/news/us-government-agencies-turn-enterprisedb-100000897.html?guccounter=1&amp;guce_referrer=aHR0cHM6Ly93d3cuZ29vZ2xlLmNvbS8&amp;guce_referrer_sig=AQAAAJD4DJ8v_xgLl4ON9gsvM5QvMQR4y9Ei65tFC8eeGQXK3TzmcM53OrnAyzELmizFlLjQwAnsG8Hk8eB_542STiG7se0WBTxf9PPZC7VWQ8Tg0N2qHhuqUZDApxAyjIq2GtQJ-B9zLHiIKgZmAsSwrxut5eS0UQ6H-aD-Eo6UY2JA">관련 뉴스 링크</a>)과 같은 세계 최대의 데이터 집약적인 조직들이 MySQL에서 PostgreSQL로 전환했다고 공개적으로 밝힌 바 있습니다.</p>
</li>
<li><p><strong>사용자 설문조사</strong>
산업 분석가들과 데이터베이스 전문가들이 수행한 설문조사에 따르면, 더 많은 사람들이 MySQL에서 PostgreSQL로의 전환을 고려하거나 계획하고 있다고 합니다.</p>
</li>
</ol>
<p>이러한 사실들은 MySQL에서 PostgreSQL로의 마이그레이션이 그 반대보다 많이 일어난다는 것을 나타내며, 이는 일부 경우에만 해당할 수 있습니다.</p>
<h3 id="결론conclusion">결론(Conclusion)</h3>
<p>PostgreSQL과 MySQL은 각기 독특한 기능과 한계를 가진 강력한 관계형 데이터베이스 관리 시스템입니다. 한 시스템을 다른 시스템보다 선호하는 결정은 프로젝트의 특정 요구 사항, 예를 들어 데이터의 성격과 양, 쿼리의 복잡성, 성능 및 확장성 요구에 기반해야 합니다. PostgreSQL과 MySQL 모두 2023년에 더욱 발전할 예정이므로, 그들의 최근 개발 상황을 지속적으로 업데이트 받는 것이 중요합니다.</p>
<p>또한, DBConvert Studio와 같은 도구를 사용하면 MySQL과 PostgreSQL 간에 데이터를 양방향으로 마이그레이션하는 데 도움이 될 수 있습니다. 이러한 도구들은 한 데이터베이스에서 다른 데이터베이스로 데이터를 전송하는 과정을 간소화할 수 있으며, 특히 한 시스템에서 다른 시스템으로 전환을 고려할 때 유용할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[VirtualBox 백업하기(feat. 혹시 몰라..)]]></title>
            <link>https://velog.io/@dyunge_100/VirtualBox-%EB%B0%B1%EC%97%85%ED%95%98%EA%B8%B0feat.-%ED%98%B9%EC%8B%9C-%EB%AA%B0%EB%9D%BC</link>
            <guid>https://velog.io/@dyunge_100/VirtualBox-%EB%B0%B1%EC%97%85%ED%95%98%EA%B8%B0feat.-%ED%98%B9%EC%8B%9C-%EB%AA%B0%EB%9D%BC</guid>
            <pubDate>Wed, 03 Apr 2024 03:45:51 GMT</pubDate>
            <description><![CDATA[<p>다른 분들이 백업해놓는 게 좋다고 하셨기도 하고, 같은 부서 내의 후배님도 작업하다가 날라갔다는 말씀을 하셨어서... 위의 박명수님과 같은 상태가 될지도 모른다는 마음에 VirtualBox 백업을 진행하고자 합니다.</p>
<p>VirtualBox에 설치한 OS는 File로 된 이미지 형태(정확히는 <strong>Virtual Disk Image</strong>)입니다. 
다음 기능들을 이용해서 이미지를 저장해보도록 합시다.</p>
<h3 id="1-스냅샷-기능">1. 스냅샷 기능</h3>
<p>저장하고픈 가상 머신 옆의 <strong><code>스냅샷</code></strong> 버튼을 누르면 아래와 같이 화면이 나옵니다.
그리고 <code>찍기</code> 버튼을 누르면 <code>현재 가상 머신의 스냅샷 찍기</code>가 나옵니다. 
원하는 이름과 설명을 적어주고 확인 버튼을 누르게 되면 현재 상태를 이미지로 저장합니다. 
특정 시점에서 시스템 에러가 나도 <code>복원</code> 기능으로 저장한 이미지로 복구할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/27225eff-d416-441d-9135-7da05e8aced1/image.png" alt=""><img src="https://velog.velcdn.com/images/dyunge_100/post/590b3474-f0d1-49da-aaed-194daedde76b/image.png" alt=""></p>
<p>이런 식으로 만든 스냅샷은 가상 머신 이미지를 저장하는 폴더에 들어가 보면 아래와 같이 <strong>Virtual Disk Image</strong>가 생성되었음을 확인할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/c2cd4806-564a-479d-8353-837f2d887294/image.png" alt=""><img src="https://velog.velcdn.com/images/dyunge_100/post/ae3722c5-fbb7-4154-9a6e-6563c2f19778/image.png" alt=""></p>
<blockquote>
<p>이미지가 저장되는 경로는 <strong><code>해당 가상 머신의 설정 &gt; 일반 &gt; 고급 &gt; 스냅샷 폴더</code></strong>를 보시면 알 수 있습니다.</p>
</blockquote>
<br/>

<h3 id="2-머신--복제">2. 머신 &gt; 복제</h3>
<p><code>복제</code> 기능은 하나의 PC 내에 동일한 가상 머신 이미지를 하나 더 만드는 기능입니다.
복제하고픈 가상 머신을 선택하고 <code>복제</code> 버튼을 누르면 다음과 같이 <code>완전한 복제</code> 와 <code>연결된 복제</code>를 선택할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/c2f9531e-43b7-41c7-bf31-faa78d9b8189/image.png" alt=""><img src="https://velog.velcdn.com/images/dyunge_100/post/31228f07-b6e2-4419-a90f-398e82fad477/image.png" alt=""></p>
<p>설명을 보시면 아시겠지만 <code>연결된 복제</code>는 새 가상 머신을 만들더라도 원본 머신과 연결되므로, 
완전히 분리하고 싶다면 <code>완전한 복제</code>를 선택하는 게 더 낫습니다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/4653711a-29a8-4a84-8981-1028bb3a05d3/image.png" alt=""> <img src="https://velog.velcdn.com/images/dyunge_100/post/ceda913b-7530-4458-8e92-9cf6766a3da5/image.png" alt=""></p>
<p>복제 방식을 선택하고 나면 <code>현재 머신 상태</code>를 복제할 것인지, <code>모두</code>를 복제할 것인지 물어보는 창이 나옵니다. </p>
<p><code>현재 머신 상태</code>는 말 그대로 현재 상태 그대로를 새 가상 머신에 복제하는 대신 스냅샷을 만들지 않는 것이고, <code>모두</code>는 현재 상태를 반영하되 원본 가상 머신의 모든 스냅샷을 복사합니다. 
저는 <code>모두</code>를 선택하여 스냅샷까지 복사해보도록 하겠습니다.</p>
<p>복제가 완료되면 아래와 같이 가상 머신 폴더가 하나 더 생기게 됩니다.
보시면 이전에 찍었던 스냅샷까지 완벽하게 복제한 것을 알 수 있습니다.
<img src="https://velog.velcdn.com/images/dyunge_100/post/05a33b43-51ab-4d69-b0f9-9ab611ebffb8/image.png" alt=""><img src="https://velog.velcdn.com/images/dyunge_100/post/883bd1f0-5577-4965-81de-ef0890103621/image.png" alt=""><img src="https://velog.velcdn.com/images/dyunge_100/post/6b075828-20c5-450f-bb47-610bf1b68aad/image.png" alt=""></p>
<p><code>복제</code> 기능은 완전히 분리된 가상 머신 이미지를 만들 수 있으므로, 원본 머신에 문제가 생기더라도 영향이 없다는 장점은 있지만 스냅샷보다는 만드는 데 시간이 조금 더 걸린다는 단점은 있습니다.</p>
<blockquote>
<p>참고 자료
<a href="https://technote.kr/178">VirtualBox, 가상머신 VM 내보내기, 복제, 그리고 스냅샷</a>
<a href="https://itlearningcenter.tistory.com/entry/%E3%80%90VirtualBox%E3%80%91%EC%8A%A4%EB%83%85%EC%83%B7-%EA%B8%B0%EB%8A%A5-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0">스냅숏 기능 사용하기</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Undertow] BadRequestException: Invalid Character Error]]></title>
            <link>https://velog.io/@dyunge_100/Undertow-Invalid-Character-Error</link>
            <guid>https://velog.io/@dyunge_100/Undertow-Invalid-Character-Error</guid>
            <pubDate>Tue, 26 Mar 2024 10:31:09 GMT</pubDate>
            <description><![CDATA[<h2 id="🧨-새로운-에러를-발견했다">🧨 새로운 에러를 발견했다</h2>
<p>제가 다니고 있는 회사는 기본적으로 B2B 제품을 많이 만듭니다. 그에 따라 Spring 프레임워크를 쓰고, 고성능 웹 서버에 대한 요구가 높아 Jetty보다는 undertow를 많이 씁니다. (물론 저도 안정적인 고성능 웹서버라고만 알고 자세히 알지는 못합니다. 후에 조사하고 정리해봐야 할 것 같아요...)</p>
<p>이번 문제는 고객사가 기존에 제공하는 UI 대신 고객사 전용 포털로 사용하면서 발생했습니다.
고객사에서는 왜인지 모르지만 프로젝트 ID를 한글로(왜.. 왜 한글로 하시는 거에요ㅠ) 만들었고, 프로젝트 ID 검증을 UI쪽에서만 진행했던 게 문제였습니다.</p>
<hr>
<h2 id="😨-이게-무슨-에러람">😨 이게 무슨 에러람...</h2>
<p>고객사에서 프로젝트를 삭제하려고 하는데 에러 알림창이 뜨면서 삭제가 진행되지 않는다고 했습니다. 그래서 &quot;오잉? 아무리 한글이라도 ID가 유니크하기 때문에 괜찮은 게 아닌가? 혹시 ID가 중복이 되었나?&quot;하는 생각도 했지만, 만약 정말 그랬다면 테스트를 전부 다 끝내기도 전에 연락이 왔을 겁니다. 그래서 저도 고객사와 똑같은 환경을 만들기 위해 임의로 한글 ID로 된 프로젝트를 생성하고 삭제하려고 보니...</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/cbf5c90e-d890-4083-bc71-634af79cbff9/image.png" alt="무슨 에러일까 이게...?"><em>무슨 에러일까 이게...?</em></p>
<p>처음 보는 에러였습니다.
이게 무슨 에러일까 싶었지만 undertow에서 난 에러는 확실해보였습니다. 
그렇다면 남은 건 검색뿐...! 한 번 검색을 해보았습니다.</p>
<p>다행히도 <a href="https://stackoverflow.com/questions/51327739/wildfly-13-0-0-final-error-ut005014-failed-to-parse-request-io-undertow-util-b">스택오버플로우</a>와 <a href="https://docs.wildfly.org/wildfly-proposals/undertow/WFLY-9724_Allow_unescaped_characters_in_URL.html">WildFly Documentation</a>에 해결 방법이 있더라구요. 내용을 쉽게 말씀드리자면 보안상의 이유로 기본적으로는 URL에 비 ASCII 문자를 처리하지 않고 있는데, 설정을 바꿔주면 가능하다는 내용이었습니다!!</p>
<p>저는 이 내용을 발견하고 바로 설정을 바꾸어주었더니 해결되었습니다.</p>
<hr>
<h2 id="🔨-해결-방법">🔨 해결 방법</h2>
<p>설정은 <code>application.properties</code> 또는 <code>application.yaml</code>에서 바꿔주시면 됩니다. 
<a href="https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.server.server.undertow.options.server">Spring Common Application Properties</a>와 <a href="https://github.com/undertow-io/undertow/blob/ddb4aeeb32f7ed58d715124acf1d464fc14b30dd/core/src/main/java/io/undertow/UndertowOptions.java#L354C107-L354C108">깃헙에 있는 Undertow 소스 코드(UndertowOptions 클래스)</a>를 참고하였습니다.
Maven 기준 설정은 아래와 같이 설정해주시면 됩니다.</p>
<pre><code class="language-properties">server.undertow.options.server.allow-unescaped-characters-in-url=true</code></pre>
<p>Gradle은 아래와 같이 설정해주시면 됩니다.</p>
<pre><code class="language-yml">server:
  undertow:
    options:
      server:
        allow-unescaped-characters-in-url: true</code></pre>
<hr>
<h2 id="🚀-이번-에러를-통해-느낀-점">🚀 이번 에러를 통해 느낀 점</h2>
<blockquote>
<p>역시 검증은 UI에서 한다고 해서 맘 놓을 것이 아니라 서버에서도 해줘야 한다는 게 맞는 것 같습니다. 평소에도 갖고 있는 생각이었지만 더욱 확고해졌습니다.
하지만 덕분에 새로운 것에 대해 알게 되어 기쁩니다.
이 글을 읽는 다른 분들한테도 도움이 되었으면 합니다 :)</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[ChatGPT] Hmm...something seems to have gone wron]]></title>
            <link>https://velog.io/@dyunge_100/ChatGPT-Hmm...something-seems-to-have-gone-wrong</link>
            <guid>https://velog.io/@dyunge_100/ChatGPT-Hmm...something-seems-to-have-gone-wrong</guid>
            <pubDate>Sun, 10 Mar 2024 23:10:37 GMT</pubDate>
            <description><![CDATA[<p>ChatGPT4를 사용하고 있다가 이러한 에러 메시지를 받게 되었습니다...</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/06acfc62-58e5-4474-9c50-6303034e166a/image.png" alt=""></p>
<p><a href="https://www.forbes.com/sites/barrycollins/2024/02/14/chatgpt-down-users-hit-with-error-messages/?sh=551c3d3ea8b7">포브스</a> 에서 게시한 뉴스에 따르면 이러한 메시지를 받은 게 나 뿐만 아니라 전세계 여러 사용자들도 체험한 에러인 듯 보입니다. OpenAI에서는 &quot;이 문제를 계속해서 조사 중&quot;이라고 밝혔다. 아직까지는 이 에러를 계속해서 조사할 뿐 고치지는 못한 것 같습니다.</p>
<p>요즘 금융&amp;경제에 관심을 갖게 돼서 ChatGPT 플러그인을 사용하여 이런 식으로 뉴스를 스크랩하고 정보를 수집하던 참이었는데, 에러가 하루 빨리 고쳐지면 좋겠습니다. <del>그래도 22달러나 냈는데 빨리 고쳐줘ㅠ</del></p>
<p>ps.
<a href="https://help.openai.com/en/articles/8988022-winding-down-the-chatgpt-plugins-beta">OpenAI 사이트에 올라온 기사</a>에 따르면 ChatGPT 플러그인 베타가 2024년 3월 19일부터 종료된다고 합니다. 이때부터는 새 플러그인 설치나 기존 플러그인을 사용해서 새 대화창을 만들 수 없습니다.</p>
<p><strong>단, 2024년 3월 19일부터 &quot;새 대화 생성&quot;이 비활성화될 뿐이지 기존에 사용하던 플러그인 대화는 2024년 4월 9일까지 사용할 수 있다고 하네요!</strong></p>
<p>플러그인 베타를 중단하는 이유는 이후 나올 GPTs에 다양한 플러그인 기능을 포함해서 출시하기 위함이라고 합니다.
<img src="https://velog.velcdn.com/images/dyunge_100/post/28be4017-0581-4f32-ba1a-747d130023d8/image.png" width="200%">
<del><em>ChatGPT 3.5도 이렇게 말했어요</em></del></p>
<hr>
<p>ps) 2024년 3월 20일(수)부터는 ChatGPT 플러그인을 사용할 수 없습니다. <del>위와 같은 문제는 앞으로 더 이상 일어날 일이 없을까요..?</del></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 예외 발생에 따른 필터와 인터셉터에서 처리하기 (feat. DispatcherType)]]></title>
            <link>https://velog.io/@dyunge_100/Spring-%EC%98%88%EC%99%B8-%EB%B0%9C%EC%83%9D%EC%97%90-%EB%94%B0%EB%A5%B8-%ED%95%84%ED%84%B0%EC%99%80-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EC%97%90%EC%84%9C-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0-feat.-DispatcherType</link>
            <guid>https://velog.io/@dyunge_100/Spring-%EC%98%88%EC%99%B8-%EB%B0%9C%EC%83%9D%EC%97%90-%EB%94%B0%EB%A5%B8-%ED%95%84%ED%84%B0%EC%99%80-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0%EC%97%90%EC%84%9C-%EC%B2%98%EB%A6%AC%ED%95%98%EA%B8%B0-feat.-DispatcherType</guid>
            <pubDate>Fri, 03 Jun 2022 01:41:05 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="0-예외-발생과-오류페이지-요청-흐름">0. 예외 발생과 오류페이지 요청 흐름</h2>
</blockquote>
<p>컨트롤러 (예외 발생!) -&gt; 인터셉터 -&gt; 서블릿 -&gt; 필터 -&gt; WAS -&gt; 
WAS가 &#39;/error-page/500&#39; 다시 요청 -&gt; 필터 -&gt; 서블릿 -&gt; 인터셉터 -&gt; 컨트롤러(errorPage/500) -&gt; View를 통해 페이지 호출</p>
<p>예외가 발생하면 오류 페이지를 출력하기 위해 WAS 내부에서 호출이 다시 한 번 발생된다. 
이때 서버 내부에서 필터나 인터셉터가 한 번 더 호출되는 것은 비효율적이다. </p>
<p>그래서 결국 클라이언트로부터 발생한 정상적인 요청인지, 아니면 오류 페이지를 출력하기 위한 내부 요청인지 구분하기 위하여 DispatcherType이라는 추가 정보를 제공한다. </p>
<blockquote>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/3964da72-bf05-493f-bb27-c0465546b6c0/image.png" alt=""></p>
<p>필터는 이런 경우를 위해 DispatcherType이라는 옵션을 제공하는데, enum 형태로 지정되어 있다.</p>
</blockquote>
<h3 id="🥽dispatchertype">🥽DispatcherType</h3>
<ul>
<li>REQUEST : 클라이언트에서 온 요청</li>
<li>ERROR : 에러에 해당하는 요청</li>
<li>FORWARD : 서블릿에서 다른 서블릿이나 JSP를 호출할 때</li>
<li>INCLUDE : 서블릿에서 다른 서블릿이나 JSP의 결과를 포함할 때</li>
<li>ASYNC : 서블릿 비동기 호출</li>
</ul>
<p><br><br></p>
<h4 id="logfilter---dispatchertype-로그를-추가한-예시">LogFilter - DispatcherType 로그를 추가한 예시</h4>
<pre><code class="language-java">@Slf4j
public class LogFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info(&quot;log filter init&quot;);
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        String requestURI = httpRequest.getRequestURI();
        String uuid = UUID.randomUUID().toString();

        try {
            log.info(&quot;REQUEST [{}][{}][{}]&quot;, uuid,
                    request.getDispatcherType(), requestURI);
            chain.doFilter(request, response);
        } catch (Exception e) {
            throw e;
        } finally {
            log.info(&quot;RESPONSE [{}][{}][{}]&quot;, uuid,
                    request.getDispatcherType(), requestURI);
        }
    }

    @Override
    public void destroy() {
        log.info(&quot;log filter destroy&quot;);
    }
}
&gt;```

#### WebConfig

```java
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Bean
    public FilterRegistrationBean logFilter() {
        FilterRegistrationBean&lt;Filter&gt; filterRegistrationBean = new FilterRegistrationBean&lt;&gt;();
        filterRegistrationBean.setFilter(new LogFilter());
        filterRegistrationBean.setOrder(1);
        filterRegistrationBean.addUrlPatterns(&quot;/*&quot;);
        filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST
                , DispatcherType.ERROR
        );
        return filterRegistrationBean;
    }
}
filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.ERROR);</code></pre>
<p>위의 두 가지를 모두 넣으면 클라이언트 요청은 물론이고 오류 페이지 요청에서도 필터가 호출된다. 아무 것도 넣지 않으면 디폴트 값인 DispatcherType.REQUEST가 호출된다. 물론 오류 페이지 요청 전용 필터를 적용하고 싶다면 DispatcherType.ERROR만 지정하면 된다.</p>
<h4 id="서블릿-예외-처리---인터셉터-예시">서블릿 예외 처리 - 인터셉터 예시</h4>
<pre><code class="language-java">@Slf4j
public class LogInterceptor implements HandlerInterceptor {

    public static final String LOG_ID = &quot;logId&quot;;
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestURI = request.getRequestURI();
        String uuid = UUID.randomUUID().toString();
        request.setAttribute(LOG_ID, uuid);
        log.info(&quot;REQUEST [{}][{}][{}][{}]&quot;, uuid, request.getDispatcherType(), requestURI, handler);
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info(&quot;postHandle [{}]&quot;, modelAndView);
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        String requestURI = request.getRequestURI();
        String logId = (String)request.getAttribute(LOG_ID);
        log.info(&quot;RESPONSE [{}][{}][{}]&quot;, logId, request.getDispatcherType(),
                requestURI);
        if (ex != null) {
            log.error(&quot;afterCompletion error!!&quot;, ex);
        }
    }
}</code></pre>
<pre><code class="language-java">@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LogInterceptor())
                .order(1)
                .addPathPatterns(&quot;/**&quot;)
                .excludePathPatterns(
                        &quot;/css/**&quot;, &quot;/*.ico&quot;
                        , &quot;/error&quot;, &quot;/error-page/**&quot; //오류 페이지 경로
                );
    }</code></pre>
<p>앞선 필터의 경우에는 필터를 등록할 때 어떤 DispatcherType에 따라 필터를 적용할지 선택할 수 있었지만 인터셉터는 스프링에서 제공하는 기능이므로 DispatcherType과 무관하게 항상 호출된다. 대신 인터셉터는 오류 페이지를 따로 빼줄 수 있다.</p>
<p><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://develop-writing.tistory.com/97">https://develop-writing.tistory.com/97</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Network] Blocking/Non-Blocking, Sync/Async I/O ]]></title>
            <link>https://velog.io/@dyunge_100/Network-BlockingNon-Blocking-SyncAsync-IO</link>
            <guid>https://velog.io/@dyunge_100/Network-BlockingNon-Blocking-SyncAsync-IO</guid>
            <pubDate>Thu, 26 May 2022 01:42:25 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="io-작업">I/O 작업</h2>
</blockquote>
<p><strong>I/O 란 대개 입력(Input)/출력(Output)</strong>의 약자로, 다양한 분야에서 사용되고 있지만 여기서는 주로 파일 입출력을 다룰 때의 I/O 를 다루기로 한다. 네트워크에서의 소켓 read/send를 생각하면 I/O 가 어떤 작업인지 이해할 수 있다. 더 쉽게 말한다면 컴퓨터끼리 통신할 때 이뤄지는 데이터(파일이나 이미지 등)의 입력과 출력을 받는 과정을 I/O 라고 부를 수 있다.
I/O 작업은 User 레벨에서 이뤄질 수 없고, (어떻게 보면 당연하다.) 
*<em>실제 I/O 작업을 수행하는 것은 Kernel 레벨에서만 가능하다. *</em>
유저 프로세스 또는 쓰레드의 경우 커널에 요청하고 작업 완료가 되어 커널에 반환될 때까지 기다릴 뿐이다.</p>
<hr>
<blockquote>
<h2 id="1-blocking-io-모델">1. Blocking I/O 모델</h2>
<p><strong>가장 기본적인 I/O 모델이다. linux의 모든 소켓 통신은 기본 Blocking I/O로 동작한다. 
I/O 작업이 진행되는 동안 요청한 유저 프로세스는 작업을 중단한 채 반환을 기다리면서 대기하는 방식이다.</strong></p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/7556b430-24e9-4e83-9d58-ef15ff43793f/image.png" alt=""></p>
<p>유저는 커널에 작업을 요청하고, 데이터가 입력될 때까지 대기한다.
그러다 데이터가 입력되면 유저에게 반환값이 전달되는데 그 이후에 유저는 자신의 작업을 다시 수행할 수 있다. 말 그대로 요청을 보낸 경우, 작업이 중단되는 Blocking 상태가 되는 것이다.
이런 경우에는 애플리케이션에서 다른 작업을 수행하지 못하고 대기하게 되므로 자원이 낭비된다.</p>
<p>흔한 예로는 카카오톡 메세지를 보냈는데 메세지를 전송하고 응답할 때까지 대기하는 거라고 생각하면 이해하기 쉽다. 반환값이 오기 전까진 아무 작업도 못한다면 누가 카카오톡을 쓰겠는가?</p>
<hr>
<blockquote>
<h2 id="2-non-blocking-io-모델">2. Non-Blocking I/O 모델</h2>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/fde5a225-aa6e-47e7-a650-6bd1196c91ba/image.png" alt=""></p>
<blockquote>
<p><strong>위와 같은 Blocking 방식의 비효율성을 극복하고자 도입된 방식이다. I/O 작업이 진행되는 동안 유저 프로세스의 작업을 중단시키지 않는 방식이다.</strong></p>
</blockquote>
<p>말 그대로 Blocking이 되지 않기 때문에 유저가 커널에게 작업을 요청하여도 데이터가 입력이 되었든 안되었든 간에 결과 메세지(EWOULDBLOCK)를 반환한다.
이러한 경우, *<em>I/O의 진행시간과 관계가 없기 때문에 애플리케이션은 중지 없이도 I/O 작업을 진행할 수 있다. 하지만 반복적으로 시스템 호출이 발생되기 때문에 불필요한 경우에도 자원이 쓰이므로 낭비라고 볼 수 있겠다. *</em>
그러니까 결론적으론 궁금하지 않아도 옆에서 자꾸 알려주는 앵무새 같은 친구가 되는 것이다.</p>
<p>역시나 Non-Blocking의 문제를 해결하기 위해 사람들은 또다른 대안을 내놓았고 I/O 이벤트 통지 모델이 도입되었다. 이벤트란 수신 버퍼나 출력 버퍼에 데이터를 처리하는 동작을 의미한다.</p>
<hr>
<blockquote>
<h2 id="3-io-이벤트-통지-모델">3. I/O 이벤트 통지 모델</h2>
<p>개발에서 흔히 말하는 &#39;이벤트&#39;의 의미는 수신 버퍼나 출력 버퍼의 이벤트를 통지한다는 의미다.
<strong>수신 버퍼의 이벤트는 말 그대로 입력 버퍼에 데이터가 수신되었다는 것을 알려주는 것이고,
반대로 출력 버퍼의 이벤트는 출력 버퍼가 비었으니 데이터 전송이 가능하다는 상황을 알려주는 것을 의미한다.</strong> </p>
</blockquote>
<p>이런 이벤트 통지 모델을 이용하게 되면 다중 I/O 모델을 효과적으로 처리할 수 있다. 
계속해서 응답이 왔는지 물어보는 것보단 입력 버퍼에서 &#39;메세지가 도착하였습니다.&#39;라고 알림이 와 확인하는 것이 좀 더 효율적이지 않은가?</p>
<p>I/O 이벤트 통지 방식에 따라서 또 동기/비동기 모델로 분류할 수 있다.</p>
<blockquote>
<p> 유저 프로세스 ----&gt; 커널  [I/O 작업 요청]
 커널 ----&gt; 유저 프로세스  [I/O 작업 상황(결과) 반환]</p>
</blockquote>
<p>여기서 우리가 주의깊게 살펴봐야 하는 부분이 [I/O 작업 상황(결과) 반환]이다.
I/O 작업 상황(결과) 반환 방식에 따라 동기, 비동기 방식으로 분류된다.</p>
<hr>
<blockquote>
<h2 id="4-synchronous동기-방식의-모델">4. Synchronous(동기) 방식의 모델</h2>
</blockquote>
<p>I/O 작업이 진행되는 동안 유저 프로세스는 결과를 기다렸다가 이벤트(결과)를 직접 처리하는 방식이다. Blocking은 아닌 것이 유저 프로세스가 작업을 수행하지 못하는 것은 아니기 때문이다. 
여기서 중요한 것은 기다린다는 것이다. 유저 프로세스는 주체적으로 진행하며, 커널은 유저 프로세스의 요청에 의해 수동적으로 응답한다.</p>
<blockquote>
<h2 id="5-asynchronous비동기-방식의-모델">5. Asynchronous(비동기) 방식의 모델</h2>
</blockquote>
<p>I/O 작업이 진행되는 동안 유저 프로세스는 관심이 없다. 
그저 자신의 일을 하다가 이벤트 핸들러에 의해 알림이 오면 처리하는 방식이다. </p>
<p>유저 프로세스는 요청 후에도 I/O 동기화를 신경 쓸 필요가 없고,
이벤트 핸들러(또는 Callback함수)에 의해 운영체제에서 처리 결과를 통지받는 방식이다.</p>
<p>Sync 방식과 반대로 커널이 주체적으로 담당하여 진행하고, 유저 프로세스는 수동적인 입장에서 통지가 들어오면 그때 I/O 작업을 진행한다. (마치 개발하고 있는 개발자에게 Slack 메세지가 오면 그때서야 무슨 이슈인지 확인하는 것과 비슷하다.)</p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://junshock5.tistory.com/148">https://junshock5.tistory.com/148</a>
<a href="https://ju3un.github.io/network-basic-1/">https://ju3un.github.io/network-basic-1/</a>
<a href="https://ju3un.github.io/network-basic-2/">https://ju3un.github.io/network-basic-2/</a>
<a href="https://sjh836.tistory.com/109">https://sjh836.tistory.com/109</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[디자인 패턴] 싱글톤 패턴(Singleton Pattern)]]></title>
            <link>https://velog.io/@dyunge_100/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern</link>
            <guid>https://velog.io/@dyunge_100/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4-%EC%8B%B1%EA%B8%80%ED%86%A4-%ED%8C%A8%ED%84%B4Singleton-Pattern</guid>
            <pubDate>Wed, 11 May 2022 01:24:08 GMT</pubDate>
            <description><![CDATA[<h2 id="1-싱글톤-패턴singleton-pattern이란">1. 싱글톤 패턴(Singleton Pattern)이란?</h2>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/1985a332-28ad-45a1-98f9-131ea3730c81/image.png" alt=""></p>
<p><strong>애플리케이션이 시작될 때 어떤 클래스가 최초 한 번만 메모리를 할당하고, 그 메모리에 인스턴스를 만들어 사용하는, 생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나인 디자인 패턴이다.</strong> 예를 든다면 레지스트리 같은 설정 파일의 경우 객체가 여러 개로 생성되면 설정 값이 바뀔 위험이 있다.</p>
<p>아래는 코드 예시이다.</p>
<pre><code class="language-java">public class SignletonPatternEx {
    // Instance
    public static SignletonPatternEx instance = new SignletonPatternEx();

    // private Constructor
    private SignletonPatternEx() {}

    // get method
    public static SignletonPatternEx getInstance() {
        return instance;
    }
}</code></pre>
<br>

<h3 id="12-싱글톤-패턴의-장점">1.2 싱글톤 패턴의 장점</h3>
<ul>
<li><p>싱글톤 패턴은 한 번의 생성으로 객체를 계속해서 <strong>재사용이 가능</strong>하기 때문에 메모리 낭비를 방지할 수 있다.</p>
</li>
<li><p>싱글톤으로 생성된 객체는 <strong>한 번의 생성으로 전역성을 띄기에</strong> 다른 객체와 데이터를 공유가 용이하다. 따라서 DBCP(Database Connection Pool)처럼 공통된 객체를 여러 개 생성해야 하는 경우에 많이 사용된다.(Thread Pool, Cache, 사용자 설정, 로그 기록 등)</p>
</li>
<li><p>인스턴스가 절대적으로 하나만 존재하는 것을 보증하고 싶을 경우 사용한다.</p>
</li>
<li><p>한 번 생성 이후 두 번째 사용 시부터는 메모리에 할당하는 과정이 없어 인스턴스 로딩 시간이 줄어 성능이 좋아진다.</p>
</li>
</ul>
<br>

<h3 id="13-싱글톤-패턴의-단점">1.3 싱글톤 패턴의 단점</h3>
<ul>
<li><p>싱글톤 인스턴스가 너무 많은 일을 하거나 많은 데이터를 공유시킬 경우, 다른 클래스의 인스턴스와의 결합도가 높아져 <strong>개방-폐쇄의 원칙(OCP)를 위반</strong>하게 될 가능성이 높다. 
이는 객체 지향 설계 원칙에 어긋나는 일이며 수정이 어려워지고, 유지보수의 비용이 높아질 수 있다.</p>
</li>
<li><p>멀티 쓰레드 환경에서 동기화 처리를 안하게 되면 인스턴스가 2개가 생성되는 문제가 발생할 수 있으며, 동기화 처리를 하더라도 성능 저하의 문제가 발생할 수 있다.</p>
</li>
</ul>
<hr>
<h2 id="2-다양한-싱글톤-구현">2. 다양한 싱글톤 구현</h2>
<p>싱글톤을 구현하는 방법은 몇 가지가 있는데 아래와 같이 구현할 수 있다.</p>
<h3 id="static-block">Static block</h3>
<pre><code class="language-java">public class SingletonPatternEx {
    // Instance
    private static SingletonPatternEx instance;

    // private Constructor
    private SingletonPatternEx() {}

    static {
        try { instance = new SingletonPatternEx(); } 
        catch(Exception e) { throw new RuntimeException(&quot;Create instance fail.&quot;
        + &quot;error msg=&quot; + e.getMessage()); }
    }

    public static SingletonPatternEx getInstance() {
        return instance;
    }
}</code></pre>
<p>static을 이용하면 클래스가 로드될 때 한 번만 실행되고 Method Area에 메모리 할당을 받게 된다. 하지만 인스턴스가 사용되는 시점이 아닌 클래스 로딩 시점에 실행이 되므로 많이 사용하게 되면 메모리 낭비가 될 수 있다. </p>
<h3 id="lazy-init">Lazy init</h3>
<p>static 방법에서 개선하여 클래스 로딩 시점이 아닌 인스턴스가 생성하고자 할 때 생성되는 싱글톤 패턴 구현 방법이다.</p>
<pre><code class="language-java">public class LazyInitialization {
    // Instance
    public static LazyInitialization instance;

    // private Constructor
    private LazyInitialization() {}

    // get method
    public static LazyInitialization getInstance() {
        if (instance == null) { instance = new LazyInitialization(); }
        return instance;
    }
}</code></pre>
<p>private static으로 인스턴스 변수를 만들고, private 생성자로 외부에서 생성하는 것을 막았다.</p>
<p>하지만 위의 형태로 구성할 경우 멀티 쓰레드 환경에 취약하다. 
만약 instance가 생성되지 않은 상태이고 Thread1이 getInstance() 메서드를 호출하면 instance 변수는 null인 상태일 것이다. 하지만 Thread2가 아직 instance의 인스턴스 생성 전에 if문을 실행하여 instance 변수가 null인지 확인하게 되면 이 또한 인스턴스를 생성하는 생성자를 호출하는 코드를 실행하게 된다. 
결과적으로 다중 쓰레드가 여러 인스턴스를 생성하게 된다.</p>
<h3 id="thread-safe-lazy-initialization">Thread safe Lazy Initialization</h3>
<pre><code class="language-java">public class ThreadSafeLazy {

    public static ThreadSafeLazy instance;

    private ThreadSafeLazy() {}

    public static synchronized ThreadSafeLazy getInstance() {
        if (instance == null) { instance = new ThreadSafeLazy(); }
        return instance;
    }
}</code></pre>
<p>이번에는 synchronized 키워드를 사용하여 thread-safe하게 만들었다.
하지만 synchronized 특성상 비교적 큰 성능 저하가 발생하므로 권장하지 않는 방법이다.</p>
<h3 id="thread-safe-lazy-iniatialization--double-checked-locking">Thread safe Lazy Iniatialization + Double-checked locking</h3>
<pre><code class="language-java">public class ThreadSafeLazyDouble {

    public static ThreadSafeLazyDouble instance;

    private ThreadSafeLazyDouble() {}

    public static ThreadSafeLazyDouble getInstance() {
        if (instance == null) {
            synchronized (ThreadSafeLazyDoublce.class) {
                if ( instance == null) instance = new ThreadSafeLazyDouble(); }
        }
        return instance;
    }
}</code></pre>
<p>이번에는 getInstance() 메서드에 synchronized를 사용하는 것이 아니라 첫 번째 if문으로 인스턴스의 존재여부를 체크한 다음 동기화 시켜 인스턴스를 생성하더라도 thread-safe하면서 처음 생성 이후 synchronized 블럭을 타지 않게 하여 성능 저하를 완화하는 방법이다.</p>
<h3 id="initialization-on-demand-holder-idiomholder에-의한-초기화">Initialization on demand holder idiom(holder에 의한 초기화)</h3>
<pre><code class="language-java">public class Something {
    private Something() {
    }

    private static class LazyHolder {
        public static final Something INSTANCE = new Something();
    }

    public static Something getInstance() {
        return LazyHolder.INSTANCE;
    }
}</code></pre>
<p>클래스 안에 클래스(Holder)를 두어 JVM의 Class loader 매커니즘과 class가 로드되는 시점을 이용한 방법이다. <strong>가장 많이 쓰이고 일반적인 Singleton 패턴 구현</strong>이며, JVM의 클래스 초기화 과정에서 보장되는 원자적 특성을 이용한 방법이다.</p>
<p>cf) Java와 Spring에서의 싱글톤 차이점은 생명주기가 다르다. 또한 Java에서 공유 범위는 Class Loader 기준이지만, Spring에서는 ApplicationContext(즉, 서블릿)가 기준이 된다.</p>
<p><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://devmoony.tistory.com/43">https://devmoony.tistory.com/43</a></p>
<p><a href="https://gmlwjd9405.github.io/2018/07/06/singleton-pattern.html">https://gmlwjd9405.github.io/2018/07/06/singleton-pattern.html</a></p>
<p><a href="https://jeong-pro.tistory.com/86">https://jeong-pro.tistory.com/86</a></p>
<p><a href="https://elfinlas.github.io/2019/09/23/java-singleton/">https://elfinlas.github.io/2019/09/23/java-singleton/</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] @Controller와 @RestController의 차이]]></title>
            <link>https://velog.io/@dyunge_100/Spring-Controller%EC%99%80-RestController%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@dyunge_100/Spring-Controller%EC%99%80-RestController%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Fri, 22 Apr 2022 05:13:59 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="0-requestbody-responsebody-어노테이션">0. @RequestBody, @ResponseBody 어노테이션</h2>
</blockquote>
<p>보통 웹에서 화면 전환이 없이 이루어지는 동작들은 대부분 비동기 통신으로 이루어진다. 비동기 통신을 하기 위해선 클라이언트가 서버로 요청 메시지의 본문(Body)에 데이터를 담아서 보내야 하고, 서버도 클라이언트에 응답하기 위해 응답 메시지의 본문(Body)에 데이터를 담아서 보내야 한다. 이 때의 본문(body)를 각각 Request Body와 Response Body로 부르는데, 이러한 Body에 담기는 데이터 형식은 <strong>JSON(JavaScript Object Notation)</strong>이다.</p>
<p><code>@RequestBody</code> 어노테이션은 이러한 비동기 통신에서 쓰이는 Body 안의 데이터(JSON객체)를 자바 객체(VO)로 변환해주는 어노테이션이다. 마찬가지로 <code>@ResponseBody</code> 어노테이션은 보내려는 자바 객체(VO)를 데이터(JSON객체)로 바꿔 Body 안에 넣어주는 어노테이션이라고 보면 무방하다.</p>
<blockquote>
<h2 id="1-controller와-restcontroller-어노테이션">1. @Controller와 @RestController 어노테이션</h2>
</blockquote>
<p><code>@Controller</code>와 <code>@RestController</code> 둘 다 Spring에서 Controller를 지정해주기 위한 어노테이션이다. 전통적인 Spring MVC의 Controller인 <code>@Controller</code>와 RESTful 웹 서비스의 Controller인 <code>@RestController</code>의 주요한 차이점은 Response Body가 생성되는 방식이다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/681912dc-5334-4bdc-8ecd-d6b0de116173/image.png" alt=""></p>
<h3 id="11-controller">1.1 @Controller</h3>
<h3 id="controller로-view를-반환할-경우">[Controller로 View를 반환할 경우]</h3>
<p>Spring MVC의 Controller인 <strong><code>@Controller</code>는 주로 View를 반환</strong>하기 위해 사용한다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/2b2ba59f-7d93-4d29-8236-43d2336480d2/image.png" alt=""></p>
<p>1) Client에서 보낸 요청은 DispatcherServlet을 거쳐 HandlerMapping을 통해 Controller를 찾고 요청을 수행하게 된다. </p>
<p>2) Controller는 받은 요청을 처리하고 난 뒤 ViewName을 반환한다.</p>
<p>3) DispatcherServlet은 ViewResolver를 통해 ViewName에 해당하는 View를 찾아 사용자에게 반환한다.</p>
<h3 id="controller로-data를-반환할-경우">[Controller로 Data를 반환할 경우]</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/befd3d4a-ce5e-448d-a48c-8f56e10c4db8/image.png" alt=""></p>
<p>하지만 View뿐만 아니라 Data(또는 객체)를 반환해야 하는 경우도 있다. 그럴 때는 데이터를 반환하기 위해 ResponseEntity(HttpStatus + HttpHeaders + HttpBody 형태의 데이터, 한 마디로 Http 응답 메시지)의 Body(Response Body)를 사용해야 하는데, 이 때 <code>@ResponseBody</code> 어노테이션을 사용하면 된다. 이를 통해 Controller도 View 뿐만이 아닌 JSON 형태의 데이터도 반환할 수 있다.</p>
<blockquote>
<h4 id="참고">참고)</h4>
<p><code>@Controller</code>를 통해 객체를 반환할 때, 일반적인 경우엔 <code>ResponseEntity</code>로 감싸서 반환한다. 
그리고 객체를 반환할 때는 View를 반환할 때와 마찬가지로 <code>ViewResolver</code> 대신 <code>HttpMessageConverter</code>가 동작한다. <code>HttpMessageConverter</code>에는 여러 <code>Converter</code>가 등록되어 있으며, 반환해야 하는 데이터의 종류에 따라 <code>Converter</code>도 그에 맞게 달라진다.</p>
<p>예를 들어, 단순 문자열인 경우에는 <code>StringHttpMessageConverter</code>가 사용되고, <code>JSON</code> 객체의 경우에는 <code>MappingJackson2HttpMessageConverter</code>가 사용된다. Spring은 클라이언트의 <code>HTTP Accept Header</code>와 서버의 <code>Controller</code> 반환 타입 정보를 조합해 적합한 <code>HttpMessageConverter</code>를 선택하여 처리한다.</p>
</blockquote>
<h3 id="controller와-responsebody-예제-코드">[@Controller와 @ResponseBody 예제 코드]</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/3a67df2d-a7ff-473d-b651-eaa39104e3d5/image.png" alt=""></p>
<p><code>@Controller</code>는 보통 View를 반환하기는 하지만 위와 같이 <code>@ResponseBody</code> 어노테이션을 활용하면 객체를 반환할 수 있다. <code>@RequestParam</code>의 경우는 Request Header 안의 파라미터를 Mapping해주는 어노테이션이다.</p>
<h3 id="12-restcontroller">1.2 @RestController</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/3c4fa240-4614-4a36-8980-c7e4450d44fe/image.png" alt=""></p>
<p><code>@RestController</code> 어노테이션은 말 그대로 <code>@Controller</code>와 <code>@ResponseBody</code>가 합쳐진 어노테이션이라고 생각하면 된다. <code>@Controller</code>와 다르게 반환하려는 주류는 JSON 형태의 객체 데이터다. REST API를 개발할 때 주로 사용하며 마찬가지로 ResponseEntity로 감싸서 주로 반환한다.</p>
<h3 id="restcontroller-예제-코드">[@RestController 예제 코드]</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/bafe38bf-aee8-4d87-9c4b-f26cb89eb6b0/image.png" alt=""></p>
<p>위의 예제 코드 중 첫 번째 메서드는 User 객체를 그대로 반환하고 있다. 이 때의 문제는 클라이언트가 예상하는 HttpStatus를 설정해줄 수가 없다는 것이다. 한마디로 에러가 났을 때 상태 코드를 보여주거나 할 수 없다는 말이다. 따라서 REST API를 개발한다면 객체를 상황에 맞게 ResponseEntity로 감싸서 반환해주는 것이 옳다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/72e7e783-fb5e-4eb7-9464-70206ee1c015/image.png" alt=""></p>
<p>위와 같이 지네릭스를 이용하여 알맞은 객체로 설정해주고 그 객체가 아닐 경우 에러가 나도록 할 수 있다. 따라서 REST API를 사용한다면 <code>@RestController</code>를 사용하는 것이 바람직해 보인다.</p>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://dev-coco.tistory.com/84">https://dev-coco.tistory.com/84</a>,
<a href="https://joomn11.tistory.com/53">https://joomn11.tistory.com/53</a>,
<a href="https://mangkyu.tistory.com/49">https://mangkyu.tistory.com/49</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[HTTP] GET, POST, PUT, PATCH 차이]]></title>
            <link>https://velog.io/@dyunge_100/Spring-Thread-Pool</link>
            <guid>https://velog.io/@dyunge_100/Spring-Thread-Pool</guid>
            <pubDate>Fri, 22 Apr 2022 04:17:07 GMT</pubDate>
            <description><![CDATA[<h2 id="1-get과-post의-차이">1. GET과 POST의 차이</h2>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/9a5e8462-03c5-4506-8bac-b1cb05ac608c/image.png" alt=""></p>
<p><code>GET</code>은 클라이언트가 서버로부터 어떠한 리소스를 요청하고 단순히 가져오는 것으로 이해하였었고,
<code>POST</code>는 말 그대로 리소스를 처리하거나 게시하는 메서드라고 이해를 했었다. 그 밖에도 <code>PUT</code> 메서드나 <code>PATCH</code> 메서드에 대해서도 정확한 차이를 짚고 넘어가는 것이 좋을 것 같아 정리하게 되었다.</p>
<h3 id="11-get-메서드">1.1 GET 메서드</h3>
<p><strong>HTTP <code>GET</code> 메서드는 서버로부터 특정한 리소스를 가져오도록 요청해주는 메서드이다. 오로지 데이터를 가져올 때만 사용해야 하는 것이다. (데이터의 변형이 없다.)</strong></p>
<p><code>GET</code> 요청을 할 때는 Body 부분이 비어있고 Header에는 Body의 컨텐츠 타입을 명시하는 <code>Content-Type</code> Header 필드도 비워 놓는다. 아래와 같이 URL 뒤에 쿼리 스트링(Query String, <code>Key</code>와 <code>Value</code>가 붙어 있는 <code>String</code>)을 붙이고, HTTP 패킷의 Header에 <code>Key</code>와 <code>Value</code>를 포함시켜 서버에 데이터를 요청하게 된다.</p>
<p><code>http://localhost:3000/login?id=admin&amp;pw=1234</code></p>
<p>URL의 &quot;?&quot; 뒷부분은 쿼리 스트링으로 데이터를 표현하는 것이기 때문에 ID, Password와 같은 민감한 정보들에 GET방식을 사용하면 보안에 취약해진다. 따라서 주로 게시물이나 목록 조회와 같이 <strong>간단한 데이터 요청</strong>을 할 때 적합하다. </p>
<p>브라우저 히스토리에 기록이 남으며, 캐싱이 가능하다. 그리고 <code>POST</code> 방식보다 상대적으로 전송 속도가 더 빠르다.</p>
<h3 id="12-post-메서드">1.2 POST 메서드</h3>
<p><strong>HTTP <code>POST</code> 메서드는 서버로 데이터를 전송하여 리소스를 추가하거나 생성하기 위해 사용하는 메서드이다. <code>GET</code> 메서드와 반대로 요청 Header의 <code>Content-Type</code>에 컨텐츠 타입을 명시하며, HTTP 패킷의 Body에는 데이터를 담아 서버로 전송한다. (보통 웹에서는 JSON 형식으로)</strong></p>
<p><code>http://localhost:3000/login</code></p>
<p><code>POST</code> 메서드는 <code>GET</code> 메서드와 다르게 데이터들이 URL에 표시되지 않아 상대적으로 보안성이 높지만, 결국엔 개발자 도구와 같은 툴로 요청 메시지 body안의 데이터를 확인할 수 있기 때문에 꼭 암호화를 해줘야 한다. (따라서 비밀번호와 같은 경우는 Bcrypt와 같은 암호화 알고리즘을 통해 암호화를 진행해준다.) 브라우저 히스토리에도 기록이 남지 않는 특징이 있다.</p>
<p><code>POST</code> 메서드는 가벼운 <code>GET</code> 메서드와 다르게 보내는 데이터의 양에 제한이 없어 대용량 데이터를 보내기 적합하지만 요청을 받는 시간이 존재한다. 또 URL에 데이터가 노출되지 않으므로 캐싱이 불가능하다.</p>
<h3 id="13-get과-post의-차이점을-간략히-나타낸-표">1.3 GET과 POST의 차이점을 간략히 나타낸 표</h3>
<table>
<thead>
<tr>
<th>HTTP Method</th>
<th>GET 방식</th>
<th>POST 방식</th>
</tr>
</thead>
<tbody><tr>
<td>사용하는 방식</td>
<td>리소스 요청(불러오기)</td>
<td>리소스 추가 또는 생성</td>
</tr>
<tr>
<td>URL 예시</td>
<td><a href="http://localhost:3000/login?id=admin&amp;pw=1234">http://localhost:3000/login?id=admin&amp;pw=1234</a></td>
<td><a href="http://localhost:3000/login">http://localhost:3000/login</a></td>
</tr>
<tr>
<td>데이터가 담기는 곳</td>
<td>HTTP 패킷 Header</td>
<td>HTTP 패킷 Body</td>
</tr>
<tr>
<td>리소스 전달 방식</td>
<td>쿼리스트링</td>
<td>HTTP Body</td>
</tr>
<tr>
<td>HTTP 응답 코드</td>
<td>200</td>
<td>201</td>
</tr>
<tr>
<td>URL에 데이터 노출 여부</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>캐싱 가능 여부</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>브라우저 기록</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>북마크 추가</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>데이터 길이 제한</td>
<td>O</td>
<td>X</td>
</tr>
<tr>
<td>멱등성(idempotent)</td>
<td>O</td>
<td>X</td>
</tr>
</tbody></table>
<p>참고) 멱등성 : 연산을 여러 번 하였다더라도 결과가 달라지지 않는 성질. <code>POST</code> 메서드는 수행할 때 결과가 달라지므로 멱등성이 지켜지지 않는다.</p>
<h2 id="2-post와-put-patch의-차이점">2. POST와 PUT, PATCH의 차이점</h2>
<h3 id="21-put-메서드">2.1 PUT 메서드</h3>
<p>HTTP <code>PUT</code> 메서드는 요청 페이로드(<a href="https://ko.wikipedia.org/wiki/%ED%8E%98%EC%9D%B4%EB%A1%9C%EB%93%9C_(%EC%BB%B4%ED%93%A8%ED%8C%85)">Payload</a>, 사용에 있어서 전송되는 데이터)를 사용해 새로운 리소스를 생성하거나, 대상 리소스를 나타내는 데이터를 대체한다.(주로 Update기능에 사용)</p>
<p><strong><code>PUT</code>과 <code>POST</code>의 차이는 멱등성으로, <code>PUT</code> 메서드는 멱등성을 가진다.</strong> 즉, <code>PUT</code>은 같은 객체를 여러 번 보내도 한 번만 생성되거나 계속해서 같은 값을 보내줄 것이다. (<code>POST</code> 메서드의 경우는 새로운 객체가 보낼 때마다 생성된다.)</p>
<p>또한 생성한 URL 개체의 이름을 명시적으로 지정한 경우에는 <code>PUT</code>을 사용하고, 서버가 결정하도록 한다면 <code>POST</code>를 사용하는 게 더 낫다.</p>
<h3 id="22-patch-메서드">2.2 PATCH 메서드</h3>
<p>HTTP <code>PUT</code> 메서드는 문서 전체의 완전한 교체만을 허용하지만, <code>PATCH</code> 메서드는 <code>PUT</code> 메서드와 달리 부분적인 교체를 할 때 사용하는 메서드이다. 또한 <code>PUT</code>은 새로운 자원을 생성하지만, PATCH는 새로운 자원을 생성하진 않는다.</p>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://cocoon1787.tistory.com/526">https://cocoon1787.tistory.com/526</a>,
<a href="https://velog.io/@songyouhyun/Get%EA%B3%BC-Post%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%A5%BC-%EC%95%84%EC%8B%9C%EB%82%98%EC%9A%94">https://velog.io/@songyouhyun/Get%EA%B3%BC-Post%EC%9D%98-%EC%B0%A8%EC%9D%B4%EB%A5%BC-%EC%95%84%EC%8B%9C%EB%82%98%EC%9A%94</a>,
<a href="https://noahlogs.tistory.com/35">https://noahlogs.tistory.com/35</a>,
<a href="https://guseowhtjs.tistory.com/entry/HTTP%EC%97%90%EC%84%9C-POST%EC%99%80-PUT%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C">https://guseowhtjs.tistory.com/entry/HTTP%EC%97%90%EC%84%9C-POST%EC%99%80-PUT%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90%EC%9D%80-%EB%AC%B4%EC%97%87%EC%9E%85%EB%8B%88%EA%B9%8C</a>,
<a href="https://velog.io/@vagabondms/%EA%B8%B0%EC%88%A0-%EC%8A%A4%ED%84%B0%EB%94%94-PUT%EA%B3%BC-PATCH-%EC%B0%A8%EC%9D%B4">https://velog.io/@vagabondms/%EA%B8%B0%EC%88%A0-%EC%8A%A4%ED%84%B0%EB%94%94-PUT%EA%B3%BC-PATCH-%EC%B0%A8%EC%9D%B4</a>,
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/PATCH">https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/PATCH</a>,
<a href="https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/PUT">https://developer.mozilla.org/ko/docs/Web/HTTP/Methods/PUT</a></p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Bcrypt를 이용한 비밀번호 암호화]]></title>
            <link>https://velog.io/@dyunge_100/Spring-Bcrypt%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%95%94%ED%98%B8%ED%99%94</link>
            <guid>https://velog.io/@dyunge_100/Spring-Bcrypt%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%B9%84%EB%B0%80%EB%B2%88%ED%98%B8-%EC%95%94%ED%98%B8%ED%99%94</guid>
            <pubDate>Fri, 22 Apr 2022 01:08:40 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="0-암호화-종류와-bcrypt">0. 암호화 종류와 Bcrypt</h2>
</blockquote>
<h3 id="01-암호화-종류">0.1 암호화 종류</h3>
<h4 id="1-sha-2secure-hash-algorithm2">1) SHA-2(Secure Hash Algorithm2)</h4>
<ul>
<li><p>미국 국가안보국(NSA)에서 설계한 암호화 해시 함수들의 집합이다.</p>
</li>
<li><p>digest size는 224, 256, 512 bit로 해시함수로 구성되어있다.</p>
</li>
<li><p>GPU를 이용한 연산 속도가 매우 빠르기 때문에 password 암호화에는 권장되지 않는다.</p>
<ul>
<li><p>GPU 연산 속도가 빠를수록 공격자의 하드웨어를 통한 오프라인 brute-force에 더 취약하다.</p>
</li>
<li><p>빠른 해시를 사용하여 암호화를 진행할 시 공격자는 오프라인 공격으로 초당 수 십억 개의 해시를 계산할 수 있다.</p>
</li>
</ul>
</li>
</ul>
<h4 id="2-pbkdf2">2) PBKDF2</h4>
<p><code>DK = PBKDF2(PRF, Password, Salt, c, dkLen)</code></p>
<pre><code>PRF : 출력 길이가 hLen인 두 파라미터(parameter)의 의사난수 함수(pseudorandom function)

Password : 파생 키(Derived Key)가 생성되는 마스터 암호

Salt : cryptographic salt로 알려진, 비트들의 시퀀스(a sequence of bits)

c : 바라는 반복 횟수

dkLen : 바라는 파생 키의 비트 길이

DK :  생성된 파생 키</code></pre><ul>
<li><p>해시 함수의 컨테이너 역할을 한다.</p>
</li>
<li><p>검증된 해시 함수만을 사용한다.</p>
</li>
<li><p>해시 함수와 salt를 적용 후 해시 함수의 반복횟수를 지정하여 암호화가 가능하다.(식 참고)</p>
</li>
<li><p>가장 많이 사용되는 함수이며, ISO 표준에 적합하다. NIST에서도 승인된 알고리즘이다.
 <a href="https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-132.pdf">NIST Special Publication 800-132</a></p>
</li>
</ul>
<h4 id="3-bcrypt">3) Bcrypt</h4>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/99c611ef-8a6e-4ceb-b212-7c3b43ffa878/image.png" alt=""></p>
<p><code>BCrypt.hashpw(password, BCrypt.gensalt())</code></p>
<ul>
<li><p><strong><a href="https://ko.wikipedia.org/wiki/%EB%B8%94%EB%A1%9C%ED%94%BC%EC%8B%9C">블로피시 암호</a>에 기반을 둔 암호화 해시 함수이다. <a href="https://ko.wikipedia.org/wiki/%EB%A0%88%EC%9D%B8%EB%B3%B4_%ED%85%8C%EC%9D%B4%EB%B8%94">Rainbow Table</a> 공격 방지를 위해 salt를 통합한 적응형 함수 중 하나이다. 현재까지 사용 중인 가장 강력한 해시 알고리즘 중 하나이다.</strong></p>
</li>
<li><p>반복 횟수를 늘려 연산 속도를 늦출 수 있으므로 연산 능력의 증가에도 brute-force 검색 공격에 대한 저항을 유지하게 된다.</p>
</li>
<li><p>.NET 및 Java를 포함한 많은 플랫폼, 언어에서 사용할 수 있다.</p>
</li>
</ul>
<h4 id="4-scrypt">4) Scrypt</h4>
<ul>
<li><p>2009년에 publish된 key derivation function이다.</p>
</li>
<li><p>오프라인 brute-force 공격에 대해 수 십억 번의 작업을 수행할 정도로 강력하지만, 많은 양의 메모리와 CPU를 사용한다.</p>
</li>
<li><p>OpenSSL 1.1이상을 제공하는 시스템에서만 작동한다.</p>
</li>
<li><p>여러 언어의 라이브러리로 제공된다.</p>
</li>
<li><p>다른 암호 기반 KDF에 비해 많은 양의 메모리를 사용하도록 설계되었다.</p>
</li>
<li><p>하드웨어를 구현하는 데 크기와 비용이 훨씬 비싸기 때문에, 주어진 자원에서 공격자가 사용할 수 있는 병렬 처리의 양이 한정적이다. </p>
</li>
</ul>
<br>

<blockquote>
<h3 id="bcrypt가-비밀-번호-암호화에--추천되어지는-이유">[Bcrypt가 비밀 번호 암호화에  추천되어지는 이유??]</h3>
<h4 id="bcrypt-설계자들이-기사에서-언급한-내용">Bcrypt 설계자들이 기사에서 언급한 내용</h4>
<p>That means one should make any password function as efficient as possible for the setting in which it will operate. The designers of crypt failed to do this. They based crypt on DES, a particularly inefficient algorithm to implement in software because of many bit transpositions. They discounted hardware attacks, in part because crypt cannot be calculated with stock DES hardware. Unfortunately, Biham later discovered a software technique known as bitslicing that eliminates the cost of bit transpositions in computing many simultaneous DES encryptions. While bitslicing won&#39;t help anyone log in faster, it offers a staggering speedup to brute force password searches.</p>
</blockquote>
<p>SHA 종류가 무조건 나쁜 것은 아니지만, SHA의 경우 일반적으로 GPU 연산에 유리한 32bit 논리 및 산술 연산만 사용하기 때문에 공격자가 빠른 연산으로 공격하기 유리하다.</p>
<p>이상적으로 봤을 때는 공격자가 유리한 게임이지만, 자원의 양은 한정적이므로 공격자의 속도를 늦출수록 암호화 해독을 하기 어렵고 오래 걸리게 된다. 그러므로 어떤 암호화 함수를 쓰던지 강력하겠지만 충분한 시도 횟수와 work-factor를 고려하였을 때, 방어자는 좀 더 느리게 설계된 암호화 방식에 의존하는 것이 더 낫다.</p>
<p><strong>또한 비용이 많이 드는 Scrypt보단 구현이 쉽고 비교적 강력한 Bcrypt를 사용하기 편하다. 단, ISO-27001 보안 규정을 준수해야 하는 상황이라면 PBKDF2를 사용하는 것을 권장한다.</strong></p>
<blockquote>
<h3 id="참고-salt에-대하여">참고) Salt에 대하여</h3>
<p>그냥 plainText로 저장된 비밀 번호라면 해킹하기 쉽겠지만 해시 함수를 사용하면 이를 방지할 수 있다. 하지만 해시 함수는 동일한 입력값에 대해 동일한 해시를 출력하므로 이마저도 Rainbow Table을 가지고 있다면 뚫리게 된다. </p>
<p>그리하여 나오게 된 개념이 <strong>Salting</strong>이다. 음식에 간을 치듯이, <strong>해시 함수에 넣기 전에 난수를 추가하므로 인해 복잡도를 올리고 보안성을 높인다.</strong> DB에는 [Salt]값과 [비밀 번호 + Salt값]의 해시가 함께 저장되며, 유저는 이후 로그인 할 때마다 실제 비밀 번호를 입력하면, 서버는 해시값을 DB와 비교하여 입장 여부를 결정한다.</p>
<p>하지만 갈수록 컴퓨팅 자원은 저렴하지만 빨라지는 무어의 법칙에 의해, 이마저도 무력해질 수 있다. 따라서 기존 Salting한 해시 결과에 다시 동일한 Salt를 적용하는 과정을 적용시킬 수 있는데, 이렇게 반복할 때의 반복 횟수를 <strong>Salting Round</strong>라고 하며 DB에는 [Salt값]과 Salting Round만큼 반복하여 나온 [최종 해시값]을 저장한다. </p>
</blockquote>
<blockquote>
<h2 id="1-bcrypt-동작-원리와-결과-해시값-해석">1. Bcrypt 동작 원리와 결과 해시값 해석</h2>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/acba370b-54fb-45d0-bdf0-84cbf33b3fe1/image.png" alt=""></p>
<h3 id="1-key-setup-phase">1. Key Setup Phase</h3>
<ul>
<li>cost는 원하는 연산량, 소요시간 등을 말한다. 그 외의 파라미터로는 salt, password가 있다.</li>
</ul>
<p>password를 가지고 key stretching을 하며 연산 속도를 늦춰준다.</p>
<h3 id="2-operation-phase">2. Operation Phase</h3>
<ul>
<li><p>PlainText와 CiphterText 사이로 encrypt/decrypt하는 단계이다.</p>
</li>
<li><p>1) OrpheanBeholderScryDoubt 는 192bit (=24byte)이며, 1단계의 결과이다.</p>
</li>
<li><p>2) 이 결과를 가지고 ekblowfish가 동작하는 ECB mode로 64번 암호화를 진행한다. </p>
</li>
<li><p>3) 암호화 루프 63번의 결과 + salt 128bit (=16byte) 등을 합친 것이 최종 결과다.</p>
</li>
</ul>
<h3 id="3-결과-해시값-해석">3. 결과 해시값 해석</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/7d9a8b3f-d394-49ed-9caf-d26781f2de03/image.png" alt=""></p>
<ul>
<li><p>$2b는 bcrypt의 버전 정보이다. </p>
</li>
<li><p>$10은 10round를 의미하며, cost 정보를 의미한다. 즉, 2^10번 돌린 것이다.</p>
</li>
<li><p>버전과 cost 정보를 제외한 나머지가 <code>Salt + CipherText</code> 인데 Base-64로 인코딩 된 것이다. 앞부분 22 문자를 Decode 해주면 16 바이트 Salt 가 된다. 나머지가 CipherText 이다.</p>
</li>
</ul>
</blockquote>
<blockquote>
<h2 id="2-spring에서-bcrypt-사용하기">2. Spring에서 Bcrypt 사용하기</h2>
</blockquote>
<p>Springboot 2.6.6 version, java 11version, 관리 도구는 maven을 사용하였다.
Springboot security를 사용하지 않고 pom.xml에 의존성을 추가하여 사용해보았다.</p>
<h3 id="--1-의존성-추가">- 1) 의존성 추가 <img src="https://velog.velcdn.com/images/dyunge_100/post/9132709e-8e4a-4310-9259-73aea099cdce/image.png" alt=""></h3>
<h3 id="--2-bcrypt를-사용하는-컴포넌트-만들기">- 2) Bcrypt를 사용하는 컴포넌트 만들기</h3>
<p><code>Salt</code>를 추가하여 <code>Bcrypt</code>방식으로 <code>encrypt</code>하는 메서드와 
로그인 시 입력한 기존의 패스워드와 해시된 패스워드를 비교해주는 <code>isMatch</code> 메서드를 작성한다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/74008efe-2f1d-44b6-9c8f-1abcfdeb8e07/image.png" alt=""></p>
<h3 id="--3-service를-구현할-때-가져온-dto를-통해-암호화-진행">- 3) Service를 구현할 때 가져온 DTO를 통해 암호화 진행 <img src="https://velog.velcdn.com/images/dyunge_100/post/17cd2839-ef48-400c-b16b-6a5a7270e980/image.png" alt=""></h3>
<p>작성한 컴포넌트를 가져와 password 암호화를 진행해준다.
DTO를 가져와 비밀번호를 암호화하고 setter를 통해 해시된 비밀번호로 바꿔준다.
Mybatis를 이용하여 SQL문과 Mapping한 Mapper(DAO)를 통해 DB에 저장하라고 명령한다.</p>
<h3 id="--4-db에-결과-저장-확인">- 4) DB에 결과 저장 확인 <img src="https://velog.velcdn.com/images/dyunge_100/post/2fb49fad-d61b-4a5a-b9cc-8cc80b96f583/image.png" alt=""></h3>
<p>다음과 같이 PostgreSQL DB에 저장된 것을 확인할 수 있다.   </p>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://velog.io/@kylexid/%EC%99%9C-bcrypt-%EC%95%94%ED%98%B8%ED%99%94-%EB%B0%A9%EC%8B%9D%EC%9D%B4-%EC%B6%94%EC%B2%9C%EB%90%98%EC%96%B4%EC%A7%88%EA%B9%8C">https://velog.io/@kylexid/%EC%99%9C-bcrypt-%EC%95%94%ED%98%B8%ED%99%94-%EB%B0%A9%EC%8B%9D%EC%9D%B4-%EC%B6%94%EC%B2%9C%EB%90%98%EC%96%B4%EC%A7%88%EA%B9%8C</a>,
<a href="https://jusths.tistory.com/158">https://jusths.tistory.com/158</a>,
<a href="https://codingdog.tistory.com/entry/bcrypt%EB%8A%94-salt%EA%B0%80-%EB%A7%A4%EB%B2%88-%EB%8B%AC%EB%9D%BC%EC%A7%80%EB%8A%94%EB%8D%B0-match%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%98-%EC%8B%9C%ED%82%AC%EA%B9%8C%EC%9A%94">https://codingdog.tistory.com/entry/bcrypt%EB%8A%94-salt%EA%B0%80-%EB%A7%A4%EB%B2%88-%EB%8B%AC%EB%9D%BC%EC%A7%80%EB%8A%94%EB%8D%B0-match%EB%A5%BC-%EC%96%B4%EB%96%BB%EA%B2%8C-%EC%9E%98-%EC%8B%9C%ED%82%AC%EA%B9%8C%EC%9A%94</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 요청 방식(@RequestMapping, @GetMapping, @PostMapping)]]></title>
            <link>https://velog.io/@dyunge_100/Spring-%EC%9A%94%EC%B2%AD-%EB%B0%A9%EC%8B%9DRequestMapping-GetMapping-PostMapping</link>
            <guid>https://velog.io/@dyunge_100/Spring-%EC%9A%94%EC%B2%AD-%EB%B0%A9%EC%8B%9DRequestMapping-GetMapping-PostMapping</guid>
            <pubDate>Tue, 19 Apr 2022 05:27:05 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="0-주요-어노테이션">0. 주요 어노테이션</h2>
</blockquote>
<table>
<thead>
<tr>
<th>이름</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>@Controller</td>
<td>해당 클래스가 Controller임을 나타내기 위한 어노테이션</td>
</tr>
<tr>
<td>@RequestMapping</td>
<td>요청에 대해 어떤 Controller, 어떤 메소드가 처리할지를 맵핑하기 위한 어노테이션</td>
</tr>
<tr>
<td>@RequestParam</td>
<td>Controller 메소드의 파라미터와 웹요청 파라미터와 맵핑하기 위한 어노테이션</td>
</tr>
<tr>
<td>@ModelAttribute</td>
<td>Controller 메소드의 파라미터나 리턴값을 Model 객체와 바인딩하기 위한 어노테이션</td>
</tr>
<tr>
<td>@SessionAttributes</td>
<td>Model 객체를 세션에 저장하고 사용하기 위한 어노테이션</td>
</tr>
<tr>
<td>@RequestPart</td>
<td>Multipart 요청의 경우, 웹요청 파라미터와 맵핑가능한 어노테이션(egov 3.0, Spring 3.1.x부터 추가)</td>
</tr>
<tr>
<td>@CommandMap</td>
<td>Controller메소드의 파라미터를 Map형태로 받을 때 웹요청 파라미터와 맵핑하기 위한 어노테이션(egov 3.0부터 추가)</td>
</tr>
<tr>
<td>@ControllerAdvice</td>
<td>Controller를 보조하는 어노테이션으로 Controller에서 쓰이는 공통기능들을 모듈화하여 전역으로 쓰기 위한 어노테이션(egov 3.0, Spring 3.2.X부터 추가)</td>
</tr>
</tbody></table>
<blockquote>
<h2 id="1-requestmapping이란">1. @RequestMapping이란?</h2>
</blockquote>
<p>특정 url로부터 요청을 받으면 어떤 Controller에서 처리할 지 알아야 한다. 
이 때, 특정 url을 요청을 수행할 Controller과 매핑하여 지정하는 어노테이션이 <code>@RequestMapping</code>이다.</p>
<blockquote>
<h2 id="2-requestmapping의-동작-방식">2. RequestMapping의 동작 방식</h2>
</blockquote>
<ol>
<li><p>SpringBoot 애플리케이션이 실행되면 애플리케이션에서 사용할 baen들을 담을 ApplicationContext를 생성하고 초기화한다.</p>
</li>
<li><p><code>@RequestMapping</code>이 붙은 메서드들이 handler에 등록되는 것은 ApplicationContext가 refresh되는 과정에서 일어난다. refresh과정에서 <code>Spring Application</code> 구동을 위해 많은 Baen들이 생성되고, 그 중 하나가 <code>RequestMappingHandlerMapping</code>이다. 이 Bean은 우리가 <code>@RequestMapping</code>으로 등록한 메서드들을 가지고 있다가 요청이 들어오면 Mapping해주는 역할을 수행한다.</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/b48da904-809b-42f2-a51e-b9b24aff7513/image.png" alt=""></p>
<ol start="3">
<li>그 이후 Bean으로 등록된 HandlerMapping이 변수들을 찾아서 Adapter를 거쳐 실행하여 실행한다.</li>
</ol>
<blockquote>
<h2 id="3-requestmapping이-사용하는-속성">3. @RequestMapping이 사용하는 속성</h2>
</blockquote>
<table>
<thead>
<tr>
<th>이름</th>
<th>타입</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>value</td>
<td>String[]</td>
<td>URL 값으로 매핑 조건을 부여 (default)</td>
</tr>
<tr>
<td>method</td>
<td>RequetMethod[]</td>
<td>HTTP Request 메소드 값을 매핑 조건으로 부여<br>사용 가능한 메소드는 GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE (7개)</td>
</tr>
<tr>
<td>params</td>
<td>String[]</td>
<td>HTTP Request 파라미터를 매핑 조건으로 부여</td>
</tr>
<tr>
<td>consumes</td>
<td>String[]</td>
<td>설정과 Content-Type request 헤더가 일치할 경우에만 URL이 호출됨</td>
</tr>
<tr>
<td>produces</td>
<td>String[]</td>
<td>설정과 Accept request 헤더가 일치할 경우에만 URL이 호출됨</td>
</tr>
</tbody></table>
<ul>
<li><h3 id="value">value</h3>
</li>
<li><em>value*</em>는 <strong>연결할 url을 지칭</strong>한다. 보통 호스트 주소와 포트 번호를 제외하고, REST API에 따른 url을 설계한다.</li>
</ul>
<pre><code class="language-java">@RequestMapping(value=&quot;/hello&quot;)</code></pre>
<p>위와 같이 매핑을 하게 되면 보통 local환경에선 localhost:8080/hello로 url을 입력했을 경우에 해당하게 된다. 뿐만 아니라 value를 생략하거나 다중 요청도 가능하다.</p>
<pre><code class="language-java">@RequestMapping({&quot;/hello&quot;, &quot;/hello-buddy&quot;, &quot;/hello/**&quot;}</code></pre>
<p>위와 같이 다중 요청도 가능하며 셋 중 어느 url을 쳐도 다 연결된다.</p>
<blockquote>
<p><strong>경로변수(@PathVariable) 사용</strong>
뿐만 아니라 최근 HTTP API는 리소스 경로에 식별자를 넣는 스타일을 선호한다. 쿼리 파라미터로 식별자를 넣는 방법도 있지만 경로 변수를 사용하는 것이 매핑되는 부분을 편리하게 조회할 수 있다. </p>
<pre><code class="language-java">    @GetMapping(&quot;/mapping/{userId}&quot;)
    public String mappingPath(@PathVariable(&quot;userId&quot;) String data) {
        log.info(&quot;mappingPath userId={}&quot;, data);
        return &quot;ok&quot;;
    }

    @GetMapping(&quot;mapping/{userId}&quot;)
    public String mappingPath(@PathVariable String userId) {
        log.info(&quot;mappingPath userId={}&quot;, userId);
        return &quot;ok&quot;;
    }</code></pre>
</blockquote>
<pre><code>&gt;
&gt; ```@PathVariable``` 어노테이션을 선언한 &quot;userId&quot;는 ```String``` 자료형으로 data에 매핑이 되는데, 아래와 같이 data 대신 같은 파라미터를 선언해주면 생략이 가능하다.
&gt;
&gt; ```java
    @GetMapping(&quot;/mapping/users/{userId}/orders/{orderId}&quot;)
    public String mappingPath(@PathVariable String userId, @PathVariable Long orderId) {
        log.info(&quot;mappingPath userId={}, orderId={}&quot;, userId, orderId);
        return &quot;ok&quot;;
    }</code></pre><blockquote>
<p>이와 같이 <code>@PathVariable</code>은 다중으로 사용할 수 있다.</p>
</blockquote>
<ul>
<li><h3 id="method">method</h3>
</li>
</ul>
<p>RequestMethod의 경우, <code>GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE</code> 등 8가지가 있다. 보통의 경우에는 <code>@RequestMapping</code> 어노테이션에 아래와 같이 method를 쓸 수 있다.</p>
<pre><code class="language-java">@RequestMapping(method = RequestMethod.GET, value = &quot;/hello&quot;)</code></pre>
<p>하지만 <code>GET, POST, PUT, PATCH, DELETE</code> 메서드에 대해서 각각에 맞는 메서드 옵션이 적용된 어노테이션(<code>@GetMapping</code>이나 <code>@PostMapping</code>과 같은)이 존재하여 <code>@RequestMapping</code> 하위에 써서 코드를 좀 더 간결하게 만들 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/e9a2b4d7-0b53-4748-848e-e3eb7f522c31/image.png" alt=""></p>
<p>추가적으로 <code>@RequestMapping</code>은 Class와 Method에 붙일 수 있고, <code>@GetMapping, @PostMapping, @PutMapping, @DeleteMapping</code> 등은 Method에만 붙일 수 있다.</p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://tecoble.techcourse.co.kr/post/2021-06-18-spring-request-mapping/">https://tecoble.techcourse.co.kr/post/2021-06-18-spring-request-mapping/</a>,
<a href="https://sarc.io/index.php/development/1139-requestmapping">https://sarc.io/index.php/development/1139-requestmapping</a>,
<a href="https://mungto.tistory.com/436">https://mungto.tistory.com/436</a>,
<a href="https://dahliachoi.tistory.com/42">https://dahliachoi.tistory.com/42</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] @RequestBody & @ResponseBody 어노테이션]]></title>
            <link>https://velog.io/@dyunge_100/Spring-RequestBody-ResponseBody-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</link>
            <guid>https://velog.io/@dyunge_100/Spring-RequestBody-ResponseBody-%EC%96%B4%EB%85%B8%ED%85%8C%EC%9D%B4%EC%85%98</guid>
            <pubDate>Tue, 19 Apr 2022 01:44:52 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="0-비동기asynchronous-통신">0. 비동기(Asynchronous) 통신</h2>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/11b066c0-3d62-4523-a8ee-315e780c1f7f/image.png" alt=""></p>
<h3 id="01-동기synchronous">0.1 동기(Synchronous)</h3>
<p>동기식 통신 및 동기식 프로그래밍이란 Request를 보내면 얼마나 시간이 걸리든 Response를 받기 전까지 기다리는 방식을 말한다. 즉, <strong>Request를 보낸 Thread는 Response를 받기 전까지 아무것도 하지 않는 &#39;Block&#39; 상태가 됨</strong>을 의미한다. </p>
<p>이러한 방식은 Request와 Response 값의 순서를 보장하고, Request에 대한 처리 결과를 보장받을 수 있다는 장점이 있다. 하지만 단점으로는 Response가 지연되게 된다면 Request를 보낸 Thread는 무작정 기다리기만 한다는 것이다. 그렇게 되면 정작 Thread를 써야 할 때 Response를 기다리느라 쓰지 못하는 경우가 발생할 수 있다. </p>
<h3 id="02-비동기asychronous">0.2 비동기(Asychronous)</h3>
<p>비동기식 통신 및 비동기식 프로그래밍이란 동기식과는 반대로 <strong>Request를 보내더라도 Response를 기다리지도 않고 상관하지도 않는다.</strong> 이 경우에는 Thread가 마냥 Response를 기다리지 않으니 다른 일을 처리할 수 있다. Request를 보내고도 Response를 기다리지 않고 다른 일을 할 수 있는 이러한 상태를 <strong>&#39;Non Block&#39;</strong> 상태라고 부른다.</p>
<p>Response를 기다리지 않기 때문에 통신의 성능(속도)적인 면에 있어선 비동기식이 우세하지만, 순서를 보장하지 않기 때문에 Response에 대한 처리 결과를 보장받아야 하는 서비스에는 적합하지 않는다. 따라서 진행하고자 하는 서비스에 맞게 동기식과 비동기식 중 어떤 걸 사용할지 선택해야 한다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/f12a5aec-fbf5-49c1-8de8-c94917ba4153/image.png" alt=""></p>
<h3 id="03-ajax란">0.3 Ajax란?</h3>
<p><strong>Ajax</strong>란 <strong>비동기 자바스크립트와 XML을 활용하여 빠르게 동작하는 웹 페이지를 만드는 개발 기법</strong>을 말한다. 
Ajax는 웹 페이저 전체를 다시 로딩하지 않고도, 웹 페이지의 일부분만을 갱신할 수 있다.(<strong>비동기성</strong>) 또한, Json, XML, HTML, 텍스트 파일 등의 다양한 형태의 데이터를 주고 받을 수 있다. Ajax는 아래와 같은 작업을 할 수 있게 해준다.</p>
<ul>
<li><p>페이지의 새로 고침 없이 서버에 요청</p>
</li>
<li><p>서버로부터 데이터를 받고 작업을 수행</p>
</li>
</ul>
<h3 id="04-json이란">0.4 JSON이란?</h3>
<p><strong>JSON(JavaScript Object Notation)은 Javascript 객체 리터럴(literal) 문법으로 구조화된 데이터를 표현하기 위한 문자 기반의 표준 포맷</strong>이다. 경량하다는 특징 덕분에 웹 애플리케이션에서 데이터를 전송할 때 일반적으로 사용하며, 저장할 때도 사용한다. XML형식에 비해 필요한 구조가 적고 <code>Key : Value</code>로 보통 존재한다.</p>
<pre><code class="language-JSON">{
  &quot;employees&quot;: [
    {
      &quot;name&quot;: &quot;Suran&quot;,
      &quot;lastName&quot;: &quot;Kim&quot;
    },
    {
      &quot;name&quot;: &quot;Seung&quot;,
      &quot;lastName&quot;: &quot;Baik&quot;
    }]
  &quot;email&quot;: &quot;kyosii11@gmail.com&quot;, ...
}</code></pre>
<p>위와 같이 <code>Key값</code>이나 문자열은 항상 <code>&quot; &quot;</code>(큰따옴표)를 이용하여 표기해야 한다. 또, 배열(Array)의 경우 <code>[ ]</code>을 이용하여 표현한다.</p>
<p>개별 JSON 객체의 경우 <code>.json</code> 확장자를 가진 단순 텍스트 파일에 저장할 수 있고, <strong>MIME타입</strong>은 <code>application/json</code>이다.</p>
<blockquote>
<h2 id="1-requestbody와-responsebody-어노테이션">1. @RequestBody와 @ResponseBody 어노테이션</h2>
</blockquote>
<p>보통 웹에서 화면 전환(새로 고침) 없이 이루어지는 동작들은 대부분 비동기식 통신으로 이루어진다. 비동기식 통신을 하기 위해선 클라이언트든 서버든 메시지의 본문에 데이터를 담아 보내야 한다. 이 때, 요청과 응답에 따라 각각 &#39;요청 메시지&#39;와 &#39;응답 메시지&#39;로 불리고, 그 메시지 안의 본문(Body) 부분을 <strong>RequestBody</strong>(요청 본문)와 <strong>ResponseBody</strong>(응답 본문)으로 부른다. 웹 상에서는 이 Body 부분에 들어가는 것들 중 가장 많이 쓰이는 형식이 <strong>JSON형식</strong>이다.</p>
<h3 id="requestbody--http-body-안에-json을-vo에-mapping하는-어노테이션">@RequestBody : HTTP Body 안에 JSON을 VO에 Mapping하는 어노테이션</h3>
<pre><code class="language-java">@RequestMapping(value = &quot;/requestBodyTest.do&quot;) 
public String requestBodyTest(@RequestBody UserVO vo) throws Exception {
    return &quot;test/login&quot;; 
}</code></pre>
<p>HTTP 요청 Body를 자바 객체로 <code>Conversion</code>해준다. 그냥 변환되는 것이 아니라 <code>HttpMessageConverter</code>에서 Request Header(요청 헤더)에 있는 <code>Content-Type</code>을 확인하고, JSON을 컨버팅 할 수 있는 컨버터(<code>Jackson2ObjectMapperBuilder</code>)를 선택해서 사용한다. 이 과정을 거쳐 요청 Body에 담긴 데이터는 자바 객체로 변환된다.
cf) <code>Jackson2ObjcetMapperBuilder</code>는 스프링부트에서 <code>JacksonAutoConfiguration</code> 클래스에서 자동으로 설정되므로 별다른 설정 없이도 JSON을 자바 객체로 변환하는 <code>ObjectMapper</code>를 사용할 수 있다.</p>
<h3 id="responsebody--vo객체를-json으로-바꿔-http-body-안에-담는-어노테이션">@ResponseBody : VO객체를 JSON으로 바꿔 HTTP Body 안에 담는 어노테이션</h3>
<pre><code class="language-java">@ResponseBody 
@RequestMapping(value = &quot;/responseBodyTest.do&quot;) 
public UserVO responseBodyTest() throws Exception { 
  UserVO vo = new UserVO(); 
  vo.setId(&quot;테스트&quot;); 

  return vo; 
}</code></pre>
<p>요청한 형태에 맞춰 메시지 변환기를 통해 결과값을 반환한다. 
@ResponseBody를 이용하면 자바 객체를 HTTP ResponseBody에 넣어 전송할 수 있다.</p>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://inpa.tistory.com/entry/WEB-%F0%9F%8C%90-%EB%B9%84%EB%8F%99%EA%B8%B0Async%ED%86%B5%EC%8B%A0-%EB%8F%99%EA%B8%B0Sync%ED%86%B5%EC%8B%A0">https://inpa.tistory.com/entry/WEB-%F0%9F%8C%90-%EB%B9%84%EB%8F%99%EA%B8%B0Async%ED%86%B5%EC%8B%A0-%EB%8F%99%EA%B8%B0Sync%ED%86%B5%EC%8B%A0</a>,
<a href="https://sudo-minz.tistory.com/21">https://sudo-minz.tistory.com/21</a>,
<a href="https://velog.io/@ym1085/JSON-%EC%82%AC%EC%9A%A9%EB%B2%95">https://velog.io/@ym1085/JSON-%EC%82%AC%EC%9A%A9%EB%B2%95</a>,
<a href="https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/JSON">https://developer.mozilla.org/ko/docs/Learn/JavaScript/Objects/JSON</a>,
<a href="https://developer.mozilla.org/ko/docs/Web/Guide/AJAX/Getting_Started">https://developer.mozilla.org/ko/docs/Web/Guide/AJAX/Getting_Started</a>,
<a href="https://truecode-95.tistory.com/113">https://truecode-95.tistory.com/113</a>,
<a href="https://medium.com/webeveloper/reqeustbody%EC%99%80-responsebody-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C-2efcab364edb#">https://medium.com/webeveloper/reqeustbody%EC%99%80-responsebody-%EC%96%B8%EC%A0%9C-%EC%82%AC%EC%9A%A9%ED%95%A0%EA%B9%8C-2efcab364edb#</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] 트랜잭션(Transaction)]]></title>
            <link>https://velog.io/@dyunge_100/DB-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98Transaction</link>
            <guid>https://velog.io/@dyunge_100/DB-%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98Transaction</guid>
            <pubDate>Mon, 18 Apr 2022 05:24:18 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="1-트랜잭션transaction이란">1. 트랜잭션(Transaction)이란?</h2>
</blockquote>
<p>트랜잭션이란 <strong>데이터베이스의 상태를 변화시키기 위한 작업 수행의 논리적 단위</strong>를 의미한다.
풀어서 설명하자면, 데이터베이스의 상태를 변화시킨다는 것은 우리가 SQL문에 흔히 쓰는 CRUD(SELECT, INSERT, DELETE, UPDATE) 기능을 하는 질의어(Query) 문장들을 일컫는다. 트랜잭션은 <strong>하나의 작업을 처리하기 위해 사용자가 임의로 정해둔 필요한 질의어(Query)들의 집합</strong>이라고 생각하면 편하다.</p>
<p>예를 들어 내가 누군가에게 10000원을 송금한다고 하였을 때, 그 과정에서 오류가 발생하여 송금은 이뤄지지 않고 내 계좌에서 10000원만 빠져나간다면 서비스의 큰 오점이 될 것이다. 이와 같은 상황을 막기 위해 거래가 성공적으로 끝나야만 완전한 거래로 인식해 승인하고, 오류가 발생하면 아예 없었던 일처럼 원래대로 되돌려 놓아야 한다.</p>
<p>이런 방식으로 <strong>시스템의 안정성을 보장하기 위해 개발하는 사람이 지정한 작업 수행의 단위</strong>가 트랜잭션인 것이다. <strong>DBMS의 성능은 초당 트랜잭션의 실행 수(TPS, Transaction per second)로 측정한다.</strong></p>
<hr>
<blockquote>
<h2 id="2-트랜잭션의-특징acid">2. 트랜잭션의 특징(ACID)</h2>
</blockquote>
<ul>
<li><h3 id="1-원자성atomicity">1) 원자성(Atomicity)</h3>
</li>
</ul>
<p>쪼개어지지 않는 원자(Atom, 원래는 쿼크 단위로도 쪼개어질 수 있지만 쪼개어질 수 없는 단위라는 의미에 있어 그렇게 쓰임)와 같이 트랜잭션을 구성하는 연산들이 모두 정상적으로 실행되거나 실행되지 못하면 트랜잭션 자체가 무효여야 한다는 의미이다. 즉, 트랜잭션 안의 연산들은 개별로 실행되어선 안되고, 하나의 단위처럼 모두 실행되거나 실행되지 않아야 한다.</p>
<ul>
<li><h3 id="2-일관성consistency">2) 일관성(Consistency)</h3>
</li>
</ul>
<p>트랜잭션이 성공적으로 수행된 후에도 데이터베이스는 일관된 상태로 유지되어야 한다. 
트랜잭션 전 후의 데이터베이스의 상태는 Correct State여야 한다고 하는데, Correct State는 도메인의 유효 범위, 무결성 제약 조건 등의 조건을 위배하지 않는 정상적인 상태를 의미한다.</p>
<ul>
<li><h3 id="3-격리성isolation">3) 격리성(Isolation)</h3>
</li>
</ul>
<p>각각의 트랜잭션은 서로 간섭 없이 독립적으로 수행되어야 한다. 시스템에서 여러 트랜잭션이 동시에 수행되지만, 각 트랜잭션이 독립적으로 수행될 수 있도록 다른 트랜잭션의 중간 연산 결과에 서로 접근하지 못하게 해야 한다.</p>
<p>하지만 격리성을 완전히 보장하려면 각각의 트랜잭션을 순서대로 처리해야 하고, 이는 동시성 처리 성능을 저해시킨다. 따라서 격리성의 수준을 여러 단계(Read-Uncommited, Read-Commited, Repeatable-Read, Serialable)로 나눠 놓았다.</p>
<ul>
<li><h3 id="4-지속성durability">4) 지속성(Durability)</h3>
</li>
</ul>
<p>트랜잭션이 성공적으로 완료된 후에는 데이터베이스에 반영한 수행 결과가 어떤 경웨도 손상되지 않고 영구적이어야 한다. 중간에 시스템 문제가 발생했을 때 데이터베이스 로그를 참고해서 성공했던 트랜잭션을 복구 할 수 있다.</p>
<hr>
<blockquote>
<h2 id="3-트랜잭션의-연산">3. 트랜잭션의 연산</h2>
</blockquote>
<p>트랜잭션이 진행되면서 질의문(Query)을 날릴 때마다 DB에 반영이 되진 않는다. 트랜잭션 연산이 성공적으로 완료되는 시점에 실질적으로 DB에 반영이 된다. 트랜잭션 연산에는 크게 두 가지가 있다.</p>
<ul>
<li><h3 id="1-커밋commit-연산">1) 커밋(Commit) 연산</h3>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/73e5dd8a-874d-4516-b78a-e2d72692e619/image.png" alt=""></p>
<p>하나의 트랜잭션이 성공적으로 수행되었을 경우에 선언되는 연산이다. Commit 연산이 수행되면 수행했던 트랜잭션이 로그에 저장되고, 최종적으로 DB에 결과가 반영된다.</p>
<ul>
<li><h3 id="2-롤백rollback-연산">2) 롤백(Rollback) 연산</h3>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/edfa795d-0b87-46a0-9516-7b499ea4194e/image.png" alt=""></p>
<p>트랜잭션이 수행되는 중간에 실패하였을 경우에 선언되는 연산이다. Rollback 연산이 수행되면 수행했던 작업들이 취소되고, 트랜잭션 수행 전의 상태로 되돌아간다.(원자성)
원칙적으로는 원자성을 지켜야 하므로 아예 처음부터 다시 시작하여야 하지만, 특수한 경우에는 SAVEPOINT를 지정하고 트랜잭션을 부분적으로 취소할 수 있다.</p>
<blockquote>
<h4 id="savepoint">SAVEPOINT</h4>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/51b40ee2-9727-484b-a0b0-4f143d769479/image.png" alt=""></p>
<ul>
<li>트랜잭션 내부에서 사용자가 지정할 수 있는 세부 작업 단위. 원칙대로라면 원자성을 보장해야 하지만, 매우 긴 트랜잭션의 경우 대부분의 로직이 수행됐는데 마지막에만 문제가 생겨 Rollback이 되면 문제가 발생하지 않은 영역까지 반복해야 하는 불필요한 상황이 발생한다. 따라서 개발자가 임의적으로 트랜잭션을 작게 분할 할 수 있다.(원자가 쿼크 단위로 쪼개지듯)</li>
</ul>
<ul>
<li>SAVEPOINT를 저장했을 경우, ROLLBACK TO SAVEPOINT문을 통해 저장된 곳으로 ROLLBACK 할 수 있다.</li>
</ul>
<ul>
<li>위의 사진을 보면 COMMIT 명령이 선언된 후, 다음 COMMIT 명령이 선언될 때까지 하나의 트랜잭션이 구성되므로 UPDATE, DELETE, INSERT는 하나의 트랜잭션이 된다. 이 중 SAVEPOINT를 지정하게 되면 하나의 트랜잭션이라고 하더라도 ROLLBACK TO 명령을 통해 SAVEPOINT로 저장한 곳까지로 ROLLBACK 할 수 있다. </li>
</ul>
</blockquote>
<hr>
<blockquote>
<h2 id="4-트랜잭션의-상태">4. 트랜잭션의 상태</h2>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/c395a249-c30f-4410-92bb-8bcbdb87af22/image.png" alt=""></p>
<ul>
<li><p><strong>Active(활성화)</strong> : 트랜잭션이 현재 수행 중인 상태.</p>
</li>
<li><p><strong>Partially Committed(부분 완료)</strong> : 트랜잭션의 마지막 연산까지 실행했지만, Commit 연산이 실행되기 직전의 상태.</p>
</li>
<li><p><strong>Committed(완료)</strong> : Commit 연산을 실행 완료하여 데이터베이스에 최종 결과가 반영된 상태.</p>
</li>
<li><p><strong>Failed(실패)</strong> : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태.</p>
</li>
<li><p><strong>Aborted(철회)</strong> : 트랜잭션이 비정상적으로 종료되어 Rollback 연산을 수행한 상태.</p>
</li>
</ul>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://mommoo.tistory.com/62">https://mommoo.tistory.com/62</a>,
<a href="https://devjem.tistory.com/27#savePoint">https://devjem.tistory.com/27#savePoint</a>,
<a href="https://memory0136.tistory.com/36">https://memory0136.tistory.com/36</a>,
<a href="https://brunch.co.kr/@skeks463/27">https://brunch.co.kr/@skeks463/27</a>,
<a href="https://devuna.tistory.com/30">https://devuna.tistory.com/30</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[DTO, VO, DAO, Entity의 차이점]]></title>
            <link>https://velog.io/@dyunge_100/DTO-VO-DAO-Entity%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</link>
            <guid>https://velog.io/@dyunge_100/DTO-VO-DAO-Entity%EC%9D%98-%EC%B0%A8%EC%9D%B4%EC%A0%90</guid>
            <pubDate>Mon, 18 Apr 2022 01:39:55 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="1-daodata-access-object란">1. DAO(Data Access Object)란?</h2>
</blockquote>
<ul>
<li><p><strong>DB에 직접적으로 접근하기 위한 객체</strong>이다.</p>
</li>
<li><p>Service와 DB를 연결하는 연결 고리 역할을 한다.</p>
</li>
<li><p><strong>DB에 접근하기 위한 로직을 분리</strong>하기 위해 사용한다.</p>
</li>
<li><p><strong>DB에 접근하여 CRUD 기능을 수행한다.</strong></p>
</li>
</ul>
<blockquote>
<h2 id="2-dtodata-transfer-object">2. DTO(Data Transfer Object)</h2>
</blockquote>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/901842c3-2097-4a4b-b81c-68b0d64af3d2/image.png" alt=""></p>
<ul>
<li><p>DTO는 <strong>계층(Controller, View, Business Layer) 간의 데이터 전달을 위한 객체</strong>이다.</p>
</li>
<li><p>비즈니스 로직을 갖고 있지 않으며, <code>getter/setter</code> 메서드만을 갖는다.</p>
</li>
<li><p><code>toEntity()</code> 메서드를 통해서 DTO에 필요한 부분을 이용하여 Entity로 만든다.</p>
</li>
<li><p>또한 Controller Layer에서 Response DTO 형태로 Client에 전달할 때 활용성이 제일 높다.</p>
</li>
</ul>
<pre><code class="language-java">@Getter
@Setter
public class SignUpDTO {
    private String userId;
    private String userPassword;
    private String userName;
    private String userEmail;
}
</code></pre>
<blockquote>
<h2 id="3-vovalue-object">3. VO(Value Object)</h2>
</blockquote>
<ul>
<li><p>값 그 자체를 나타내는 객체이다. </p>
</li>
<li><p><strong>DTO와 동일한 개념으로 같지만, Read-Only(불변성) 속성을 갖는다.</strong></p>
</li>
<li><p>보통 VO는 특정한 비즈니스 값을 담는 객체이고 비즈니스 로직도 포함 가능하다. 모든 레이어에서 사용 가능하다.</p>
</li>
<li><p>VO는 <code>Getter</code>와 <code>Setter</code>를 모두 가질 수 있으나, <code>equals()</code>와 <code>hashCode()</code>를 오버라이딩하여 자주 사용한다. 따라서 value가 같으면 같은 객체라고 본다.</p>
</li>
</ul>
<blockquote>
<h2 id="4-entity-class">4. Entity Class</h2>
</blockquote>
<ul>
<li><p>흔히 아키텍처를 설명할 때 <strong>Domain 클래스</strong>로 불리기도 한다. 
Spring 3 Tier인 <code>Persistence</code>, <code>Business</code>, <code>Presentation</code> Tier 중 <code>Persistence Tier</code>에서 사용된다.</p>
</li>
<li><p><strong>실제 DB 테이블과 1:1로 매핑(Mapping)되는 핵심 클래스(Class)로, DB 테이블에 존재하는 칼럼(Column)들을 필드(Field)로 가지는 객체다.</strong></p>
</li>
<li><p>Entity는 데이터베이스 영속성(Persistent)의 목적으로 사용되는 객체이며, 때문에 요청이나 응답으로 바로 값을 전달하는 클래스로 사용하는 것은 좋지 않다. 이러한 경우에는 DTO를 사용하여 값을 전달하는 게 맞다. 느낀 바로는 Entity 클래스와 DTO 클래스를 분류하여 설계하였을 때 유지보수면에서 확실히 자유로워질 수 있다.(많은 서비스 클래스와 비즈니스 로직들이 Entity 클래스를 기준으로 동작하기 때문에 Entity 클래스가 변경되면 좋지 않다는 말과 일맥상통하다.)</p>
</li>
<li><p>Entity 클래스에서는 Setter 메서드 사용을 지양해야 한다. Setter로 접근하여 변경되는 순간 객체의 일관성, 안정성을 보장하기 힘들어지기 때문이다. 따라서 Setter 대신 Constructor(생성자)나 Builder Pattern을 사용해야 한다. </p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/0a17bd32-2d3f-41cf-a5cf-e0aa56ac8f52/image.png" alt=""></p>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://choitaetae.tistory.com/97">https://choitaetae.tistory.com/97</a>,
<a href="http://melonicedlatte.com/2021/07/24/231500.html">http://melonicedlatte.com/2021/07/24/231500.html</a>,
<a href="https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html">https://gmlwjd9405.github.io/2018/12/25/difference-dao-dto-entity.html</a>,
<a href="https://wildeveloperetrain.tistory.com/101">https://wildeveloperetrain.tistory.com/101</a>,
<a href="https://velog.io/@gillog/Entity-DTO-VO-%EB%B0%94%EB%A1%9C-%EC%95%8C%EA%B8%B0">https://velog.io/@gillog/Entity-DTO-VO-%EB%B0%94%EB%A1%9C-%EC%95%8C%EA%B8%B0</a>,
<a href="https://velog.io/@ha0kim/DAO-DTO-VO-%EC%B0%A8%EC%9D%B4">https://velog.io/@ha0kim/DAO-DTO-VO-%EC%B0%A8%EC%9D%B4</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] JDBC에 대한 정리]]></title>
            <link>https://velog.io/@dyunge_100/DB-JDBC%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@dyunge_100/DB-JDBC%EC%97%90-%EB%8C%80%ED%95%9C-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Fri, 15 Apr 2022 07:21:24 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="1-jdbc란-무엇인가">1. JDBC란 무엇인가?</h2>
</blockquote>
<p>*<em>JDBC(Java Database Connectivity)는 자바에서 데이터베이스에 접속할 수 있도록 하는 자바 API다. JDBC를 통해서 DBMS의 종류에 상관없이 데이터베이스를 연결하고 작업을 처리할 수 있다. *</em></p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/c5d94022-d8be-4ad7-beec-699fe0f30f4a/image.png" alt=""></p>
<p>JDBC의 특징과 역할은 다음과 같다.</p>
<ul>
<li><p>Java 코드에서 DB서버에 접속할 수 있다. </p>
</li>
<li><p>SQL문을 구성하고 DB서버에서 실행할 수 있다. 이 때, SQL문은 Java 코드 안에 포함된다. </p>
</li>
<li><p>DB의 정보나 DB서버에서 처리한 결과를 가져올 수 있다.</p>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/4b32c338-b572-41ff-95f7-f186fdd64f8d/image.png" alt=""></p>
<p>데이터를 메모리(램)에만 저장하면 애플리케이션이 종료되었을 때 데이터가 다 날라가버린다. 
따라서 데이터의 영속성(<strong>Persistence</strong>)를 보장해줘야 하는데, 이를 보장하는 것이 데이터베이스(DB)같은 저장소다. </p>
<p>Java는 Persistence Layer를 이러한 JDBC로 구현한다. JDBC를 통해 영속성이 보장되는 데이터베이스에 접근할 수 있는 것이다.</p>
<hr>
<blockquote>
<h2 id="2-jdbc-프로그래밍-흐름과-관련-인터페이스">2. JDBC 프로그래밍 흐름과 관련 인터페이스</h2>
</blockquote>
<h3 id="21-jdbc-프로그래밍의-대략적인-흐름">2.1 JDBC 프로그래밍의 대략적인 흐름</h3>
<h4 id="1-jdbc-driver-로드">1) JDBC Driver 로드</h4>
<h4 id="2-db-연결-생성">2) DB 연결 생성</h4>
<h4 id="3-db에-있는-데이터를-읽거나-쓰기-sql문">3) DB에 있는 데이터를 읽거나 쓰기 (SQL문)</h4>
<h4 id="4-db-연결-종료">4) DB 연결 종료</h4>
<h3 id="22-jdbc-프로그래밍의-구체적인-흐름코드-레벨">2.2 JDBC 프로그래밍의 구체적인 흐름(코드 레벨)</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/daa1cda9-5b6a-4cb7-b965-8eee5c1a3e49/image.png" alt=""></p>
<ul>
<li><p>1) <code>import java.sql.*;</code></p>
</li>
<li><p>2) 각 DBMS별에 알맞는 Driver를 로드한다. 예를 들면, PostgreSQL의 경우 </p>
<pre><code class="language-java">Class.forName(&quot;org.postgresql.Driver&quot;);</code></pre>
<p>을 이용하여 드라이버를 로드한다. </p>
</li>
</ul>
<blockquote>
<p>cf) <code>Class</code> 클래스는 클래스들의 정보를 담는 메타 클래스로, JVM은 <code>Class</code> 클래스를 통해 클래스들에 대한 정보를 <code>Class Loader</code>에 로드(Load)한다. 
JDBC Driver와 같이 인스턴스를 별도로 관리하지 않는 대부분의 클래스의 경우, 그 클래스가 스스로의 인스턴스를 정적 블록을 통해 생성하고 관리한다. <code>forName()</code> 메서드를 호출하면 Driver 자기 자신을 초기화하여 DriverManager에 등록한다. 즉, 개발자가 따로 관리하지 않는 Static 객체들이 알아서 DriverManager에 등록된다.</p>
</blockquote>
<ul>
<li>3) <code>DriverManager</code>의 <code>getConnection</code>메소드를 이용하여 <code>Connection</code> 인스턴스를 얻는다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/8a1b8b99-a7ba-46c7-960b-837fe751c224/image.png" alt=""></p>
<ul>
<li>4) <code>Connection</code> 인스턴스를 통해 <code>PreparedStatement</code> 객체를 생성하고 쿼리문을 생성하여 보낸다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/9e7f0bea-3f3f-40c5-9d7e-173a412cc482/image.png" alt=""></p>
<ul>
<li><p>5) SQL문을 실행하고 결과물이 있다면, <code>ResultSet</code> 객체를 생성하고 반환한다.</p>
</li>
<li><p>6) 생성했던 객체들을 <code>close()</code> 메소드로 닫아 없앤다.</p>
</li>
</ul>
<h3 id="23-관련-인터페이스와-클래스에-대한-설명">2.3 관련 인터페이스와 클래스에 대한 설명</h3>
<ul>
<li><h4 id="jdbc-driver-apijavasqldriver">JDBC Driver API(java.sql.Driver)</h4>
</li>
</ul>
<p>DB와 연결하는 <code>DriverManager</code> 클래스를 만들 때 반드시 들어가야 하는 인터페이스. 
JDBC DriverManager와 각 DBMS의 벤더에서 제공하는 JDBC Driver가 서로 접속하기 위해 필요하다.(properties 정보와 매치하여 접속)</p>
<ul>
<li><h4 id="jdbc-drivermanager-클래스-javasqldrivermanager">JDBC DriverManager 클래스 (java.sql.DriverManager)</h4>
</li>
</ul>
<p>DBMS의 벤더에서 제공하는 JDBC Driver에 직접적으로 접속하게 만들어주는 클래스. <code>getConnection()</code> 메소드를 통해 <code>Connection</code> 인스턴스를 생성한다.</p>
<ul>
<li><h4 id="connection-인터페이스-javasqlconnection">Connection 인터페이스 (java.sql.Connection)</h4>
</li>
</ul>
<p>특정 DB와의 연결 정보를 가지는 인터페이스.</p>
<ul>
<li><h4 id="statement-인터페이스-javasqlstatement">Statement 인터페이스 (java.sql.Statement)</h4>
</li>
</ul>
<p>SQL문을 DB에 전송하는 방법을 정의한 인터페이스.</p>
<ul>
<li><h4 id="preparedstatement-클래스-javasqlpreparedstatement">PreparedStatement 클래스 (java.sql.PreparedStatement)</h4>
</li>
</ul>
<p>Statement의 하위 인터페이스. SQL문을 미리 컴파일 하여 실행 속도를 높이는 데 도움을 준다.
<code>execute</code> 메소드를 사용해서 쿼리문을 실행하라는 명령을 내린다.</p>
<ul>
<li><h4 id="resultset-인터페이스-javasqlresultset">ResultSet 인터페이스 (java.sql.ResultSet)</h4>
</li>
</ul>
<p>SELECT문의 실행 결과를 조회할 수 있는 방법을 정의한 인터페이스.
ResultSet 객체에 대한 참조하여 <code>next()</code> 메소드로 각 요소들을 setter로 VO나 DTO에 넣어 객체를 반환할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/45b8d828-26d0-48d7-97c2-968fd60992ad/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/839bd2f9-ed82-4b09-88b5-1326156abcbc/image.png" alt=""></p>
<hr>
<h2 id="3-jdbc-sqlmapper-orm-등에-대하여">3. JDBC, SQLMapper, ORM 등에 대하여</h2>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/0d46d6f6-cba5-4a9b-ba16-e2e3c89e0ae3/image.png" alt=""></p>
<p>JDBC API는 영속성을 보장해주는 편리한 API이긴 하지만 SQL문을 작성하는 것에 있어 중복 코드가 많아질 우려가 있고, Connection 관리를 계속해서 해줘야 하는 단점이 있다. 이러한 단점을 극복하기 위해 발전된 것이 SQLMapper와 ORM이다.</p>
<h3 id="31-sqlmapper">3.1 SQLMapper</h3>
<h4 id="1-spring-jdbc">1) Spring JDBC</h4>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/f4413034-aa0e-42ea-8e96-629ce44744e1/image.png" alt=""></p>
<p>Connection에 대한 Configuration을 JdbcTemplate이라는 클래스에 담아 Spring을 통해 주입 받는 형식의 Mapper다. 추상화가 많이 이뤄져 편하게 사용할 수 있다.</p>
<h4 id="2-mybatis">2) Mybatis</h4>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/be80d5c9-0c8a-4205-b33c-0fb6af580702/image.png" alt=""></p>
<p>Mybatis는 Java 코드에서 SQL을 쓰는 것 자체를 XML파일로 이동시켜 분리시켜버린다. 
SQL문을 XML파일로 따로 지정하고 Java 메소드와 매핑시킴으로써 반복되는 코드를 줄이고 개발하는 단계에서 SQL문을 한 번 작성하면 나머진 Java코드로 해결할 수 있도록 만들어준다.</p>
<h3 id="32-orm-object-relational-mapping">3.2 ORM (Object-Relational Mapping)</h3>
<h4 id="jpa-java-persistence-api--hibernate">JPA (Java Persistence API) / Hibernate</h4>
<p>객체지향적으로 구현되어 있는 구조에서 RDB와 연결하는 것을 간편하게 하기 위해 등장한 기술이다. JPA는 표준 인터페이스이고, 이를 구현하는 실제 여러 서비스 중 하나가 Hibernate이다. </p>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://sh77113.tistory.com/185">https://sh77113.tistory.com/185</a>,
<a href="https://dyjung.tistory.com/50">https://dyjung.tistory.com/50</a>,
<a href="https://jaehoney.tistory.com/29">https://jaehoney.tistory.com/29</a>,
<a href="https://velog.io/@doforme/JDBC%EB%9E%80">https://velog.io/@doforme/JDBC%EB%9E%80</a>,
<a href="https://velog.io/@jungnoeun/JDBC%EB%9E%80">https://velog.io/@jungnoeun/JDBC%EB%9E%80</a>,
<a href="https://shs2810.tistory.com/18">https://shs2810.tistory.com/18</a>,
<a href="https://sdesigner.tistory.com/101">https://sdesigner.tistory.com/101</a>,
<a href="https://sorjfkrh5078.tistory.com/296">https://sorjfkrh5078.tistory.com/296</a>,</p>
</blockquote>
<p><a href="https://pjh3749.tistory.com/250">https://pjh3749.tistory.com/250</a>,
<a href="https://kyun2.tistory.com/23">https://kyun2.tistory.com/23</a>,</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] PostreSQL에 대한 소개와 설치 과정]]></title>
            <link>https://velog.io/@dyunge_100/DB-PostreSQL</link>
            <guid>https://velog.io/@dyunge_100/DB-PostreSQL</guid>
            <pubDate>Tue, 12 Apr 2022 07:36:10 GMT</pubDate>
            <description><![CDATA[<h2 id="0-dbmsdatabase-management-system">0. DBMS(Database Management System)</h2>
<h3 id="01-db와-dbms가-등장한-배경">0.1 DB와 DBMS가 등장한 배경</h3>
<p><strong>데이터베이스(Database)</strong>란 구조화된 데이터들의 집합이다. 데이터를 통합하고 효율적으로 관리하고 검색하기 위해 이러한 데이터 집합을 만들었는데, 우리는 이 데이터들로부터 우리에게 유의미한 데이터인 <strong>&#39;정보(Information)&#39;</strong>를 추출할 수 있다.</p>
<p>DBMS가 등장하기 이전에는 파일 시스템으로 데이터를 관리하였는데 데이터의 중복이나 누락, 연관이 없는 데이터들끼리 모여있는 등의 다양한 문제가 있었다. </p>
<p>더 효율적으로 데이터를 관리하기 위해 데이터베이스의 데이터 조작과 관리를 극대화한 시스템 소프트웨어가 나왔는데 그것이 바로 DBMS였다. DBMS는 응용프로그램과 데이터베이스 사이에서 중재하는 역할을 한다. 이로 인해 웹 애플리케이션을 제작할 때, 데이터베이스와 주요 서비스 로직을 분리할 수 있다는 장점이 생겼다.</p>
<h3 id="02-데이터-모델의-종류">0.2 데이터 모델의 종류</h3>
<ul>
<li><p>1) 계층형 데이터 모델 : 트리 구조를 활용하여 데이터 연관성을 계층별로 나누어 부모 자식 관계를 정의하고 데이터를 관리하는 형태의 데이터 모델.</p>
</li>
<li><p>2) 네트워크 데이터 모델 : 그래프 구조 기반 형태의 데이터 모델.</p>
</li>
<li><p>3) 객체 지향형 데이터 모델 : 객체 지향 프로그래밍에서 사용하는 객체 개념을 기반으로 한 데이터 모델. 다만 객체지향 개념을 완벽히 도입하는 게 쉽지 않아 이를 적용한 DBMS는 많이 존재하지 않음.</p>
</li>
<li><p>4) 관계형 데이터 모델 : 가장 많이 알려진 데이터 모델로써, 데이터 간의 관계(Relationship)에 초점을 둔다. 관계형 데이터 모델의 구성 요소는 다음과 같다. </p>
<ul>
<li><p>개체(Entity) : 데이터베이스에서 데이터화하려는 사물, 개념의 정보 단위. 관계형 데이터베이스의 테이블(Table)의 개념과 대응된다.</p>
</li>
<li><p>속성(Attribute) : 개체를 구성하는 데이터의 가장 작은 논리적 단위. 관계형 데이터베이스의 열(Column)의 개념과 대응된다.</p>
</li>
<li><p>관계(Relationship) : 개체와 개체 또는 속성 간의 연관성을 나타내기 위해 사용한다. 관계형 데이터베이스에서는 테이블 간의 관계를 왜래키(Foreign Key) 등으로 구현하여 사용한다. </p>
</li>
</ul>
</li>
</ul>
<h3 id="03-sqlstructured-query-language이란">0.3 SQL(Structured Query Language)이란?</h3>
<p>쿼리(Query)라는 단어 자체는 질의, 질문을 뜻하지만 웹 클라이언트가 DB에게 특정한 데이터를 보내달라는 요청을 말하기도 한다. SQL이란 RDBMS에서 데이터를 다루고 관리하는 데 사용하는 데이터베이스 질의 언어라고 생각하면 된다. SQL은 사용 목적에 따라 DQL, DML, DDL, TCL, DCL로 나뉘어 구분된다.</p>
<hr>
<h2 id="1-postgresql">1. PostgreSQL</h2>
<h3 id="11-postgresql이란">1.1 PostgreSQL이란?</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/c9d5d11f-b773-4104-a333-8efa1031336e/image.png" alt=""></p>
<p>PostgreSQL은 오픈 소스 객체-관계형 데이터베이스 시스템(ORDBMS, Object-Relationship DataBase Management System)으로, Enterprise급 DBMS기능과 차세대 DBMS에서나 볼 수 있을 법한 기능들을 제공한다. 실제 기능적인 면에서는 Oracle과 유사하여, Oracle 사용자들이 가장 쉽게 적응할 수 있는 오픈소스 DBMS라는 평이 많다.</p>
<br>
***

<h3 id="12-postgresql의-구조">1.2 PostgreSQL의 구조</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/87ec9ce3-ffd7-4c3d-a74d-ed4347ba5b42/image.png" alt=""></p>
<p>PostgreSQL의 구조는 <strong>클라이언트-서버</strong> 구조이다. 서버는 데이터베이스 파일들을 관리하며, 클라이언트 대신 들어오는 요청에 대해 데이터베이스 액션을 수행한다. 서버는 다중 클라이언트 연결을 처리할 수 있는데, 서버는 <strong>클라이언트의 연결 요청이 오면 각 커넥션에 대해 새로운 프로세스를 생성하고 fork</strong>한다.(연결 요청을 마치 포크로 찍어 가져가는 걸 연상시킨다.) 그리고 <strong>Postmaster가 fork된 모든 프로세스를 제어</strong>한다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/036114ea-a4e1-4597-b339-087ceb9f45c9/image.png" alt=""></p>
<br>
***


<h3 id="13-기능-및-제한">1.3 기능 및 제한</h3>
<p>PostgreSQL은 기본적인 트랜잭션과 ACID(Atomicity, Consistency, Isolation, Durability)를 지원한다. 또한 ANSI SQL:2008 규격을 상당 부분 만족시키고 있으며, 전부를 지원하는 것을 목표로 현재도 기능적으로 업데이트가 꾸준히 되고 있다.</p>
<p>또한 PostgreSQL은 오래된만큼 상당히 많은 기능을 제공하고 있다. </p>
<p><code>Vaccum</code>은 PostgreSQL에만 존재하는 고유한 명령어로, 오래된 영역을 재사용하거나 정리해주는 명령어이다. PostgreSQL은 MVCC(Multi-Version Concurrency Control, 다중 버전 동시성 제어) 기법을 활용하기 때문에 특정 Row를 추가 또는 업데이트 할 경우, 디스크 상의 해당 Row를 물리적으로 업데이트 하여 사용하지 않고, 새로운 영역을 할당하여 사용한다.</p>
<table>
<thead>
<tr>
<th>항목</th>
<th>제한 사항</th>
</tr>
</thead>
<tbody><tr>
<td>최대 DB 크기(Database Size)</td>
<td>무제한</td>
</tr>
<tr>
<td>최대 테이블 크기(Table Size)</td>
<td>32TB</td>
</tr>
<tr>
<td>최대 레코드 크기(Row Size)</td>
<td>1.6TB</td>
</tr>
<tr>
<td>최대 컬럼 크기(Field Size)</td>
<td>1 GB</td>
</tr>
<tr>
<td>테이블당 최대 레코드 개수(Rows per Table)</td>
<td>무제한</td>
</tr>
<tr>
<td>테이블당 최대 컬럼 개수(Columns per Table)</td>
<td>250~1600개</td>
</tr>
<tr>
<td>테이블당 최대 인덱스 개수(Indexes per Table)</td>
<td>무제한</td>
</tr>
</tbody></table>
<h3 id="14-postgresql의-특장점">1.4 PostgreSQL의 특장점</h3>
<ul>
<li><p>Portable : ANSI C로 개발되었으며, <strong>다양한 플랫폼(OS)을 지원</strong>한다.</p>
</li>
<li><p>BSD 라이선스여서, 정책에 따라 소스를 변경하고 그 소스를 숨긴 채 재배포해도 법적으로 문제가 없다. 또한 무료 오픈소스여서 라이선스에 대한 <strong>비용 문제가 전혀 없다.</strong> 
즉, 영구적인 무료 DBMS이다.</p>
</li>
<li><p><strong>꾸준히 업데이트되고 있는 DBMS이며, 독창적인 자료형과 문법을 가지고 있다.</strong></p>
</li>
</ul>
<h2 id="2-postgresql설치부터-동작까지">2. PostgreSQL설치부터 동작까지</h2>
<h3 id="21-postgresql-설치부터-테이블-생성까지">2.1 PostgreSQL 설치부터 테이블 생성까지</h3>
<h4 id="1-postgresql-설치">1) PostgreSQL 설치</h4>
<p><a href="https://www.postgresql.org/">https://www.postgresql.org/</a> 사이트로 들어가서 PostgreSQL을 설치한다. 비밀번호를 설정하고 기억해야 한다.</p>
<h4 id="2-sql쉘psql을-실행하고-데이터베이스-생성-후-연결">2) SQL쉘(psql)을 실행하고 데이터베이스 생성 후 연결</h4>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/afdd8760-0e84-46f7-9a00-8f0acec217c5/image.png" alt=""></p>
<p>처음에는 이렇게 나오는데 Enter키를 누르다보면</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/5d64c882-f876-4043-b701-34b8b9cfbcc9/image.png" alt=""></p>
<p>이런 식으로 나오게 되고 Username까지는 Enter를 쳐줘도 된다.
기본적으로 Username은 postgres로 설정되는 것으로 보인다.
암호는 설치할 때 기억해뒀던 비밀번호로 입력하면 된다.
그 후,</p>
<pre><code class="language-sql">CREATE DATABASE 데이터베이스 이름;</code></pre>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/b7888c38-b5d2-4a47-a5cb-233bd6080e9e/image.png" alt=""></p>
<p>을 이용하여 데이터베이스를 생성하면 된다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/bbd48f0a-b04e-4754-8f22-6236313e59a7/image.png" alt=""></p>
<p>데이터베이스가 성공적으로 생성된 것을 확인해보고 싶다면,
<code>\l</code>을 입력하면 위와 같이 확인할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/d0d897be-7cfb-4b51-a56f-06115ab4176b/image.png" alt=""></p>
<p>이제 생성한 데이터베이스를 연결하고 싶다면 <code>\c 데이터베이스 이름</code>을 치면 해당 이름을 가진 데이터베이스에 연결된다.</p>
<h4 id="3-테이블-생성">3) 테이블 생성</h4>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/938387f6-0f43-4a80-812b-3ee7db74639c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/8e780f5f-3933-41ae-9646-2b3cfffd052c/image.png" alt=""></p>
<pre><code class="language-sql">CREATE TABLE 테이블 이름 (Column명 데이터타입, Column명 데이터타입, ...)</code></pre>
<p>위의 코드를 이용하여 테이블을 생성할 수 있다. 
테이블을 확인하고 싶다면 <code>SELECT * FROM 테이블명</code>을 이용하면 생성된 테이블을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/dyunge_100/post/80d881cd-7c69-48ba-a384-486574106125/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/59ba9d3c-ae45-4e0a-986e-fb2503183598/image.png" alt=""></p>
<p>cf) 주로 쓰이는 데이터 타입(Data Type, 자료형)</p>
<ul>
<li><p>Boolean </p>
<ul>
<li>BOOLEAN : 참과 거짓을 저장하는 자료형</li>
</ul>
</li>
<li><p>Character</p>
<ul>
<li><p>CHAR : 고정형 길이의 문자열 저장.</p>
</li>
<li><p>VARCHAR : 가변형 길이의 문자열 저장. 최대 길이는 지정해줄 수 있음.</p>
</li>
<li><p>TEXT : 대용량의 문자데이터 저장.</p>
</li>
</ul>
</li>
<li><p>Numeric </p>
<ul>
<li><p>INT : 정수형 데이터 저장, 크기는 4btye.</p>
</li>
<li><p>SMALLINT : 정수형 데이터를 저장하지만 크기가 2byte.</p>
</li>
<li><p>FLOAT : 실수형 데이터 저장, 크기는 8byte.</p>
</li>
<li><p>NUMERIC : NUMERIC(15,2)와 같이 전체 크기와 소수점 자리 지정 가능.</p>
</li>
</ul>
</li>
</ul>
<h4 id="4-insert-into-테이블명-values데이터-데이터-을-사용하여-테이블-안에-데이터를-넣어준다">4). <code>INSERT INTO 테이블명 VALUES(&#39;데이터&#39;, &#39;데이터&#39;, ...)</code>을 사용하여 테이블 안에 데이터를 넣어준다.</h4>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/c48b0716-243a-40fd-9add-ec17a0a66d90/image.png" alt=""></p>
<h3 id="22-dbeaver">2.2 DBeaver</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/79fdd35a-c0e0-4287-a1a0-625f11d8c8e3/image.png" alt=""></p>
<p><strong>DBeaver는 SQL 클라이언트이자 데이터베이스 관리 툴이다.</strong> 자바 애플리케이션이여서 JDBC API를 사용하여 JDBC 드라이버를 통해 데이터베이스와 통신한다. </p>
<blockquote>
<p>DBeaver의 주요 특징</p>
</blockquote>
<ul>
<li><p>Community Edition 버전을 사용하면 라이센스(Apache License)가 무료이다.</p>
</li>
<li><p>자바/이클립스 기반으로 개발되어서 윈도우, 리눅스, MAC에서 구동된다.</p>
</li>
<li><p>JDBC 기반으로 DB를 연결해서 엄청나게 많은 DBMS를 지원한다. (ORACLE, MySQL, Mariadb, Postgresql, Greenplum ... )</p>
</li>
<li><p>개발소스가 공개되어서 버그픽스가 가능하고 새로운 기능을 개발하여 사용이 가능하다.</p>
</li>
</ul>
<p>PostgreSQL을 편리하게 다루기 위해 이 관리 툴을 선택하여 사용하려고 한다.</p>
<ol>
<li>먼저 DBeaver를 다운로드 받고 설치한다.</li>
</ol>
<p><a href="https://dbeaver.io/download/">https://dbeaver.io/download/</a></p>
<ol start="2">
<li>DBeaver를 실행하고, <img src="https://velog.velcdn.com/images/dyunge_100/post/bdd67afc-cdec-4132-85d4-77707c0159b1/image.png" alt="">
파일 &gt;&gt; 새로 만들기 &gt;&gt; 데이터베이스 연결 &gt;&gt; PostgreSQL 선택 순으로 진행한다.</li>
</ol>
<ol start="3">
<li>그리고 비밀번호를 입력하면 생성했던 데이터베이스에 연결된다. 연결하고자 하는 Database가 따로 있다면 Database의 이름을 따로 적어줘야 한다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/4dac4420-be61-4c88-b815-b4bebb093949/image.png" alt=""></p>
<ol start="4">
<li>데이터베이스가 연결이 되었고 생성했던 테이블이 보인다.</li>
</ol>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/77a08b9f-f813-497a-aaaf-f0ab2c722294/image.png" alt=""></p>
<p>쿼리문을 실행할 경우
<img src="https://velog.velcdn.com/images/dyunge_100/post/6dd2056d-95c4-4536-8048-1dfadb66a9dc/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/47e96757-bfcc-4063-81a1-b6600b45fa87/image.png" alt=""></p>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://codecamp.tistory.com/2">https://codecamp.tistory.com/2</a>,
<a href="https://d2.naver.com/helloworld/227936">https://d2.naver.com/helloworld/227936</a>,
<a href="https://mangkyu.tistory.com/71">https://mangkyu.tistory.com/71</a>,
<a href="https://mozi.tistory.com/565">https://mozi.tistory.com/565</a>,
<a href="https://ko.wikipedia.org/wiki/PostgreSQL">https://ko.wikipedia.org/wiki/PostgreSQL</a>,</p>
</blockquote>
<p><a href="https://wylee-developer.tistory.com/39">https://wylee-developer.tistory.com/39</a>,</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 빌드 도구 Maven과 Gradle]]></title>
            <link>https://velog.io/@dyunge_100/Spring-%EB%B9%8C%EB%93%9C-%EB%8F%84%EA%B5%AC-Maven%EA%B3%BC-Gradle</link>
            <guid>https://velog.io/@dyunge_100/Spring-%EB%B9%8C%EB%93%9C-%EB%8F%84%EA%B5%AC-Maven%EA%B3%BC-Gradle</guid>
            <pubDate>Tue, 12 Apr 2022 05:10:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="0-자바의-빌드-도구">0. 자바의 빌드 도구</h2>
</blockquote>
<h3 id="01-빌드build란">0.1 빌드(Build)란?</h3>
<p>소스 코드 파일을 실제로 컴퓨터나 스마트폰에서 동작할 수 있는 독립적인 프로그램으로 만드는 과정을 일컫는다.</p>
<p>자바의 경우, 빌드 방식을 인터프리터 방식에서 JIT방식으로 변경하였다.</p>
<h3 id="02-빌드-도구란-무엇인가">0.2 빌드 도구란 무엇인가?</h3>
<p>빌드 도구란 소스 코드를 애플리케이션으로 변경하는데 있어 자동화를 해주는 툴(Tool)이자 프로그램이다. 
빌드 도구가 해주는 역할은 다음과 같다. </p>
<ul>
<li><p><strong>필요한 라이브러리들을 자동으로 추가해주고 동기화시켜준다.</strong></p>
</li>
<li><p><strong>프로젝트 생성부터 테스트까지 쉽게 다룰 수 있도록 만들어준다.</strong></p>
</li>
<li><p><strong>컴파일 및 빌드 자동화</strong></p>
</li>
</ul>
<p>자바에는 원래 &#39;Ant&#39;라는 툴이 있었지만 빌드의 과정을 이해하기 어렵거나 스크립트의 재사용성의 문제로 현재는 쓰고 있지 않다.</p>
<hr>
<h2 id="1-maven">1. Maven</h2>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/0601c97f-a4e7-4235-9c7b-9fb7ba520e45/image.png" alt=""></p>
<ul>
<li><p>프로젝트의 전체적인 사이클을 관리하며, Ant의 대안책으로 만들어졌다.</p>
</li>
<li><p>필요한 라이브러리를 pom.xml에 적으면 네트워크를 통해 자동으로 불러온다.</p>
</li>
<li><p>해당 라이브러리가 작동하는 데 필요한 다른 라이브러리들의 의존성도 관리한다. </p>
</li>
</ul>
<ul>
<li>아파치 라이센스로 배포되는 오픈소스 소프트웨어다.</li>
</ul>
<blockquote>
<h3 id="11-maven의-기본적인-폴더-구조">1.1 Maven의 기본적인 폴더 구조</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/2bf0cec9-6001-4261-962e-7a9794ae5bda/image.png" alt=""></p>
<ul>
<li><p>[src/main/java] : 기본적인 클래스나 인터페이스들을 저장하는 공간</p>
</li>
<li><p>[src/main/resources] : 스프링 설정에 관한 xml 파일들을 저장하고, DB 정보를 담고 있는 properties파일이나 static 파일, templates 파일이 들어있는 공간</p>
</li>
<li><p>[src/test/java] : 테스트 코드를 저장하는 공간</p>
</li>
<li><p>[JRE System Library] : 자바 표준 라이브러리를 저장하는 공간</p>
</li>
</ul>
</blockquote>
<blockquote>
<h3 id="12-maven에서-pomproject-object-modelxml이란">1.2 Maven에서 POM(Project Object Model).xml이란?</h3>
<p>여기서 POM(Project Object Model)이란 프로젝트의 다양한 정보를 처리하기 위한 객체 모델이다. </p>
<ul>
<li>1) 기본적인 구조</li>
</ul>
<pre><code class="language-xml">&lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot; 
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0  
http://maven.apache.org/maven-v4_0_0.xsd&quot;&gt;
   &lt;modelVersion&gt;4.0.0&lt;/modelVersion&gt;
   &lt;groupId&gt;com.blidkaga.group&lt;/groupId&gt;
   &lt;artifactId&gt;group-test&lt;/artifactId&gt;
   &lt;name&gt;test&lt;/name&gt;
   &lt;packaging&gt;war&lt;/packaging&gt;
   &lt;version&gt;1.0.0-SNAPSHOT&lt;/version&gt;
&lt;/project&gt;</code></pre>
<p><code>&lt;procject&gt;</code> : 루트 태그로 정해진 기본 정보를 기술한 태그</p>
<p><code>&lt;modelVersion&gt;</code> : POM 모델 버전을 알려주는 태그</p>
<p><code>&lt;groupId&gt;</code> : 그룹ID를 알려주는 태그로 제작자나 회사를 식별하기 위함</p>
<p><code>&lt;artifcatId&gt;</code> : 프로젝트의 고유 ID이며 프로젝트명을 알려주는 태그</p>
<p><code>&lt;version&gt;</code> : 프로그램 버전, 기본적으로 1.0-SNAPSHOT으로 설정됨</p>
<p><code>&lt;name&gt;</code> : 프로그램의 이름을 알려주는 태그</p>
<p><code>&lt;packaging&gt;</code> : 패키지 종류로 .jar, .zip, .war 등으로 지정하고, 주로 웹 애플리케이션에선 .war로 지정하는 경우가 많다.</p>
<p>2) 의존성 설정</p>
<pre><code>  &lt;properties&gt;
    &lt;java-version&gt;1.6&lt;/java-version&gt;
    &lt;org.springframework-version&gt;3.1.1.RELEASE&lt;/org.springframework-version&gt;
    &lt;org.aspectj-version&gt;1.6.10&lt;/org.aspectj-version&gt;
    &lt;org.slf4j-version&gt;1.6.6&lt;/org.slf4j-version&gt;
&lt;/properties&gt;
&lt;dependencies&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-context&lt;/artifactId&gt;
       &lt;version&gt;${org.springframework-version}&lt;/version&gt;
        &lt;exclusions&gt;
            &lt;exclusion&gt;
                &lt;groupId&gt;commons-logging&lt;/groupId&gt;
                &lt;artifactId&gt;commons-logging&lt;/artifactId&gt;
            &lt;/exclusion&gt;
        &lt;/exclusions&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.springframework&lt;/groupId&gt;
        &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;
        &lt;version&gt;${org.springframework-version}&lt;/version&gt;
        &lt;scope&gt;provided&lt;/scope&gt;
    &lt;/dependency&gt;
&lt;/dependencies&gt;</code></pre><p><code>&lt;properties&gt;</code> : maven 내부에서 반복적으로 사용되는 값들을 정의할 때 사용하는 태그 
예시) 해당 자바 버전을 선언 하고 dependencies에서 다음과 같이 활용이 가능 하다. </p>
</blockquote>
<pre><code class="language-xml">&gt; &lt;version&gt;${java.version}&lt;/version&gt;</code></pre>
<blockquote>
<p><code>&lt;dependencyManagement&gt;</code> : <code>dependencies</code> 태그보다 상위에 쓰며, 각 <code>&lt;dependency&gt;</code> 태그는 최소 3개의 메인 태그들(groupId, artifactId, version)을 가지고 있어야 한다. 선언적인 의미가 크며 직접적으로 종속성을 추가해주진 않음.</p>
<p><code>&lt;dependencies&gt;</code> : <code>&lt;dependency&gt;</code> 태그들의 리스트이며, 최소 2개 이상의 메인 태그들(groupId, artifactId)을 가지고 있어야 한다.</p>
<p><code>&lt;dependency&gt;</code> : 의존성 라이브러리의 정보를 추가해주는 곳이며, <code>&lt;scope&gt;</code> 태그는 해당 라이브러리가 이용되는 범위를 설정해줄 때 쓰인다.</p>
<p>3) 빌드 정보 </p>
<pre><code class="language-xml">&lt;build&gt;
        &lt;sourceDirectory&gt;src/main/java&lt;/sourceDirectory&gt;
 &lt;testSourceDirectory&gt;src/test/java&lt;/testSourceDirectory&gt;
 &lt;outputDirectory&gt;${project.basedir}/target/classes&lt;/outputDirectory&gt;
        &lt;resources&gt;
            &lt;resource&gt;
                &lt;directory&gt;src/main/resources&lt;/directory&gt;
                &lt;filtering&gt;true&lt;/filtering&gt;
            &lt;/resource&gt;
            &lt;resource&gt;
 &lt;directory&gt;resources-${deploy.phase}/&lt;/directory&gt;
                &lt;filtering&gt;true&lt;/filtering&gt;
            &lt;/resource&gt;
        &lt;/resources&gt;
        &lt;plugins&gt;
            &lt;plugin&gt;
                &lt;groupId&gt;org.apache.maven.plugins&lt;/groupId&gt;
                &lt;artifactId&gt;maven-compiler-plugin&lt;/artifactId&gt;
                &lt;version&gt;2.5.1&lt;/version&gt;
                &lt;configuration&gt;
                    &lt;source&gt;1.6&lt;/source&gt;
                    &lt;target&gt;1.6&lt;/target&gt;
                    &lt;compilerArgument&gt;-Xlint:all&lt;/compilerArgument&gt;
                    &lt;showWarnings&gt;true&lt;/showWarnings&gt;
                    &lt;showDeprecation&gt;true&lt;/showDeprecation&gt;
                &lt;/configuration&gt;
            &lt;/plugin&gt;
            &lt;/plugin&gt;
        &lt;/plugins&gt;
    &lt;/build&gt;</code></pre>
<p><code>&lt;build&gt;</code> : 빌드에 사용할 플러그인 목록들을 가지고 있으며, 원하는 형태의 파일로 빌드하기 위해 필요한 태그이다. 빌드 과정에 대한 정보를 담고 있다.</p>
<p>그 밖에도 의존성을 다운 받을 위치를 지정해주는 <code>&lt;repository&gt;</code> 태그와 maven plugin을 다운 받을 위치를 지정해주는 <code>&lt;PluginRepository&gt;</code> 태그 그리고 <code>deploy</code> goal을 실행했을 때 배포되는 위치를 기술하는 <distributionManagement> 태그도 있다.</p>
</blockquote>
<blockquote>
<h3 id="13-플러그인plugin과-라이프-사이클life-cycle">1.3 플러그인(Plugin)과 라이프 사이클(Life-Cycle)</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/4926ffc6-db3c-45ca-93fd-9833d75778ba/image.png" alt=""></p>
<p>플러그인(Plugin)이란 Maven의 가장 핵심적인 특성이다. 플러그인은 Goal(작업에 대한 명령)을 하나 이상 가지고 있고 이를 실행시키면 플러그를 콘센트에 꽂듯이 작업에 대한 명령을 수행에 옮긴다. </p>
<p>라이프 사이클(Life-Cycle)이란 메이븐이 빌드를 하는 과정을 미리 표준으로 정의한 순서를 말한다. 라이프 사이클의 각 단계를 페이즈(Phase)라고 부르며, 간단히 요약하자면 compile =&gt; test =&gt; package 순으로 진행된다.</p>
</blockquote>
<hr>
<h2 id="2-gradle">2. Gradle</h2>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/aec608f8-ed5a-486e-84f9-e33e23bce9bf/image.png" alt=""></p>
<ul>
<li><p>Ant의 장점을 가져오고 Groovy 기반 DSL로 만들어져, 기존 Ant의 역할과 배포 스크립트의 기능을 모두 사용한다.</p>
</li>
<li><p>JAVA뿐만 아니라 C/C++과 Python도 지원한다.</p>
</li>
<li><p>Maven에 비해 빌드 속도가 빠르다. </p>
</li>
<li><p>Build-by-convention : 스크립트 규모가 작고 읽기 쉽다.</p>
</li>
<li><p>Maven과 달리 <code>build.gradle</code> 파일로 여러 설정을 해준다.</p>
</li>
</ul>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://araikuma.tistory.com/447">https://araikuma.tistory.com/447</a>,
<a href="https://dev-coco.tistory.com/65">https://dev-coco.tistory.com/65</a>,
<a href="https://wikidocs.net/18340">https://wikidocs.net/18340</a>,
<a href="https://araikuma.tistory.com/447">https://araikuma.tistory.com/447</a>,
<a href="https://goddaehee.tistory.com/199">https://goddaehee.tistory.com/199</a>,
<a href="https://maven.apache.org/guides/introduction/introduction-to-plugins.html">https://maven.apache.org/guides/introduction/introduction-to-plugins.html</a>,
<a href="https://www.baeldung.com/maven-plugin">https://www.baeldung.com/maven-plugin</a>,
<a href="https://giles.tistory.com/12">https://giles.tistory.com/12</a>,
<a href="https://goddaehee.tistory.com/199">https://goddaehee.tistory.com/199</a>,
<a href="https://www.baeldung.com/maven-dependencymanagement-vs-dependencies-tags">https://www.baeldung.com/maven-dependencymanagement-vs-dependencies-tags</a>,
<a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html">https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html</a>,
<a href="https://stackoverflow.com/questions/2619598/differences-between-dependencymanagement-and-dependencies-in-maven/37280943#37280943">https://stackoverflow.com/questions/2619598/differences-between-dependencymanagement-and-dependencies-in-maven/37280943#37280943</a>,
<a href="https://salmonworld.tistory.com/139">https://salmonworld.tistory.com/139</a>,
<a href="https://sugerent.tistory.com/571">https://sugerent.tistory.com/571</a>,
<a href="https://jisooo.tistory.com/entry/Spring-%EB%B9%8C%EB%93%9C-%EA%B4%80%EB%A6%AC-%EB%8F%84%EA%B5%AC-Maven%EA%B3%BC-Gradle-%EB%B9%84%EA%B5%90%ED%95%98%EA%B8%B0">https://jisooo.tistory.com/entry/Spring-%EB%B9%8C%EB%93%9C-%EA%B4%80%EB%A6%AC-%EB%8F%84%EA%B5%AC-Maven%EA%B3%BC-Gradle-%EB%B9%84%EA%B5%90%ED%95%98%EA%B8%B0</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] Spring Container의 구동 원리와 설정 파일에 대한 설명]]></title>
            <link>https://velog.io/@dyunge_100/Spring-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EC%84%A4%EC%A0%95%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</link>
            <guid>https://velog.io/@dyunge_100/Spring-%EA%B8%B0%EB%B3%B8%EC%A0%81%EC%9D%B8-%EC%84%A4%EC%A0%95%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC</guid>
            <pubDate>Mon, 11 Apr 2022 09:36:18 GMT</pubDate>
            <description><![CDATA[<p>스프링 부트(Spring Boot)를 이용하면 xml파일을 따로 설정할 필요가 없지만, 기본적인 xml파일들에 대한 역할을 알아야 할 것 같아 정리하게 되었다.</p>
<blockquote>
<h2 id="0-들어가기-전">0. 들어가기 전</h2>
</blockquote>
<blockquote>
<h3 id="01-서블릿-컨테이너와-스프링-컨테이너의-차이점">0.1 서블릿 컨테이너와 스프링 컨테이너의 차이점</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/f6a12a00-9ff6-4059-b113-74467b5c731e/image.png" alt=""></p>
</blockquote>
<p>서블릿 컨테이너는 말 그대로 서블릿을 관리해주는 컨테이너(Container)다. 컨테이너(Container)라는 말 자체가 어떤 객체들을 관리해주는 의미이긴 하지만 스프링 컨테이너는 스프링 빈(Bean) 객체를 생성하거나 관리해주는 컨테이너이기도 하다. DispatcherServlet 또한 서블릿이긴 하나 서블릿 컨테이너가 보내는 요청을 맨 앞단에서 처리하는 Front Controller 역할을 할 뿐 스프링 컨테이너 안에 포함되어 있다.</p>
<p><strong>결론적으로 스프링 컨테이너도 컨테이너(Container)의 일종이긴 하나 스프링 빈(Bean) 객체를 다룸과 동시에 서블릿(Servlet)도 관리하는 컨테이너라고 할 수 있겠다.</strong></p>
<h3 id="02-들어가기-전에-알아둘-것">0.2 들어가기 전에 알아둘 것</h3>
<p>서블릿도 자바로 만들어진 하나의 클래스이다. 이 서블릿 객체를 생성하고 다루는 것은 서블릿 컨테이너(=WAS)이다. 이클립스에서 서블릿 클래스(ex. HttpServlet 등)를 상속 받아 개발하면 web.xml 파일에 자동으로 등록된다. </p>
<p>WAS는 구동하면 맨 처음 WEB-INF/web.xml 파일을 로딩하고, 그 설정에 맞게 웹 애플리케이션 설정을 구성하게 된다.</p>
<hr>
<blockquote>
<h2 id="1-스프링-컨테이너는-어떻게-동작하는가-by-webxml">1. 스프링 컨테이너는 어떻게 동작하는가? (by web.xml)</h2>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/0cda56e8-85fc-4dd6-b0df-be3baa7cfd40/image.png" alt=""></p>
</blockquote>
<ol>
<li><p>Web Application이 실행되면, WAS는 web.xml을 맨 처음 읽게 된다. 
web.xml 파일은 모든 서블릿 컨테이너에 대한 기본적인 설정과 정보를 가지고 있고, 들어온 모든 요청을 DispatcherServlet으로 가도록 한다.</p>
</li>
<li><p>web.xml에서 <code>&lt;context-param&gt;</code> 태그는 모든 서블릿과 필터가 공유하는 루트 스프링 컨테이너(= <strong>RootContext = ApplicationContext</strong>)를 정의하고, web.xml에 <code>&lt;listener&gt;</code> 태그에 등록된 ContextLoaderListener가 <strong>ApplicationContext.xml(또는 root-context.xml)</strong>에 따라 ApplicationContext를 생성한다. </p>
</li>
</ol>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;web-app version=&quot;2.5&quot; xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://Java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd&quot;&gt;

    &lt;!-- 첫번째 --&gt;
    &lt;context-param&gt;
        &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
        &lt;param-value&gt;/WEB-INF/spring/root-context.xml&lt;/param-value&gt;
    &lt;/context-param&gt;

    &lt;!-- 두번째 --&gt;
    &lt;listener&gt;
        &lt;listener-class&gt;org.springframework.web.context.ContextLoaderListener&lt;/listener-class&gt;
    &lt;/listener&gt;

    &lt;!-- 세번째 --&gt;
    &lt;servlet&gt;
        &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
        &lt;servlet-class&gt;org.springframework.web.servlet.DispatcherServlet&lt;/servlet-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;contextConfigLocation&lt;/param-name&gt;
            &lt;param-value&gt;/WEB-INF/spring/appServlet/servlet-context.xml&lt;/param-value&gt;
        &lt;/init-param&gt;
        &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;
    &lt;/servlet&gt;

    &lt;!-- 네번째 --&gt;
    &lt;servlet-mapping&gt;
        &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
        &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;
    &lt;/servlet-mapping&gt;

&lt;/web-app&gt;</code></pre>
<ol start="3">
<li><p>ApplicationContext.xml에 등록되어 있는 설정에 따라 스프링 컨테이너가 구동되고, 이 때 개발자가 작성한 비즈니스 로직, DAO, VO 등의 개체가 생성된다.</p>
</li>
<li><p>그 이후 요청이 오게 되면 서블릿 컨테이너에선 Heap영역에서 적절한 서블릿을 찾게 되고, 만약 없을 경우에는 새로 생성하여 DispatcherServlet에게 요청을 하게 된다. </p>
</li>
<li><p>그 이후 요청을 처리하는 과정은 다른 글에서 이미 정리했으므로 생략.</p>
</li>
</ol>
<p>결국 WAS(=Servlet Container)는 프로세스 하나에 배정되고, 그에 따라 웹 애플리케이션 하나(JVM)가 필요하다. 이에 요청 하나당 하나의 쓰레드가 형성되고, 이 요청들을 Thread별로 처리하도록 역할을 배정하는 것이 <strong>Thread Pool</strong>이라는 것이다. </p>
<hr>
<blockquote>
<h3 id="2-각-설정-파일에-대한-설명">2. 각 설정 파일에 대한 설명</h3>
</blockquote>
<blockquote>
<h4 id="1-webxml">1. web.xml</h4>
<p>WAS가 실행되면 최초로 실행되는 파일이다. 그 이유 또한 WAS(즉, Servlet Container)가 서블릿들을 생성하고 어떤 서블릿이 어떤 요청(Mapping)을 할 것인지 등에 대한 정보들을 가지고 있기 때문이다. </p>
</blockquote>
<blockquote>
<h4 id="2-applicationcontextxmlroot-contextxml">2. ApplicationContext.xml(=root-Context.xml)</h4>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans xmlns=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd&quot;&gt; 
  &lt;!-- Root Context: defines shared resources visible to all other web components --&gt;        
&lt;/beans&gt;</code></pre>
</blockquote>
<pre><code>&gt;
&gt;스프링에 의해 생성되는 Bean 객체들에 대한 **Spring DI Container**이다.(흔히 말하는 DI Container는 이것을 지칭한다. 또는 IoC Container라고도 하지만 엄밀히 따지면 IoC보단 DI가 좀 더 Container에 대한 역할과 일맥상통하다.) 
&gt;
&gt;스프링 컨테이너에는 두 가지 유형이 있는데 **BeanFactory** 컨테이너와 이를 상속한** ApplicationContext** 컨테이너이다. 
&gt;
&gt; - 1) **BeanFactory**는 가장 기본적인 컨테이너 기능만 제공하며, 클라이언트의 요청(LookUp)에 의해서만 Bean 객체가 생성된다.(Lazy Loading 방식)
&gt;
&gt; - 2) 반면에 **ApplicationContext**는 BeanFactory를 상속하여 Bean 객체 관리 기능 외에도 트랜잭션 관리 등의 다양한 기능을 제공한다.
&gt;
&gt;공통적으로 사용하는(=공유가 가능한) Bean들을 등록하는 Context이며, View와 관련이 없는 Repository(DAO)나 Service, DB 등과 같이 비즈니스 로직과 관련된 것들을 관리한다. 또한 컨테이너가 구동되는 시점에 바로 Bean 객체를 생성한다.(pre-loading 방식)
&gt;
&gt;ApplicationContext의 구현 클래스 중 하나인 **XmlWebApplicationContext**는 웹 기반의 스프링 애플리케이션을 개발할 때 가장 많이 쓰이며 직접 생성하지 않는 컨테이너이다. 


&gt; #### 3. Servlet-Context.xml
&gt;
&gt; ```xml
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans:beans xmlns=&quot;http://www.springframework.org/schema/mvc&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:beans=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd&quot;&gt;
    &lt;!-- DispatcherServlet Context: defines this servlet&#39;s request-processing infrastructure --&gt;
    &lt;!-- Enables the Spring MVC @Controller programming model --&gt;
    &lt;annotation-driven /&gt;
    &lt;!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --&gt;
    &lt;resources mapping=&quot;/resources/**&quot; location=&quot;/resources/&quot; /&gt;
    &lt;!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --&gt;
    &lt;beans:bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&gt;
        &lt;beans:property name=&quot;prefix&quot; value=&quot;/WEB-INF/views/&quot; /&gt;
        &lt;beans:property name=&quot;suffix&quot; value=&quot;.jsp&quot; /&gt;
    &lt;/beans:bean&gt;
    &lt;context:component-scan base-package=&quot;com.company.devpad&quot; /&gt;
&lt;/beans:beans&gt;</code></pre><blockquote>
<ul>
<li><p><code>&lt;annotation-driven&gt;</code> : @Controller 어노테이션을 감지하여 해당 클래스를 Controller로 등록할 수 있도록 해주는 태그 </p>
</li>
<li><p><code>&lt;resources&gt;</code> : 정적인 html문서 같은 웹 리소스들의 정보를 기술하는 태그 </p>
</li>
<li><p><code>&lt;beans:bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&gt;</code> : Controller가 <code>ModelAndView</code>를 return하고 DispatcherServlet이 <code>.jsp</code>파일을 찾을 때 쓰이는 정보를 적은 태그. &quot;home&quot;이라는 문자열을 반환하면 /WEB-INF/views/ 경로에서 접미사가 <code>.jsp</code>인 해당 파일을 찾는다. 
예시) <code>/WEB-INF/views/home.jsp</code></p>
</li>
<li><p><code>&lt;context:component-scan&gt;</code> : Java 파일의 @Component로 등록된 Bean 객체를 찾도록 해주는 태그 </p>
</li>
</ul>
<p>스프링 DI 컨테이너(또는 IoC 컨테이너라고 불리기도 하는)를 부모 Context로 사용하는 Context이다. 주로 View와 관련된 자원으로 구성되며, DispatcherServlet이 사용하는 컨트롤러와 관련된 Bean을 등록하고 관리하는 컨테이너이다.</p>
</blockquote>
<p><br><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p>책&lt;스프링 퀵 스타트&gt;,
<a href="https://velog.io/@cateto/Spring-ApplicationContext.xml-%EC%99%80-ServletContext.xml">https://velog.io/@cateto/Spring-ApplicationContext.xml-%EC%99%80-ServletContext.xml</a>,
<a href="https://devpad.tistory.com/24">https://devpad.tistory.com/24</a>,
<a href="https://jypthemiracle.medium.com/servletcontainer%EC%99%80-springcontainer%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%B8%EA%B0%80-626d27a80fe5">https://jypthemiracle.medium.com/servletcontainer%EC%99%80-springcontainer%EB%8A%94-%EB%AC%B4%EC%97%87%EC%9D%B4-%EB%8B%A4%EB%A5%B8%EA%B0%80-626d27a80fe5</a>,
<a href="https://jeong-pro.tistory.com/222">https://jeong-pro.tistory.com/222</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[DB] MyBatis]]></title>
            <link>https://velog.io/@dyunge_100/DB-MyBatis</link>
            <guid>https://velog.io/@dyunge_100/DB-MyBatis</guid>
            <pubDate>Fri, 08 Apr 2022 00:34:49 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="1-mybatis란">1. Mybatis란?</h2>
</blockquote>
<p><img src="https://velog.velcdn.com/cloudflare/dyunge_100/8c67fced-55d3-4d6b-8549-5062276b434f/image.png" alt=""></p>
<p><strong>JDBC API와 고급 Mapping을 지원하여 Java코드 안에서 SQL문을 분리해주게 만드는 프레임워크다.</strong> 
분리한 SQL문은 XML파일에 작성하고, 이를 메서드와 Mapping하여 중복 코드를 줄여주고 가독성을 좋게 만들어 준다.</p>
<blockquote>
<h2 id="2-mybatis-특징">2. Mybatis 특징</h2>
</blockquote>
<ul>
<li><p>1) <strong>Mybatis-Spring</strong>은 <strong>Mybatis3</strong>와 <strong>Spring 연동 라이브러리</strong>로 제공된다.</p>
</li>
<li><p>2) <strong>싱글톤(Singleton)패턴</strong>으로 스프링 빈으로 등록하여 의존성 주입(DI)이 용이하다.</p>
</li>
<li><p>3) <strong>Mybatis Mapper Interface를 통해 DB에 접근한다.</strong></p>
</li>
<li><p>4) 객체 프로퍼티로 파라미터와 결과를 객체(DTO, Map) 등으로 자동 Mapping을 지원한다.</p>
</li>
<li><p>5) Spring 연동 모듈을 제공하기 때문에 설정이 간단하다.</p>
</li>
<li><p>6) 트랜잭션을 관리해주기 때문에 쉽게 설정이 가능하다.</p>
</li>
</ul>
<blockquote>
<h2 id="3-mybatis의-주요-구성-요소와-액세스-과정">3. Mybatis의 주요 구성 요소와 액세스 과정</h2>
</blockquote>
<h3 id="31-mybatis의-주요-구성-요소">3.1 Mybatis의 주요 구성 요소</h3>
<table>
<thead>
<tr>
<th>구성 요소 / 구성 파일</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>Mybatis Configuration File</td>
<td>Mybatis3의 작업 설정을 설명하는 XML파일이다.<br> 데이터베이스의 연결 대상, 매핑 파일의 경로, Mybatis3의 작업 설정 등과 같은 세부 사항을 설정한다.</td>
</tr>
<tr>
<td>SqlSessionFactroyBuilder<br>(org.apache.ibatis.session.SqlSessionFactoryBuilder)</td>
<td>Mybatis 구성 파일을 읽고 생성하는 SqlSessionFactory의 구성요소이다.<br>이 구성 요소는 Spring과 통합되어 사용할 때 애플리케이션 클래스에서 직접 처리하진 않는다.</td>
</tr>
<tr>
<td>SqlSessionFactory<br>(org.apache.ibatis.session.SqlSession)</td>
<td>SQL 실행 및 트랜잭션 제어를 위한 API를 제공하는 구성 요소이다.<br>Mybatis를 사용하여 데이터베이스에 액세스 할 때 필요한 요소이다.</td>
</tr>
<tr>
<td>Mapper Interface</td>
<td>Mapping 파일에 정의된 SQL을 호출하는 인터페이스이다.<br>Mybatis는 Mapper 인터페이스에 대한 구현 클래스를 자동으로 생성하므로 개발자는 인터페이스만 생성하면 된다.</td>
</tr>
</tbody></table>
<h3 id="3-2-mybatis3의-데이터베이스-액세스access-과정">3-2. Mybatis3의 데이터베이스 액세스(Access) 과정</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/6305c2a1-2b33-4c63-b6b7-fdd81cf4b6eb/image.png" alt=""></p>
<p>위에는 액세스 과정을 간략화한 것이다.</p>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/b271d499-511d-4f31-a855-be694da98c1d/image.png" alt=""></p>
<ul>
<li><ol start="0">
<li>JDBC API를 이용하여 데이터베이스로부터 <code>Connection</code> 객체를 얻어오기 위해 데이터베이스와의 물리적인 연결을 지원하는 <strong>DataSource</strong>가 필요하다.(<code>SqlSessionFactoryBean</code>클래스의 <code>setDataSource()</code> 메서드에 의해 쓰여진다.)
따라서 아래와 같이 <code>application.properties</code> 파일에 spring.datasource.* 패턴으로 <strong>Datasource</strong>를 설정한다.
<img src="https://velog.velcdn.com/images/dyunge_100/post/fdccb19b-ea77-458a-91ce-8cb95d4ce3e5/image.png" alt="">
그 외에도 dependency 설정과 Mybatis <code>Config</code> 파일 설정을 완료한 채 진행한다.</li>
</ol>
</li>
</ul>
<br>

<p>(1) ~ (3)은 애플리케이션 시작할 시 수행되는 프로세스다.</p>
<ul>
<li><ol>
<li>애플리케이션이 <code>SqlSessionFactoryBuilder</code>를 통해 <code>SqlSessionFactory</code>를 빌드하도록 요청한다.</li>
</ol>
</li>
<li><ol start="2">
<li><code>SqlSessionFactoryBuilder</code>는 <code>SqlSessionFactory</code>를 생성하기 위한 Mybatis <code>Config</code> 파일을 읽고,</li>
</ol>
</li>
<li><ol start="3">
<li><code>Config</code> 파일에 따라 <code>SqlSessionFactory</code>를 생성한다.</li>
</ol>
</li>
</ul>
<p>(4) ~ (10)은 클라이언트의 각 요청에 대해 수행되는 프로세스다.</p>
<ul>
<li><ol start="4">
<li>클라이언트가 웹 애플리케이션에 요청을 보낸다.</li>
</ol>
</li>
<li><ol start="5">
<li>애플리케이션은 <code>SqlSessionFactoryBuilder</code>를 사용하여 빌드된 <code>SqlSessionFactory</code>에서 <code>SqlSession</code>을 가져오도록 명령한다.</li>
</ol>
</li>
<li><ol start="6">
<li><code>SqlSessionFactory</code>는 <code>SqlSession</code>를 생성하고 이를 애플리케이션에 반환한다.</li>
</ol>
</li>
<li><ol start="7">
<li>애플리케이션이 <code>SqlSession</code>에서 <code>Mapper</code> 인터페이스의 구현 객체를 가져오고,</li>
</ol>
</li>
<li><ol start="8">
<li>애플리케이션이 <code>Mapper</code> 인터페이스 메서드를 호출한다.</li>
</ol>
</li>
<li><ol start="9">
<li><code>Mapper</code> 인터페이스의 구현 객체가 <code>SqlSession</code> 메서드를 호출하고 SQL 실행을 요청한다.</li>
</ol>
</li>
<li><ol start="10">
<li><code>SqlSession</code>은 <code>Mapping</code> 파일에서 실행할 SQL을 가져와 실행한다.</li>
</ol>
</li>
</ul>
<blockquote>
<h2 id="4-mybatis-spring">4. Mybatis-Spring</h2>
</blockquote>
<h3 id="41-mybatis-spring의-컴포넌트-구조">4.1 Mybatis-Spring의 컴포넌트 구조</h3>
<table>
<thead>
<tr>
<th>구성 요소 / 구성 파일</th>
<th>설명</th>
</tr>
</thead>
<tbody><tr>
<td>SqlSessionFactoryBean<br>(org.mybatis.spring.SqlSessionFactoryBean)</td>
<td>SqlSessionFactory를 작성하고 Spring DI 컨테이너에 객체를 저장하는 구성 요소. <br> SqlSessionFactoryBean을 사용하면 Mybatis Config 파일이 없어도 SqlSessionFactory를 빌드할 수 있다.</td>
</tr>
<tr>
<td>MapperFactoryBean<br>(org.mybatis.spring.mapper.MapperFactoryBean)</td>
<td>싱글톤 Mapper 객체를 만들고 Spring DI 컨테이너에 저장하는 구성 요소. Mybatis3 표준 매커니즘에 의해 생성된 Mapper 객체는 쓰레드에 안전하지 않아 각 쓰레드에 대한 인스턴스를 할당해야 한다.</td>
</tr>
<tr>
<td>SqlSessionTemplate<br>(org.mybatis.spring.SqlSessionTemplate)</td>
<td>SqlSession 인터페이스를 구현하는 싱글톤 버전의 SqlSession 구성 요소.</td>
</tr>
</tbody></table>
<h3 id="42--mybatis-spring의-데이터베이스-액세스access-과정">4.2  Mybatis-Spring의 데이터베이스 액세스(Access) 과정</h3>
<p><img src="https://velog.velcdn.com/images/dyunge_100/post/7546446a-092f-4236-a277-0cf253f8ac44/image.png" alt=""></p>
<p>(1)~(4)은 응용 프로그램 시작시 수행되는 과정이다.</p>
<ul>
<li><ol>
<li><code>SqlSessionFactoryBean</code>은 <code>SqlSessionFactoryBuilder</code>를 통해 <code>SqlSessionFactory</code>를 빌드하도록 요청한다.</li>
</ol>
</li>
<li><ol start="2">
<li><code>SessionFactoryBuilder</code>는 <code>SqlSessionFactory</code> 생성을 위해 <code>MyBatis Config</code> 파일을 읽는다. </li>
</ol>
</li>
<li><ol start="3">
<li><code>SqlSessionFactoryBuilder</code>는 <code>MyBatis Config</code> 파일의 정의에 따라 <code>SqlSessionFactory</code>를 생성한다. 생성된 <code>SqlSessionFactory</code>는 Spring DI 컨테이너에 의해 저장된다.</li>
</ol>
</li>
<li><ol start="4">
<li><code>MapperFactoryBean</code>은 <code>SqlSession(SqlSessionTemplate)</code> 및 <code>Mapper</code> 객체(<code>Mapper</code> 인터페이스의 프록시 객체)를 생성한다. 
생성되는 <code>Mapper</code> 객체는 스프링 DI 컨테이너에 의해 저장되며, Service 클래스 등에 DI가 적용된다. <code>Mapper</code> 객체는 안전한 <code>SqlSession(SqlSessionTemplate)</code>을 사용하여 쓰레드에 대해 안전한 구현을 제공한다.</li>
</ol>
</li>
</ul>
<p>(5)~(11)은 클라이언트의 각 요청에 대해 수행되는 과정이다.</p>
<ul>
<li><ol start="5">
<li>클라이언트가 애플리케이션에 대해 요청을 하면</li>
</ol>
</li>
<li><ol start="6">
<li>애플리케이션은 DI 컨테이너에서 주입한 <code>Mapper</code> 인터페이스를 호출한다. </li>
</ol>
</li>
<li><ol start="7">
<li><code>Mapper</code>는 호출된 메소드에 해당하는 <code>SqlSession</code> 메소드를 호출한다.</li>
</ol>
</li>
<li><ol start="8">
<li><code>SqlSession(SqlSessionTemplate)</code>은 프록시 사용 및 쓰레드에 대해 안전한 <code>SqlSession</code> 메서드를 호출한다.</li>
</ol>
</li>
<li><ol start="9">
<li><code>SqlSession</code>은 트랜잭션에 할당된 Mybatis3 표준 <code>SqlSession</code>을 사용한다. 트랜잭션에 할당된 <code>SqlSession</code>이 존재하지 않는 경우, <code>SqlSessionFactory</code> 메서드를 호출하여 표준 Mybatis3의 <code>SqlSession</code>을 가져온다.</li>
</ol>
</li>
<li><ol start="10">
<li><code>SqlSessionFactory</code>는 Mybatis3 표준 <code>SqlSession</code>을 반환한다. 반환된 <code>SqlSession</code>이 트랜잭션에 할당되기 때문에 동일한 트랜잭션 내에 있는 경우, 새 <code>SqlSession</code>을 생성하지 않고 동일한 <code>SqlSession</code>을 재사용한다.</li>
</ol>
</li>
<li><ol start="11">
<li><code>On</code> 메서드를 호출하고 SQL 실행을 요청하고, <code>SqlSession</code>은 <code>Mapping</code> 파일에서 실행할 SQL을 가져와 실행한다.</li>
</ol>
</li>
</ul>
<blockquote>
<h2 id="5-mapper와-mapperscan-어노테이션">5. @Mapper와 @MapperScan 어노테이션</h2>
</blockquote>
<p><code>@Mapper</code>는 Mapper 등록을 위한 인터페이스에 선언하여 사용한다.</p>
<p>cf) 참고로 Mybatis3부터 mapper.xml 대신 interface 클래스의 Annotation을 통해 SQL을 사용할 수 있다.
<code>@Mapper</code> 어노테이션은 Spring DI 컨테이너에 Bean으로 등록하고, 등록한 해당 인터페이스의 SQL Annotation(<code>@Select</code>, <code>@Insert</code> 등)을 토대로 실제 SQL문을 실행시켜준다.</p>
<p>이 때 매개변수를 받아올 때, <code>@Param(&quot; &quot;)</code>을 통해 값을 명시하면 된다. 또 동적바인딩을 하고 싶다면 <code>#{ }</code>를 이용하면 된다.</p>
<pre><code class="language-java">@Mapper
public interface UserMapper {

    @Select(&quot;SELECT * FROM user&quot;)
    List&lt;User&gt; findAll();

    @Select(&quot;SELECT * FROM user WHERE userIdx = #{userIdx}&quot;)
    User findByUserIdx(@Param(&quot;userIdx&quot;) int userIdx);
}</code></pre>
<p>위의 예시는 <code>@Mapper</code>를 활용한 예시이다.</p>
<p><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p><a href="https://khj93.tistory.com/entry/MyBatis-MyBatis%EB%9E%80-%EA%B0%9C%EB%85%90-%EB%B0%8F-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC">https://khj93.tistory.com/entry/MyBatis-MyBatis%EB%9E%80-%EA%B0%9C%EB%85%90-%EB%B0%8F-%ED%95%B5%EC%8B%AC-%EC%A0%95%EB%A6%AC</a>,
<a href="https://jung-story.tistory.com/121">https://jung-story.tistory.com/121</a>,</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Spring] 스프링 프레임워크(Spring Framework)의 특징과 구조]]></title>
            <link>https://velog.io/@dyunge_100/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACSpring-Framework%EC%9D%98-%ED%8A%B9%EC%A7%95%EA%B3%BC-%EA%B5%AC%EC%A1%B0</link>
            <guid>https://velog.io/@dyunge_100/Spring-%EC%8A%A4%ED%94%84%EB%A7%81-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%ACSpring-Framework%EC%9D%98-%ED%8A%B9%EC%A7%95%EA%B3%BC-%EA%B5%AC%EC%A1%B0</guid>
            <pubDate>Fri, 08 Apr 2022 00:34:35 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h2 id="0-스프링-프레임워크spring-framework란">0. 스프링 프레임워크(Spring Framework)란?</h2>
</blockquote>
<p><strong>동적 웹 사이트 개발을 위한 자바 플랫폼의 오픈 소스 애플리케이션 프레임워크</strong>다.
EJB를 사용할 때 알아야만 했던 수많은 디자인 패턴을 신경 쓸 필요없다. 스프링 프레임워크 그 자체로 이미 많은 디자인 패턴이 적용되어 배포되므로 스프링을 사용하는 것 자체가 디자인 패턴을 사용하는 것이다.</p>
<blockquote>
<h2 id="1-spring-framework의-특징">1. Spring Framework의 특징</h2>
<p>스프링은 &quot;IoC와 AOP를 지원하는 경량의 컨테이너 프레임워크&quot;다.</p>
</blockquote>
<ul>
<li>1) <strong>경량적</strong>이다.</li>
</ul>
<p>스프링은 여러 개의 모듈로 구성되어 있는 <strong>모듈식 프레임워크</strong>이다. 각 모듈은 하나 이상의 JAR 파일로 구성되어 있어 쉬운 개발과 실행이 가능하다. 또한 <strong>POJO(평범한 옛날 자바 객체, Plain Old Java Object)</strong> 형태로 객체를 관리해서 단순하고 가볍다.</p>
<ul>
<li>2) <strong>제어의 역행(IoC, Inversion of Control)</strong>과 <strong>의존성 주입(DI, Dependency Injection)</strong></li>
</ul>
<p>스프링은 <strong>IoC</strong>를 통해 애플리케이션을 구성하는 객체 간의 낮은 결합도를 유지한다. IoC는 말 그대로 개발자가 직접 생성하거나 제어하는 것이 아닌 스프링의 <strong>Spring Bean</strong>모듈에서 객체를 생성하고 제어하며 관리하는 특징을 잘 설명해준다. (Bean 인스턴스를 생성해주는 곳은 <strong>Bean Factory</strong>라고 불린다.)</p>
<pre><code class="language-java">// 기존 Java
public class TV {
    private Speaker speaker;

    public TV(Speaker speaker) {
        this.speaker = speaker;
    }
}

// Spring
@Component
public class TV {

    @Autowired
    private Speaker speaker;
}</code></pre>
<p><strong>DI</strong>는 객체 간의 의존성을 크게 줄여준다는 것에서 의미가 있다. 객체 간의 의존성이 줄어든다는 것은 그만큼 유지 보수를 할 때 손이 많이 가는 것을 줄여준다는 의미이기도 하다.</p>
<ul>
<li>3) <strong>관점 지향 프로그래밍(AOP, Aspect Oriented Programming)</strong></li>
</ul>
<p>스프링은 비즈니스 메서드를 개발할 때 사용하는 공통 로직을 외부의 독립된 클래스로 분리하여, 해당 기능을 프로그램 코드에 직접 명시하지 않고 선언적으로 처리할 수 있다. 이로 인해 응집도가 높은 비즈니스 컴포넌트를 만들 수 있으며, 유지 보수 또한 높일 수 있다. OOP의 문제점 또한 보완할 수 있다.</p>
<ul>
<li>4) <strong>컨테이너(Container)</strong></li>
</ul>
<p>컨테이너는 특정 객체의 생성과 관리를 담당하고 객체 운용에 필요한 다양한 기능을 제공한다. 대표적으로 Servlet과 Servlet Container가 그 예인데, Servlet 객체를 생성하고 생명 주기를 관리해주는 게 Servlet Container라는 맥락에서 스프링 또한 애플리케이션의 운용에 필요한 객체의 생성과 의존 관계를 관리한다는 점에서 일종의 컨테이너라고 할 수 있다. </p>
<br>

<blockquote>
<h2 id="2-spring-framework의-구조">2. Spring Framework의 구조</h2>
<p><img src="https://imagedelivery.net/v7-TZByhOiJbNM9RaUdzSA/4064615f-ec88-481a-5d96-fcb78740b700/public" alt=""></p>
</blockquote>
<ul>
<li><h3 id="1-core-container">1. Core Container</h3>
<p>서블릿의 생명 주기를 관리하는 서블릿 컨테이너와 비슷하게 bean의 생성과 관리를 해주는 container 역할을 한다.</p>
<ul>
<li><h4 id="1-spring-core">1) Spring Core</h4>
<p>Core 모듈은 DI와 Ioc 패턴을 적용할 수 있는 기본적인 스프링 프레임워크 클래스들을 포함하고 있다. 어떤 타입의 스프링 애플리케이션을 빌드하든 항상 직간접적으로 이 Spring Core에 대한 종속성을 가진다. </p>
</li>
<li><h4 id="2-spring-bean">2) Spring Bean</h4>
<p>Bean 모듈은 모든 bean 객체들의 생명 주기를 관리한다. Spring Bean이 갖고 있는 Bean Factory는 bean 인스턴스를 생성하거나 bean의 의존성 문제를 해결하는 역할을 담당하고 있다.</p>
</li>
<li><h4 id="3-spring-context">3) Spring Context</h4>
<p>Spring Context는 Bean 객체들의 의존성 주입을 담당한다. 대부분의 경우 Spring 애플리케이션이 실행할 때, Spring Context 모듈은 실행되며 ApplicationContext로 불린다. (흔히 ApplicationContext.xml에 bean을 등록하여 의존성 주입해주는 역할을 해주는 모듈이라고 생각하면 편하다.)</p>
</li>
<li><h4 id="4-spelspring-expression-language">4) SpEL(Spring Expression Language)</h4>
<p>Runtime동안 object graph를 쿼링(querying)하고 실행하는데 도움을 준다.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li><h3 id="2-data-accessintegration">2. Data Access/Integration</h3>
<p>데이터베이스, XML 또는 Messaging을 포함한 다양한 형태의 데이터에 접근하기 용이하도록 하는 모듈들의 모음이다.</p>
<ul>
<li><h4 id="1-spring-jdbc">1) Spring JDBC</h4>
<p>Spring JDBC는 Java JDBC API에 대한 추상화를 제공한다. 이러한 추상화와 함께 JdbcTemplate 또한 제공하여 데이터에 쉽게 접근 가능하도록 한다.</p>
</li>
<li><h4 id="2-spring-orm">2) Spring ORM</h4>
<p>Spring은 Hibernate, JPA와 같이 유명한 ORM 프레임워크를 제공해준다.</p>
</li>
<li><h4 id="3-spring-transactions">3) Spring Transactions</h4>
<p>Spring Transactions Management API는 데이터베이스 뿐만 아니라 객체의 트랜잭션을 균일하게 관리해준다. 뿐만 아니라 프로그래밍 방식과 선언적 트랜잭션 관리를 모두 지원해준다.</p>
</li>
</ul>
</li>
</ul>
<ul>
<li><h3 id="3-web">3. Web</h3>
<p>Web Application을 빌드할 때 사용하는 컴포넌트이다.</p>
<ul>
<li><h4 id="1-spring-web">1) Spring Web</h4>
<p>multipart file을 업로드하거나 IoC 컨테이너를 초기화 하는 등 기초적인 웹(Web)에 대한 부분들을 관리한다.</p>
</li>
<li><h4 id="2-spring-web-servlet">2) Spring Web Servlet</h4>
<p>Web Servlet 모듈은 웹 애플리케이션 실행을 위한 MVC 구현이 포함되어 있다. </p>
</li>
<li><h4 id="3-spring-web-sockets">3) Spring Web Sockets</h4>
<p>웹 애플리케이션에서 Web Sockets(웹 소켓)이란 클라이언트와 서버를 이어주는 터널이라고 생각하면 되는데 Spring Web Sockets은 이러한 Web Sockets을 구축하는데 도움을 준다.</p>
</li>
</ul>
</li>
</ul>
<p>그 밖에도 AOP, Aspects, Instrument, Test 그리고 Messaging 등과 구조로 나누어 볼 수 있다.</p>
<blockquote>
<h2 id="3-spring-framework의-동작-과정">3. Spring Framework의 동작 과정</h2>
<p><img src="https://imagedelivery.net/v7-TZByhOiJbNM9RaUdzSA/4230a410-6e85-44bb-8fa4-071ea0758800/public" alt=""></p>
<p><img src="https://imagedelivery.net/v7-TZByhOiJbNM9RaUdzSA/c5f015e7-e650-45b9-0a60-37b7b2fa4f00/public" alt=""></p>
</blockquote>
<h4 id="1-클라이언트가-요청을-보내면-dispatcherservlet가-가로챈다">1. 클라이언트가 요청을 보내면 DispatcherServlet가 가로챈다.</h4>
<p>클라이언트가 보낸 HTTP 요청을 보낼 때 아무 요청이나 가로채는 것은 아니고, web.xml의 <url-pattern>에 등록된 내용을 토대로 가로채게 된다.</p>
<pre><code class="language-xml">&lt;servlet-mapping&gt;
    &lt;servlet-name&gt;appServlet&lt;/servlet-name&gt;
    &lt;url-pattern&gt;*.do&lt;/url-pattern&gt;
&lt;/servlet-mapping&gt;</code></pre>
<p>위의 <code>&lt;url-pattern&gt;</code> 안에 있는대로 .do가 붙어야 한다. &#39;<a href="http://localhost8080/post/view.do&#39;%EC%B2%98%EB%9F%BC">http://localhost8080/post/view.do&#39;처럼</a> 지정한 패턴이 web.xml에 들어있는 경우, DispatcherServlet은 요청을 가로채게 된다.</p>
<h4 id="2-가로챈-요청을-handlermapping에게-보내-해당-요청을-수행할-controller를-찾는다">2. 가로챈 요청을 HandlerMapping에게 보내 해당 요청을 수행할 Controller를 찾는다.</h4>
<pre><code class="language-java">@Controller
class HomeController {

    @RequestMapping(value = &quot;/post/view&quot;)
    public String view() {
        return &quot;&quot;;
    }
}</code></pre>
<p>@Controller 어노테이션을 붙이면 Servlet-Context.xml에서는 이를 인식하여 Controller로 등록한다. HandlerMapping은 DispatcherServlet으로부터 요청을 전달받고, 해당 요청을 수행할 Controller를 찾는다. 수행할 Controller를 찾았다면 이번에는 HandlerAdapter가 Controller의 Method(@RequestMapping)를 인식하고 찾아가게 된다. </p>
<h4 id="3-실제-요청-처리">3. 실제 요청 처리</h4>
<pre><code class="language-java">@Controller
public class HomeController {

    @RequestMapping(value = &quot;/post/view&quot;)
    public String view() {

        // DB에서 포스팅 정보를 가져왔다는 가정한다.
        String title = &quot;DB에서 조회한 포스팅 제목&quot;;
        String content = &quot;DB에서 조회한 포스팅 내용&quot;;

        return &quot;home&quot;;
    }
}  </code></pre>
<p>Controller의 해당 Method에선 비즈니스 로직을 처리하게 되고 DB를 연동하는 클래스인 DAO를 따라 DB로부터 값을 가져온다. </p>
<h4 id="4-viewresolver를-통해-view-화면을-찾는다">4. ViewResolver를 통해 View 화면을 찾는다.</h4>
<pre><code class="language-java">@Controller
public class HomeController {

    @RequestMapping(value = &quot;/post/view&quot;)
    public String view() {

        // DB에서 포스팅 정보를 가져왔다는 가정한다.
        String title = &quot;DB에서 조회한 포스팅 제목&quot;;
        String content = &quot;DB에서 조회한 포스팅 내용&quot;;

        model.addAttribute(&quot;title&quot;, title);
        model.addAttribute(&quot;content&quot;, content);

        return &quot;home&quot;;
    }
}</code></pre>
<p>Model 객체를 이용하여 addAttribute 함수를 통해 화면에 보여줄 값들을 세팅하고 이를 return해준다. 이 때, &quot;home&quot;이라는 문자열은 Servlet-Context.xml에 설정된 prefix와 suffix 정보를 참조하여 /WEB-INF/views/home.jsp 파일을 찾는 정보를 제공한다. </p>
<p>Controller는 View와 View에 전달할 Model 객체를 DispatcherServlet으로 반환한다. ViewResolver는 Controller가 보내준 View의 이름을 토대로 View 화면을 찾게 된다. </p>
<h4 id="5-viewresolver가-찾은-view화면을-view로-보내주면-view는-처리-결과를-dispatcherservlet에-보내고-dispathcerservlet은-클라이언트에게-최종-결과를-보내준다">5. ViewResolver가 찾은 View화면을 View로 보내주면 View는 처리 결과를 DispatcherServlet에 보내고, DispathcerServlet은 클라이언트에게 최종 결과를 보내준다.</h4>
<pre><code class="language-jsp">&lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot;%&gt;
&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=utf-8&quot; pageEncoding=&quot;utf-8&quot;%&gt;
&lt;html&gt;
    &lt;body&gt;
        &lt;h1&gt;${title}&lt;/h1&gt;

        &lt;P&gt;${content}&lt;/P&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>View화면(=home.jsp파일)은 Model 객체를 넘겨받고 그 Model 객체 안의 속성 값들을 ${} 기호에 표현된 부분으로 치환한다. 클라이언트는 처리가 모두 완료된 동적 웹 페이지를 최종적으로 넘겨 받게 된다.</p>
<p><br><br><br></p>
<blockquote>
<h3 id="link">Link</h3>
<p>책 &lt;스프링 퀵 스타트&gt;,
<a href="https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/html/overview.html">https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/html/overview.html</a>,
<a href="https://velog.io/@duckchanahn/Spring-%EC%9D%B4%EB%A1%A0%EC%A0%95%EB%A6%AC">https://velog.io/@duckchanahn/Spring-%EC%9D%B4%EB%A1%A0%EC%A0%95%EB%A6%AC</a>,
<a href="https://www.amitph.com/spring-framework-architecture/">https://www.amitph.com/spring-framework-architecture/</a>,
<a href="https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/html/overview.html">https://docs.spring.io/spring-framework/docs/4.0.x/spring-framework-reference/html/overview.html</a>,
<a href="https://devpad.tistory.com/24">https://devpad.tistory.com/24</a>,  <a href="https://intro0517.tistory.com/151">https://intro0517.tistory.com/151</a>,</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>