<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>주독야독</title>
    <link>https://hulrud.tistory.com/</link>
    <description>나와 같은 궁금증을 가진 사람들을 위해 오늘도!  </description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 23:04:26 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>hurlud</managingEditor>
    <image>
      <title>주독야독</title>
      <url>https://tistory1.daumcdn.net/tistory/5890278/attach/a6afe83b8972475e9b80c394d35a2341</url>
      <link>https://hulrud.tistory.com</link>
    </image>
    <item>
      <title>[SpringBatch] 스프링 배치란?</title>
      <link>https://hulrud.tistory.com/114</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;스프링 배치와 배치 프로그램에 대한 개념 위주로 서술한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fcfcfc; color: #000000; text-align: left;&quot;&gt;  이런 분들이 읽으면 좋아요!&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;배치 프로그램이 뭔지 몰라요&lt;/li&gt;
&lt;li&gt;스프링 배치를 처음 들어봤어요&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Batch&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배치 프로그램이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 프로그램은 &lt;b&gt;대량의 데이터를 정해진 주기나 조건에 따라 자동으로 처리하는 프로그램&lt;/b&gt;입니다. 웹 애플리케이션처럼 사용자가 요청을 보냈을 때 바로 요청을 처리하는 것이 아니라, &lt;b&gt;요청을 일괄적으로 묶어서 한 번에 처리(batch)합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 프로그램은 반복적인 작업 처리를 해야 할 때 쓰입니다. 예를 들어 매일 새벽마다 데이터를 백업하거나, 매주 특정 시간에 보고서를 생성하는 등의 작업을 배치 프로그램을 통해 처리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 배치 프로그램은 백그라운드에서 실행되기 때문에 사용자가 실시간으로 신경쓰고 있지 않아도 시스템이 뒤에서 작업을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배치 프로그램과 스케쥴러&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 개념을 보고 배치 프로그램 = 스케줄러 라고 생각하시는 분들도 계실 것 같습니다. 스케쥴러(Scheduler)는 배치 프로그램과는 다른 개념입니다. 스케줄러는 단순히 &lt;b&gt;작업의 실행 시점을 제어&lt;/b&gt;하는 도구입니다. 즉, 특정 시간에 작업을 실행하도록 예약해주는 역할이 스케줄러 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스케줄러는 배치와는 다르게&amp;nbsp;&lt;b&gt;작업을 직접 처리하지 않으며,&amp;nbsp;&lt;/b&gt;배치 프로그램과 같은 처리를 담당하는 프로그램을 실행시킵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;배치 프로그램&lt;/b&gt;: 실제로 데이터를 처리하고, 비즈니스 로직을 수행하는 프로그램.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스케줄러&lt;/b&gt;: 배치 프로그램을 &lt;b&gt;언제 실행할지 결정&lt;/b&gt;하는 시스템(예: cron, Quartz Scheduler).&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어, &lt;b&gt;배치 프로그램&lt;/b&gt;은 매일 밤 데이터베이스의 백업을 담당하고, &lt;b&gt;스케줄러&lt;/b&gt;는 이 작업을 매일 밤 12시에 실행되도록 예약하는 역할을 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Spring Batch&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;SpringBatch&lt;/b&gt;는 대량의 데이터를 효율적으로 처리하기 위한 &lt;b&gt;배치 처리 프레임워크&lt;/b&gt;입니다. 주로 &lt;b&gt;ETL(Extract, Transform, Load)&lt;/b&gt;작업, 데이터 마이그레이션, 보고서 생성, 대량의 데이터 처리 등에 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 용어&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Job
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Job은 배치 처리의 가장 큰 단위로, 배치 프로그램 자체를 의미합니다.&lt;/li&gt;
&lt;li&gt;여러 Step으로 구성되며, 각각의 Step은 독립적인 처리 단계입니다.&lt;/li&gt;
&lt;li&gt;한 번 실행될 때, 정의된 모든 Step을 차례대로 실행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Step
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Step은 Job의 구성 요소로, 실제 데이터를 처리하는 단계입니다.&lt;/li&gt;
&lt;li&gt;Reader, Processor, Writer가 하나의 Step을 구성하며, 하나의 Step이 완료된 후 다음 Step으로 넘어갑니다.&lt;/li&gt;
&lt;li&gt;각 Step은 개별 트랜잭션 단위로 실행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Reader&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Reader는 데이터를 읽어오는 역할을 합니다.&lt;/li&gt;
&lt;li&gt;일반적으로 파일, 데이터베이스, API 등에서 데이터를 읽어옵니다.&lt;/li&gt;
&lt;li&gt;e.d. ItemReader, FlatFileItemReader, JdbcCursoritemReader&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Processor
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Processor는 Reader에서 읽어노 데이터를 가공하거나 변환하는 역할을 합니다.&lt;/li&gt;
&lt;li&gt;데이터를 검증하거나, 변환하는 비즈니스 로직을 여기에 포함할 수 있습니다.&lt;/li&gt;
&lt;li&gt;e.d. ItemProcessor&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Writer
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Writer는 처리된 데이터 출력하거나 저장하는 역할을 합니다.&lt;/li&gt;
&lt;li&gt;데이터베이스에 저장하거나, 파일로 기록하거나, API에 데이터를 전달하는 등의 작업을 합니다.&lt;/li&gt;
&lt;li&gt;e.d. ItemWriter, FlatFileItemWriter, JdbcBatchItemWriter&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Chunk
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Chunk는 데이터를 처리할 때 사용하는 일괄 처리 단위입니다.&lt;/li&gt;
&lt;li&gt;Chunk 기반 처리에서는 데이터를 작은 덩어리로 나누어 처리하여 메모리 효율을 높입니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 1000건 데이터를 한 번에 처리하는 대신, 10건씩 나누어 처리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;각 Chunk는 별도의 트랜잭션으로 처리됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JobInstance
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JobInstance는 특정 Job에 대한 실행 시도를 나타냅니다.&lt;/li&gt;
&lt;li&gt;같은 Job이더라도 매번 실행할 때마다 고유한 JobInstance가 생성됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JobExecution
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JobExecution은 Job의 실행 상태나 결과를 나타냅니다.&lt;/li&gt;
&lt;li&gt;JobInstance가 실행될 때, 해당 실행에 대한 상세 정보(성공/실패 여부, 실행 시간, 오류 정보 등)를 담고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JobRepository
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JobRepository는 Job과 Step의 실행 정보를 저장하고 관리하는 저장소입니다.&lt;/li&gt;
&lt;li&gt;Job의 실행 상태, 중단된 지점, 실패한 이유 등 배치 작업의 이력을 관리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JobLauncher
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JobLauncher는 Job을 실행하는 인터페이스입니다.&lt;/li&gt;
&lt;li&gt;주로 외부에서 배치 작업을 트리거할 때 사용합니다.&lt;/li&gt;
&lt;li&gt;e.d. 특정 시간에 스케줄링 된 작업을 실행하거나, 특정 조건에서 수종으로 Job을 실행할 때 JobLauncher를 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;JobParameters
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JobParameters는 Job을 실행할 때 필요한 외부 입력값입니다.&lt;/li&gt;
&lt;li&gt;Job이 실행될 때마다 다른 피라미터가 필요한 경우, JobParameters를 통해 값을 전달할 수 있습니다. 예를 들어, 파일 경로나 특정 날짜 등의 값을 Job에 전달할 때 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Transaction
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Tranction은 데이터 처리의 일관성과 무결성을 보장하는 단위입니다.&lt;/li&gt;
&lt;li&gt;하나의 Step에서 발생하는 데이터 읽기, 처리, 쓰기 과정은 트랜잭션으로 처리되며, 오류 발생 시 롤백됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Skip
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Skip은 배치 처리 중 특정 예외가 발생했을 때 해당 데이터를 건너뛰는 기능입니다.&lt;/li&gt;
&lt;li&gt;예를 들어, 데이터 변환 중 일부 데이터에 오류가 발생하더라도 전체 Job이 실패하지 않고, 오류가 발생한 데이터를 건너뛰고 계속해서 나머지 데이터를 처리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Retry
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Retry는 처리 중 예외가 발생할 경우, 지정된 횟수만큼 재시도를 수행하는 기능입니다.&lt;/li&gt;
&lt;li&gt;트랜잭션이 실패하면 즉시 종료되지 않고, 설정된 횟수만큼 재시도한 후에도 실패할 경우에만 종료됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Partitioning
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Partitioning은 대량의 데이터를 병렬로 처리하기 위해 데이터를 여러 부분으로 나누어 각기 다른 스레드나 프로세스에서 동시에 실행하는 방법입니다.&lt;/li&gt;
&lt;li&gt;병렬 처리를 통해 성능을 개선할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Scailing
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Scaling은 여러 Step을 병렬로 처리하여 성능을 향상시키는 방법입니다.&lt;/li&gt;
&lt;li&gt;스레드를 사용하거나 여러 프로세스에서 병렬로 작업을 수행할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Framework/SpringBoot</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/114</guid>
      <comments>https://hulrud.tistory.com/114#entry114comment</comments>
      <pubDate>Sun, 8 Sep 2024 20:33:29 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 낙관적 락, 비관적 락</title>
      <link>https://hulrud.tistory.com/113</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;낙관적 락과 비관적 락의 개념적 차이 위주로 서술한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;락(Lock)의 필요성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 사용자나 프로세스가 동시에 동일한 수정하려고 하는 상황에서, 데이터가 충돌하거나 일관성이 깨질 수 있습니다. 이것을 방지하기 위해 락을 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;락이란 데이터베이스에서 여러 트랜잭션이 동시에 동일한 데이터를 변경할 때, 충돌을 방지하고 데이터 무결성을 유지하기 위해 &lt;b&gt;하나의 트랜잭션만이 데이터를 변경할 수 있도록 하는 매커니즘&lt;/b&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 락은 비관적 락과 낙관적 락으로 나뉘게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비관적 락(Pessiimistic Lock)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비관적 락은 데이터의 충돌이 자주 발생할 것으로 가정하고, 트랜잭션이 데이터를 읽거나 수정할 때&amp;nbsp;&lt;b&gt;즉시 락을 걸어&lt;/b&gt; 다른 트랜잭션이 해당 데이터에 접근하지 못하게 하는 방식입니다. 즉, 데이터 충돌 가능성을 사전에 차단하는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비관적 락은 두 유형으로 나눠집니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;읽기 락(Shared Lock)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 데이터를 읽을 때, 다른 트랜잭션이 해당 데이터를 수정하지 못하도록 &lt;b&gt;읽기 전용 락&lt;/b&gt;을 겁니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동시에 여러 트랜잭션이 같은 데이터를 읽을 수 있지만, 해당 데이터를 수정하려는 트랜잭션은 락이 해제될 때까지 대기&lt;/b&gt;해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;쓰기 락(Exclusive Lock)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터를 읽거나 수정하려는 트랜잭션은 단독으로 락을 획득해야 합니다.&lt;/li&gt;
&lt;li&gt;쓰기 락이 걸리면 다른 트랜잭션은 해당 데이터를 읽거나 수정할 수 없습니다.&lt;/li&gt;
&lt;li&gt;트랜잭션 완료 후에 락이 해제될 때까지 대기 상태에 들어갑니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 쿼리를 보자면,&lt;/p&gt;
&lt;pre id=&quot;code_1725776386599&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;BEGIN TRANSACTION;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- 이 시점에 계좌 1번에 대해 비관적 락이 걸리며, 다른 트랜잭션은 해당 데이터를 수정하지 못함
UPDATE accounts SET balance = balance + 100 WHERE id = 1;
COMMIT;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FOR UPDATE는 데이터베이스가 해당 행에 대해 Exclusive Lock을 걸도록 합니다. 다른 트랜잭션이 동일한 데이터를 수정하려고 시도하면 락이 해제될 때까지 대기하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비관적 락의 장점은 다음과 같습니다&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충돌이 자주 발생할 것으로 예상되는 환경에서 데이터 무결성을 강력하게 보장합니다.&lt;/li&gt;
&lt;li&gt;데이터를 수정하는 동안, 다른 트랜잭션이 데이터에 접근할 수 없기 때문에 데이터가 다른 트랜잭션에 의해 변경되지 않도록 안정성 보장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;성능 저하: 트랜잭션이 락을 해제할 때까지 다른 트랜잭션이 대기해야 하기 때문에 성능 저하가 발생할 수 있습니다. (특히 대규모 시스템에서는 병목 현상이 일어날 수 있습니다.)&lt;/li&gt;
&lt;li&gt;데드락(Deadlock) 가능성: 두 트랜잭션이 서로의 락을 기다리는 상황에서 데드락이 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라 비관적 락은 데이터 일관성이 매우 중요한 환경, 데이터 수정이 빈번하고 충돌 가능성이 높은 시스템에 사용됩니다. (e.d. 은행 시스템, 재고 관리 시스템)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;낙관적 락(Optimistic Lock)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낙관적 락은 충돌이 발생하지 않을 것이라고 가정하고, 트랜잭션이 데이터를 수정하려고 할 때만 충돌을 처리합니다. 즉, 트랜잭션이 데이터에 락을 미리 걸지 않고, 데이터를 업데이트 하는 순간 다른 트랜잭션에 의해 변경되지 않았는지 확인합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낙관적 락에서는 데이터를 수정할 때, &lt;b&gt;충돌이 발생하지 않았는지 검증하는 과정&lt;/b&gt;이 필요합니다. 이를 위해서 일반적으로는 데이터의 버전 필드나 타임스탬프를 사용합니다. 트랜잭션이 데이터를 수정할 때, 해당 데이터의 버전을 확인하고 수정 시점에서 버전이 변경되지 않았을 때만 업데이트를 적용합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;버전 관리(Versioning) 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 데이터 항목에는 버전(Version) 번호가 존재합니다&lt;/li&gt;
&lt;li&gt;트랜잭션이 데이터를 수정할 때, 현재 버전과 이전에 읽은 버전이 일치하는지 확인한 후 업데이트를 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CAS (Compare-And-Swap) 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리에서 주로 사용되는 방식으로, 현재 값과 예상 값이 동일한지 비교하고, 동일한 경우에만 값을 변경합니다.&lt;/li&gt;
&lt;li&gt;데이터베이스보다는 주로 동시성 제어가 필요한 메모리 구조에서 많이 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 검증 과정들은 DB에서 제공하는 기능을 사용하기 보단 Application Level에서 이루어집니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쿼리를 살펴보자면&lt;/p&gt;
&lt;pre id=&quot;code_1725777164717&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE accounts 
SET balance = balance + 100, version = version + 1
WHERE id = 1 AND version = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 쿼리는 version 필드가 1일대만 업데이트를 수행합니다. 만약 다른 트랜잭션이 먼저 이 데이터를 수정하려 버전이 2로 변경되었다면, 이 쿼리는 실패하게 됩니다. 실패 시, 트랜잭션은 충돌을 감지하고 재시도하거나 사용자에게 알림을 보냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낙관적 락의 장점은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 읽기 작업에 락을 걸지 않기 때문에 성능에 뛰어납니다. (낙관적 락은 락 오버헤드가 거의 없으므로, 대규모 읽기 위주의 시스템에서 매우 효과적입니다.)&lt;/li&gt;
&lt;li&gt;데드락 문제가 발생하지 않습니다. 락을 걸지 않기 때문에 트랜잭션 간의 교착 상태가 발생하지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점은 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;충돌이 자주 발생하는 경우, 트랜잭션이 실패할 가능성이 높습니다. 트랜잭션이 반복적으로 실패할 경우, 재시도를 해야 하므로 성능이 떨어질 수 있습니다.&lt;/li&gt;
&lt;li&gt;충돌을 감지한 후, 트랜잭션을 재시도하거나 오류 처리를 하는 추가 작업이 필요합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라 낙관적 락은 읽기 작업이 많고 수정이 적은 시스템, 대규모 트랜잭션이 빈번하게 발생하지 않는 환경에서 주로 사용됩니다. (e.d. SNS, 게시판 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;요약&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;비관적 락&lt;/b&gt;은 데이터 충돌 가능성이 높고, 일관성이 중요한 환경에서 트랜잭션이 시작되면 &lt;b&gt;즉시 락을 걸어&lt;/b&gt; 다른 트랜잭션이 해당 데이터에 접근하지 못하도록 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;낙관적 락&lt;/b&gt;은 충돌이 적을 것이라고 예상하고, 트랜잭션이 데이터를 수정할 때만 충돌을 확인하며, &lt;b&gt;락을 미리 걸지 않고 충돌 시 처리&lt;/b&gt;합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 글이 도움이 되길 바라며 마치겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>CS</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/113</guid>
      <comments>https://hulrud.tistory.com/113#entry113comment</comments>
      <pubDate>Sun, 8 Sep 2024 15:39:06 +0900</pubDate>
    </item>
    <item>
      <title>[Express] Aws s3 버킷을 이용하여 파일 업로드 구현하기</title>
      <link>https://hulrud.tistory.com/112</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;AWS S3 버킷을 이용하여 파일 업로드 로직을 구현하는 방법에 대해 설명한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  참고사항&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 해당 글에서는 S3 버킷을 만들고 액세스 키를 발급받는 방법이 생략되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 해당 글에서는 Express 프로젝트를 생성하고, DB를 연결하는 등의 방법이 생략되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 개발 언어로는 JS를 사용하며, ORM 라이브러리는 typeorm을 사용한 프로젝트입니다. (ORM 라이브러리는 상관 X)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버킷이 아직 없다면 아래 글을 참고해 주세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hulrud.tistory.com/105&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://hulrud.tistory.com/105&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1723701402966&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[AWS] AWS S3를 알아보고 버킷 만들어보기&quot; data-og-description=&quot;S3를 알아보고, 실제 S3 서비스를 이용하는 방법을 작성한 글입니다&amp;nbsp;  사전 준비1. AWS 회원가입2. SpringBoot 3.2.3 버전 프로젝트 (3.x.x 버전은 모두 무관합니다.)&amp;nbsp;Amazon S3Amazone Simple Storage Service(S3)는&quot; data-og-host=&quot;hulrud.tistory.com&quot; data-og-source-url=&quot;https://hulrud.tistory.com/105&quot; data-og-url=&quot;https://hulrud.tistory.com/105&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cd0WKk/hyWOkAwR5v/TR1Y7dgSMs1l7lMxrfjkX1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hd13N/hyWOoiEJ7S/tOqIyLkYrlez3nBDY1qTtK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/tvmap/hyWOlsHqZH/MiRvxKLhGxW5KyhgmQa5F0/img.png?width=1826&amp;amp;height=1656&amp;amp;face=0_0_1826_1656&quot;&gt;&lt;a href=&quot;https://hulrud.tistory.com/105&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hulrud.tistory.com/105&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cd0WKk/hyWOkAwR5v/TR1Y7dgSMs1l7lMxrfjkX1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/hd13N/hyWOoiEJ7S/tOqIyLkYrlez3nBDY1qTtK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/tvmap/hyWOlsHqZH/MiRvxKLhGxW5KyhgmQa5F0/img.png?width=1826&amp;amp;height=1656&amp;amp;face=0_0_1826_1656');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[AWS] AWS S3를 알아보고 버킷 만들어보기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;S3를 알아보고, 실제 S3 서비스를 이용하는 방법을 작성한 글입니다&amp;nbsp;  사전 준비1. AWS 회원가입2. SpringBoot 3.2.3 버전 프로젝트 (3.x.x 버전은 모두 무관합니다.)&amp;nbsp;Amazon S3Amazone Simple Storage Service(S3)는&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hulrud.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;환경 변수 설정&lt;/h2&gt;
&lt;pre id=&quot;code_1723701087364&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;AWS_ACCESS_KEY_ID=액세스 키 아이디
AWS_SECRET_ACCESS_KEY=비밀 액세스 키
AWS_REGION=버킷 리전 (아시아-서울인 경우: ap-northeast-2)
S3_BUCKET_NAME=버킷 이름&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 .env 파일에 버킷과 액세스 키 관련 정보를 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;라이브러리 설치&lt;/h2&gt;
&lt;pre id=&quot;code_1723701138925&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;npm install @aws-sdk/client-s3 multer-s3&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS SDK와 multer-s3를 설치합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설정 파일 작성&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/config 에 s3client.js 파일을 만들어 아래와 같이 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723702006037&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const { S3Client } = require('@aws-sdk/client-s3');

const s3 = new S3Client({
    region: process.env.AWS_REGION,
    credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
    },
});

module.exports = s3;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;src/config 에 multerConfig.js 파일을 만들어 아래와 같이 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1723702096934&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const multer = require('multer');
const multerS3 = require('multer-s3');
const path = require('path');
const s3 = require('./s3Client'); // S3 클라이언트 불러오기

const upload = multer({
    storage: multerS3({
        s3: s3,
        bucket: process.env.S3_BUCKET_NAME,
        key: function (req, file, cb) {
            const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
            // profiles/ 디렉토리 밑으로 저장
            // 루트에 저장하거나, 다른 디렉토리에 저장해야 할 경우에는 적절히 코드를 수정하세요.
            cb(null, `profiles/${uniqueSuffix}${path.extname(file.originalname)}`); // S3에 저장될 파일 경로와 이름
        },
        contentType: multerS3.AUTO_CONTENT_TYPE,
    }),
});

module.exports = upload;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;라우터 파일에 다음과 같이 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 토이프로젝트에 적용한 코드라 몇 부분은 생략하였습니다. 핵심 코드를 보시고 여러분의 상황에 맞게 적절히 적용해 주세요!&lt;/p&gt;
&lt;pre id=&quot;code_1723702766416&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const express = require('express');
const upload = require('../config/multerConfig'); // Multer 설정 불러오기

const router = express.Router();

router.post('/', upload.single('profile_img'), async (req, res) =&amp;gt; {
    try {
        const newData = {
            name: req.body.name,
            email: req.body.email,
            profile_img: req.file ? req.file.location : null, // S3 URL을 저장
        };
		
        // 데이터 베이스 저장 로직은 여러분의 프로젝트 상황에 맞추어 작성하세요!
        const createdData = await create(createdData); 
        
        res.status(201).json(createdTeacher); // 201 Created 상태 코드 반환
    } catch (error) {
        res.status(500).json({ error: 'Internal Server Error' });
    }
});

module.exports = router;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;포스트맨으로 테스트했을 때 성공적으로 업로드 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 profiles/ 에 파일을 저장했는데, 다른 디렉토리에 저장하실 분들은 multerConfig.js 파일을 적절히 수정하시길 바랍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bIaaw9/btsI5tK7iP7/ZF2K81CSvVAcbX2KTV2oFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bIaaw9/btsI5tK7iP7/ZF2K81CSvVAcbX2KTV2oFK/img.png&quot; data-origin-width=&quot;796&quot; data-origin-height=&quot;616&quot; data-is-animation=&quot;false&quot; style=&quot;width: 19.8337%; margin-right: 10px;&quot; data-widthpercent=&quot;20.07&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bIaaw9/btsI5tK7iP7/ZF2K81CSvVAcbX2KTV2oFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbIaaw9%2FbtsI5tK7iP7%2FZF2K81CSvVAcbX2KTV2oFK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;796&quot; height=&quot;616&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/V6GS1/btsI4qolQkC/G9PZWQ3Y1PNPKfKHHBCMx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/V6GS1/btsI4qolQkC/G9PZWQ3Y1PNPKfKHHBCMx1/img.png&quot; data-origin-width=&quot;1678&quot; data-origin-height=&quot;326&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;79.93&quot; style=&quot;width: 79.0035%;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/V6GS1/btsI4qolQkC/G9PZWQ3Y1PNPKfKHHBCMx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FV6GS1%2FbtsI4qolQkC%2FG9PZWQ3Y1PNPKfKHHBCMx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1678&quot; height=&quot;326&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Framework/Node.js</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/112</guid>
      <comments>https://hulrud.tistory.com/112#entry112comment</comments>
      <pubDate>Thu, 15 Aug 2024 15:22:55 +0900</pubDate>
    </item>
    <item>
      <title>[CS] OSI 7계층과 TCP/IP</title>
      <link>https://hulrud.tistory.com/111</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;혼공학습단 12기 과제로&amp;nbsp;&lt;b&gt;혼자 공부하는 네크워킹&lt;/b&gt;을 읽고, 정리한 내용을 작성한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;아주 긴 서론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;혼공학습단을 처음 지원한게 아마 8기인 것 같아요... 그 때는 혼자 공부하는 파이썬으로 혼공 학습단에 참여했는데, 제가 개발 블로그를 시작하게 된 동기가 되어 준 스터디 활동이라 아주 애정합니다. 혼공파 글은 네이버 블로그에서 작성했기 떄문에 이 블로그에선 볼 수 없지만, 혼자 공부하는 MySQL글은 아직도 있답니다...!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음 혼공단을 할 때에는 고등학교 1학년, 프로그래밍을 배운지 3개월정도 밖에 안 된 병아리... 까마귀였는데 지금은 취업까지 한(정규직은 아니지만) 상태입니다 ㅠㅠㅠ 덜덜 시간이 참 빠르네요...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기술 블로그가 제가 프로그래밍을 공부하는 데에 큰 도움이 되었어요, 남들에게 제 꾸준함을 보여줄 수 있는 지표가 되어주기도 했고 여러 방면에서 참 복덩이같은 존재인데! 그런 기술 블로그를 시작하게 된 계기인 혼공학습단! 취업한 기념으로 한번 더 해봐야지라는 마음으로 신청해봤답니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비록 시험기간과 겹치지만 그래도 열심히 해보도록 하겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;패킷 교환&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;패킷 교환(Packet Switching)은 데이터 통신 네트워크에서 데이터를 작은 패킷 단위로 나누어 전송하는 방식입니다. 패킷 교환 방식은 데이터를 효율적으로 전송하고 네트워크 자원을 최적화하는 데 중요한 역할을 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;패킷 교환의 기본 개념&lt;/b&gt;&lt;b&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;데이터 분할&lt;/b&gt;: 큰 데이터는 여러 개의 작은 패킷으로 분할됩니다. 각 패킷은 독립적으로 전송되며, 목적지에서 다시 원래의 데이터로 재조립됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;패킷 헤더&lt;/b&gt;: 각 패킷은 데이터뿐만 아니라 헤더 정보를 포함합니다. 헤더에는 송신자와 수신자의 주소, 패킷 순서, 오류 검출 코드 등이 포함되어 있어, 네트워크를 통해 올바르게 전달되고 재조립될 수 있게 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;독립적 전송&lt;/b&gt;: 각 패킷은 독립적으로 네트워크를 통해 전송되며, 경로가 다를 수 있습니다. 이는 네트워크 혼잡을 줄이고, 특정 경로의 장애를 회피할 수 있게 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터넷은 패킷 교환 방식을 사용하는 대표적인 예입니다. 인터넷에서 데이터는 IP 패킷으로 분할되어 전송되며, TCP/IP 프로토콜 스택을 통해 신뢰성 있는 데이터 전송이 이루어집니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로토콜&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜은 네트워크 상의 통신을 규정하는 일련의 규칙과 절차로, 데이터의 형식, 순서, 오류 처리, 흐름 제어 등을 포함합니다. 쉽게 말해,&amp;nbsp;&lt;b&gt;데이터를 올바르게 주고받기 위해 합의된 규칙이나 방법을 의미합니다. &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;즉, 서로 다른 통신 장치들이 정보를 주고 받으려면 프로토콜이 통해야 합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OSI 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSI 모델은 국제 표준화 긱에서 만든 네트워크 참조 모델입니다. 통신 단계를 7개의 계층으로 나누는데, 최하위 계층에서 최상위 계층순으로 각각 물리 계층, 데이터 링크 계층, 네크워크 계층, 전송 계층, 세션 계층, 표현 계층, 응용 계층입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;물리 계층 (Physical Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 물리적 매체를 통한 비트 전송을 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 케이블, 전기 신호, 커넥터 등의 물리적인 전송 매체와 관련된 표준을 규정합니다. 실제 데이터 전송이 이루어지는 계층입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 링크 계층 (Data Link Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 물리적 주소(MAC 주소) 기반의 프레임 전송 및 에러 검출을 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 네트워크 기기 간의 데이터 전송을 관리하고, 오류 검출 및 수정, 프레임 동기화 등을 수행합니다. 이 계층은 두 개의 하위 계층으로 나뉩니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;MAC (Media Access Control) 계층&lt;/b&gt;: 실제 네트워크 매체 접근 및 제어&lt;/li&gt;
&lt;li&gt;&lt;b&gt;LLC (Logical Link Control) 계층&lt;/b&gt;: 논리적 링크 제어 및 에러 검출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 계층 (Network Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 논리적 주소(IP 주소) 기반의 패킷 전송 및 경로 설정을 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 네트워크 간의 데이터 전송 경로를 설정하고, 데이터 패킷을 목적지까지 라우팅합니다. IP(Internet Protocol)가 이 계층에서 작동합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전송 계층 (Transport Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 신뢰성 있는 데이터 전송(TCP) 및 비신뢰성 데이터 전송(UDP)을 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 데이터의 분할, 전송, 오류 검출 및 수정, 재전송 등의 기능을 담당하며, 통신 세션의 관리 및 데이터 흐름 제어를 수행합니다. 대표적인 프로토콜로 TCP와 UDP가 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세션 계층 (Session Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 세션 설정, 관리 및 종료를 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 응용 프로그램 간의 대화(conversation)를 관리하고, 데이터 교환이 시작되고 유지되며 종료되는 방법을 규정합니다. 세션 복구 및 체크포인트 기능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;표현 계층 (Presentation Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 데이터 형식 변환 및 암호화/복호화를 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 응용 계층에서 사용하는 데이터 형식을 네트워크에서 사용할 수 있는 공통 형식으로 변환합니다. 데이터 압축, 암호화, 인코딩/디코딩 등의 기능을 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응용 계층 (Application Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 네트워크 응용 프로그램 인터페이스를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 사용자와 직접 상호작용하는 응용 프로그램과 네트워크 간의 인터페이스를 제공합니다. 웹 브라우징, 이메일, 파일 전송 등의 서비스가 이 계층에서 이루어집니다. HTTP, FTP, SMTP, DNS 등의 프로토콜이 이 계층에서 작동합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;532&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/q2FYl/btsIq9su2bP/CTBkGBGkTauDnCqh7LrS8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/q2FYl/btsIq9su2bP/CTBkGBGkTauDnCqh7LrS8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/q2FYl/btsIq9su2bP/CTBkGBGkTauDnCqh7LrS8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fq2FYl%2FbtsIq9su2bP%2FCTBkGBGkTauDnCqh7LrS8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;532&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;532&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;TCP/IP 모델&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP/IP 모델은 네트워크 통신을 설명하고 표준화하는 데 사용되는 네트워크 모델로, OSI 모델과 달리 4개의 계층으로 구성되어 있습니다. 이 모델은 인터넷과 같은 네트워크에서의 데이터 통신을 정의하며, 실제 네트워크 프로토콜이 어떻게 작동하는지에 중점을 둡니다. TCP/IP 모델의 4계층과 각 계층의 기능을 설명하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;네트워크 인터페이스 계층 (Network Interface Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 물리적 네트워크 인터페이스와 데이터 링크 계층 기능을 포함합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 이 계층은 실제 데이터 전송이 일어나는 물리적 매체와 관련된 기능을 담당합니다. 프레임의 형식, MAC 주소를 사용한 물리적 주소 지정, 하드웨어 관련 사항 등을 다룹니다. Ethernet, Wi-Fi (IEEE 802.11), PPP (Point-to-Point Protocol) 등이 이 계층에 속합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터넷 계층 (Internet Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 패킷 전송 및 라우팅을 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 네트워크 간 데이터 전송을 관리하고, 데이터 패킷을 목적지까지 라우팅합니다. IP 주소를 사용하여 논리적인 주소 지정 및 경로 설정을 수행합니다. 주요 프로토콜로는 IP(Internet Protocol), ICMP(Internet Control Message Protocol), ARP(Address Resolution Protocol) 등이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전송 계층 (Transport Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 신뢰성 있는 데이터 전송(TCP)과 비신뢰성 데이터 전송(UDP)을 담당합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 데이터의 분할, 전송, 오류 검출 및 수정, 재전송 등의 기능을 수행합니다. 통신 세션의 관리 및 데이터 흐름 제어도 이 계층에서 이루어집니다. 주요 프로토콜로는 TCP(Transmission Control Protocol)와 UDP(User Datagram Protocol)가 있습니다. TCP는 연결 지향형 프로토콜로 신뢰성 있는 전송을 보장하며, UDP는 비연결형 프로토콜로 빠르고 효율적인 전송을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응용 계층 (Application Layer)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기능&lt;/b&gt;: 네트워크 응용 프로그램 인터페이스를 제공합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세부 설명&lt;/b&gt;: 사용자와 직접 상호작용하는 응용 프로그램과 네트워크 간의 인터페이스를 제공합니다. 이메일, 파일 전송, 웹 브라우징 등과 같은 서비스가 이 계층에서 이루어집니다. 주요 프로토콜로는 HTTP(HyperText Transfer Protocol), FTP(File Transfer Protocol), SMTP(Simple Mail Transfer Protocol), DNS(Domain Name System) 등이 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;과제 1. OSI 모델 및 TCP/IP 모델 차이점을 정리하고, 이를 바탕으로 네트워크 계층 구조 작성&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OSI 모델&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OSI(Open Systems Interconnection) 모델은 ISO(International Organization for Standardization)에서 개발한 7계층 네트워크 모델입니다. 각 계층은 특정 기능을 담당하며, 하위 계층에서 상위 계층으로 서비스를 제공합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;물리 계층 (Physical Layer)&lt;/b&gt;: 물리적 매체를 통한 비트 전송&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터 링크 계층 (Data Link Layer)&lt;/b&gt;: 물리적 주소(MAC 주소) 기반의 프레임 전송 및 에러 검출&lt;/li&gt;
&lt;li&gt;&lt;b&gt;네트워크 계층 (Network Layer)&lt;/b&gt;: 논리적 주소(IP 주소) 기반의 패킷 전송 및 경로 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전송 계층 (Transport Layer)&lt;/b&gt;: 신뢰성 있는 데이터 전송(TCP) 및 비신뢰성 데이터 전송(UDP)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;세션 계층 (Session Layer)&lt;/b&gt;: 세션 관리 및 통신 동기화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;표현 계층 (Presentation Layer)&lt;/b&gt;: 데이터 형식 변환 및 암호화/복호화&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응용 계층 (Application Layer)&lt;/b&gt;: 네트워크 응용 프로그램 인터페이스 (HTTP, FTP 등)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;TCP/IP 모델&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TCP/IP(Transmission Control Protocol/Internet Protocol) 모델은 인터넷에서 사용되는 4계층 네트워크 모델입니다. 실질적인 인터넷 통신 표준으로 자리 잡았습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;네트워크 인터페이스 계층 (Network Interface Layer)&lt;/b&gt;: 물리적 네트워크 인터페이스와 데이터 링크 계층 기능 포함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인터넷 계층 (Internet Layer)&lt;/b&gt;: IP 프로토콜을 사용한 패킷 전송 및 경로 설정&lt;/li&gt;
&lt;li&gt;&lt;b&gt;전송 계층 (Transport Layer)&lt;/b&gt;: TCP/UDP 프로토콜을 사용한 데이터 전송&lt;/li&gt;
&lt;li&gt;&lt;b&gt;응용 계층 (Application Layer)&lt;/b&gt;: 네트워크 응용 프로그램 인터페이스 (HTTP, FTP 등)&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;OSI 모델과 TCP/IP 모델의 비교&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 160px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style3&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;OSI 모델&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;TCP/IP 모델&lt;/td&gt;
&lt;td style=&quot;height: 17px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;물리 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;네트워크 인터페이스 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;비트 전송&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;데이터 링크 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;네트워크 인터페이스 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;프레임 전송 및 에러 검출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;네트워크 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;인터넷 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;패킷 전송 및 경로 설정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;전송 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;전송 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;데이터 전송 (TCP/UDP)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;세션 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;응용 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;세션 관리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;표현 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;응용 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;데이터 형식 변환&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;응용 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;응용 계층&lt;/td&gt;
&lt;td style=&quot;height: 18px;&quot;&gt;네트워크 응용 프로그램&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;과제 2. 문제 풀이&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;프로토콜에 대한 설명으로 옳지 않은 것은?&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;프로토콜은 정보를 주고받는 통신 장치 간의 합의된 규칙이나 방법을 의미합니다.&lt;/li&gt;
&lt;li&gt;네크워크 참조 모델에서 계층별로 프로톨을 달리 구성할 수 있습니다.&lt;/li&gt;
&lt;li&gt;프로토콜에는 목적과 특징이 있습니다.&lt;/li&gt;
&lt;li&gt;통신 장치 간에 프로토콜이 통하지 않아도 정보를 주고받을 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옳지 않은 것은 4번입니다! 통신 장치 간의 프로토콜이 같아야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;네크워크 참조 모델에 대한 설명으로 옳지 않은 것은?&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;OSI 모델은 7개의 계층으로 통신 과정을 구분합니다.&lt;/li&gt;
&lt;li&gt;TCP/IP 모델은 3개의 계층으로 통신 과정을 구분합니다.&lt;/li&gt;
&lt;li&gt;네트워크 참조 모델은 네트워크 구성과 설계를 용이하게 합니다.&lt;/li&gt;
&lt;li&gt;네트워크 참조 모델은 네크워크 문제 진단과 해결을 용이하게 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옳지 않은 것은 2번입니다. TCP/IP 모델은 4개의 계층으로 통신 과정을 구분합니다.&lt;/p&gt;</description>
      <category>CS</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/111</guid>
      <comments>https://hulrud.tistory.com/111#entry111comment</comments>
      <pubDate>Sat, 6 Jul 2024 12:50:19 +0900</pubDate>
    </item>
    <item>
      <title>[Spring] 내가 생각하는 Spring을 하면서 꼭 알아야 하는 개념들</title>
      <link>https://hulrud.tistory.com/110</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;Spring을 하면서 꼭 알아야 한다고 생각하는 개념들에 대해 작성한 글입니다. 어떤 개념을 다루는지는 목차를 참고해 주세요! (2024.05.15 업데이트)&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 스프링 프로젝트를 하면서 다시 개념에 대한 공부를 할 타이밍이란 것을 느끼게 되었습니다. 이유는 &lt;i&gt;&lt;b&gt;이론 공부한 지 너무 오래되어 개념들이 머리 속에서 정리가 안 된 기분이 들어서...&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서! 이 글에서는 제가 작년부터 스프링을 공부하면서 정리한 개념들을 쭉 나열했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;한 개념을 자세하게 설명하지 않았습니다.!&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 &lt;b&gt;어떤 개념을 자세하게 알고 싶어서 이 글을 클릭하셨다면 뒤로 가기를 추천드립니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러 개념을 쓱~ 보고 싶으시다면 이 글이 도움이 될지도 모르겠습니다... ㅎ&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 계층&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트에는 프로젠테이션, 비즈니스, 퍼시스턴스 계층이 있습니다. 이 계층들이 서로 통신하며 프로그램을 구성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프레젠테이션 계층: HTTP 요청을 받고 이 요청을 비즈니스 계층으로 전송하는 역할을 합니다. 컨트롤러가 바로 프레젠테이션 계층 역할을 합니다. 컨트롤러가 프레젠테이션 계층의 역할을 합니다.&lt;/li&gt;
&lt;li&gt;비즈니스 계층: 모든 비즈니스 로직을 처리합니다. 비즈니스 로직이란 서비스를 만들기 위한 로직을 말합니다. 쉽게 말해 웹 사이트에서 벌어지는 모든 작업, 이를테면 주문 서비스라고 한다면 주문 개수, 가격 등의 데이터를 처리하기 위한 로직, 주문 처리를 하다가 발생하는 예외 처리 로직 등이 포함됩니다. 서비스가 비즈니스 계층의 역할을 합니다.&lt;/li&gt;
&lt;li&gt;퍼시스턴스 계층: 모든 데이터베이스 관련 로직을 처리합니다. 이 과정에서 데이터베이스에 접근하는 DAO 객체를 사용할 수도 있습니다. DAO는 데이터베이스 계층과 상호작용하기 위한 객체입니다. 리포지토리가 퍼시스턴스 계층의 역할을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;스프링 부트 요청 - 응답 과정&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;클라이언트가 톰캣에 요청&lt;/li&gt;
&lt;li&gt;스프링 부트의 디스패치 서블릿이 URL을 분석하고 요청을 처리할 컨트롤러를 찾아 요청 전달&lt;/li&gt;
&lt;li&gt;컨트롤러 내에 있는 메서드와 요청이 매치&lt;/li&gt;
&lt;li&gt;비즈니스 계층과 퍼시스턴스 계층을 통하여 필요한 작업을 함&lt;/li&gt;
&lt;li&gt;뷰 리졸버가 HTML문서를 만들거나 JSON, XML등의 데이터를 생성&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 style=&quot;color: #000000;&quot; data-ke-size=&quot;size26&quot;&gt;2. MVC&lt;/h2&gt;
&lt;div&gt;
&lt;div style=&quot;color: #000000;&quot; data-testid=&quot;conversation-turn-97&quot; data-scroll-anchor=&quot;true&quot;&gt;
&lt;div&gt;
&lt;div data-message-author-role=&quot;assistant&quot; data-message-id=&quot;0ee41fac-97d3-4726-8300-4cd2379b1134&quot;&gt;
&lt;div style=&quot;color: #000000;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MVC는 Model-View-Controller의 약자로, 애플리케이션을 세 가지 주요 부분으로 나누어 개발하는 디자인 패턴입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컨트롤러(Controller):&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li style=&quot;list-style-type: none;&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컨트롤러는 클라이언트의 요청을 처리하고, 적절한 비즈니스 로직을 호출하여 응답을 생성합니다.&lt;/li&gt;
&lt;li&gt;@Controller 애노테이션을 사용하여 클래스를 컨트롤러로 지정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;메서드는 @RequestMapping 애노테이션을 사용하여 특정 URL과 HTTP 메서드에 매핑됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모델(Model)&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모델은 컨트롤러와 뷰 사이에서 데이터를 전달하는 역할을 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데이터와 데이터와 관련된 로직을 처리하고, 데이터를 관리&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;하는데 사용되는 모든 주체들을 Model로 칭할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;뷰(View)&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;뷰는 클라이언트에게 결과를 표시하는 역할을 합니다.&lt;/li&gt;
&lt;li&gt;주로 JSP, Thymeleaf, Freemarker 등의 템플릿 엔진을 사용하여 뷰를 생성합니다.&lt;/li&gt;
&lt;li&gt;뷰는 컨트롤러가 전달한 데이터를 사용하여 동적으로 페이지를 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div style=&quot;background-color: #ffffff; color: #000000; text-align: start;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 제어의 역전과 의존성 주입&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IoC (Inversion of Control)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IoC란 Inversion of Control의 약자로 직역하면&amp;nbsp;&lt;b&gt;제어의 역전&lt;/b&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;기존의 전통적인 프로그래밍 모델에서는 개발자가 코드의 흐름과 제어를 직접 관리하고 제어합니다. 그러나 제어의 역전은 이와 달리 코드의 제어 흐름을 프레임워크나 컨테이너가 가져가도록 하는 것을 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 객체 생성을&amp;nbsp;&lt;b&gt;해당 객체에 의존하는 객체가 직접 new 키워드와 생성자를 이용하여 하는 것이 아니라&lt;/b&gt;, 객체를 필요로 한다는 일종의 힌트를 주기 위한 어노테이션만 붙여주면&amp;nbsp;&lt;b&gt;외부에서 해당 객체를 만들어 주입하여 제공&lt;/b&gt;하는 전략을 말합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;DI (Dependency Injection)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;앞에서 설명한 것처럼 스프링에서는 객체들을 관리하기 위해 제어의 역전을 사용합니다. 그리고 제어의 역전을 구현하기 위해 사용하는 방법이 DI입니다. DI는 Dependency Injection의 약자로 직역하면&amp;nbsp;&lt;b&gt;의존성 주입&lt;/b&gt;입니다. 의존성 주입은&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #0d0d0d;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;어떤 클래스가 다른 클래스에 의존한다는 뜻입니다.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 말 그대로&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;객체가 의존하는 특정 객체를 대신 생성하고, 주입도 해주는 디자인 패턴을 의미합니다.&amp;nbsp;&lt;/b&gt;DI를 통해 객체간의 결합도를 줄이고 코드의 재사용성을 높일 수 있습니다.&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;DI를 하는 세 가지 방법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링에서 사용되는 DI방법에는 크게 세가지가 있습니다&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;생성자 주입 (Constructor Injection)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;생성자 주입은 객체를 생성할 때 생성자를 통해 의존성을 주입하는 방식입니다.&lt;/li&gt;
&lt;li&gt;스프링에서는 생성자에 @Autowired 애노테이션을 사용하여 의존성을 주입합니다. 또는 XML 설정 파일에서 &amp;lt;constructor-arg&amp;gt; 요소를 사용할 수도 있습니다.&lt;/li&gt;
&lt;li&gt;생성자 주입은 필수적인 의존성을 명시적으로 표현할 수 있고, 불변성을 보장하여 안정적인 객체를 생성할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1715602169741&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class ExampleService {
    private final Dependency dependency;

    @Autowired
    public ExampleService(Dependency dependency) {
        this.dependency = dependency;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;Setter 주입 (Setter Injection)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Setter 주입은 객체 생성 후 Setter 메서드를 통해 의존성을 주입하는 방식입니다.&lt;/li&gt;
&lt;li&gt;스프링에서는 Setter 메서드에 @Autowired 애노테이션을 사용하여 의존성을 주입합니다. 또는 XML 설정 파일에서 &amp;lt;property&amp;gt; 요소를 사용할 수도 있습니다.&lt;/li&gt;
&lt;li&gt;Setter 주입은 선택적인 의존성을 표현하기에 유용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1715602169742&quot; class=&quot;java&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class ExampleService {
    private Dependency dependency;

    @Autowired
    public void setDependency(Dependency dependency) {
        this.dependency = dependency;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;필드 주입 (Field Injection)&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc; background-color: #ffffff; color: #0d0d0d; text-align: left;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;필드 주입은 필드에 바로 의존성을 주입하는 방식입니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;스프링에서는 필드에 @Autowired 애노테이션을 사용하여 의존성을 주입합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1715602169742&quot; class=&quot;angelscript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class ExampleService {
    @Autowired
    private Dependency dependency;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;셋 중 하나의 방법을 쓰면 됩니다만&amp;nbsp;&lt;b&gt;동시에 여러 방법을 쓰는 것은 중복 주입이 이루어지므로 지양&lt;/b&gt;해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 보통 생성자를 통해서 의존성 주입을 진행하는 것이 가장 좋은 방법입니다. 그리고 생성자 주입을 통해서만&amp;nbsp;&lt;b&gt;의존성 주입을 받는 필드를 상수로 정의할 수 있습니다.&amp;nbsp;&lt;/b&gt;대부분 의존성 주입을 받은 객체를 변경할 일이 없기 때문에 실수를 예방하기 위해서 상수로 지정하는 것을 선호합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #0d0d0d;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;4. Bean과 스프링 컨테이너&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;스프링은 애플리케이션의 객체 생성과 관리를 담당하는 스프링 컨테이너와 이를 통해 관리되는 객체를 빈(Bean)이라고 부르는데, 이들에 대해 각각 설명해보겠습니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;Bean&lt;/span&gt;&lt;/h3&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;빈은 스프링 컨테이너에 의해 생성되고 관리되는 객체를 말합니다. 스프링에서는 개발자가 작성한 일반적인 자바 클래스를 빈으로 등록하여 사용할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;빈은 XML 설정 파일이나 Java Config, 어노테이션을 통해 정의될 수 있습니다. 즉, 빈을 등록하는 방법에는 여러가지가 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000;&quot; data-ke-size=&quot;size20&quot;&gt;Bean을 등록하는 방법&lt;/h4&gt;
&lt;p style=&quot;color: #000000;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;XML 기반 설정 (XML Configuration)&lt;/b&gt;: XML 파일에 &amp;lt;bean&amp;gt; 요소를 사용하여 Bean을 정의하는 방법입니다. 일반적으로 applicationContext.xml 또는 beans.xml과 같은 이름의 XML 파일을 사용합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715599661037&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;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
                           http://www.springframework.org/schema/beans/spring-beans.xsd&quot;&amp;gt;

    &amp;lt;bean id=&quot;myBean&quot; class=&quot;com.example.MyBean&quot;/&amp;gt;

&amp;lt;/beans&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Java 기반 설정 (Java Configuration)&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;: Java 클래스에 &lt;/span&gt;@Configuration&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt; 애노테이션을 사용하여 설정 클래스를 정의하고, &lt;/span&gt;@Bean&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt; 애노테이션을 사용하여 Bean을 정의하는 방법입니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715599698289&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
public class AppConfig {

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Component Scanning&lt;/b&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;: &lt;/span&gt;@Component&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;, &lt;/span&gt;@Service&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;, &lt;/span&gt;@Repository&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;, &lt;/span&gt;@Controller&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt; 등의 스프링 애노테이션을 사용하여 클래스를 표시하고, 스프링이 자동으로 Bean으로 등록되도록 하는 방법입니다. 스프링 컨테이너는 클래스 경로에서 이러한 애노테이션이 지정된 클래스를 검색하고 자동으로 Bean으로 등록합니다. &lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1715599722969&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class MyService {
    //...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;여기서 Configuration을 사용한 방법과 Component Scanning 을 통한 방법에 대해 더 자세하게 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;@Component&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Component 애노테이션은 스프링 컨테이너가 해당 클래스를 스캔하여 Bean으로 등록하도록 지시합니다. 이 애노테이션은 일반적으로 개발자가 정의한 일반적인 POJO(Plain Old Java Object) 클래스에 부여됩니다.&lt;/li&gt;
&lt;li&gt;@Component 애노테이션을 사용하면 해당 클래스가 스프링 컨테이너에 의해 자동으로 Bean으로 등록됩니다. 스프링은 이러한 Bean을 인스턴스화하고 관리합니다.&lt;/li&gt;
&lt;li&gt;@Component는 다른 세부적인 스프링 애노테이션인 @Service, @Repository, @Controller의 상위 개념입니다. 따라서 이 애노테이션들은 @Component를 확장하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;@Configuration&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;@Configuration 애노테이션은 스프링의 Java 기반 설정 클래스를 나타냅니다. 이 클래스는 스프링 빈 설정을 정의하고, @Bean 애노테이션을 사용하여 빈을 생성하고 구성하는 메서드를 포함할 수 있습니다.&lt;/li&gt;
&lt;li&gt;@Configuration 클래스를 사용하여 스프링 빈을 설정할 때에는 해당 클래스를 구성 클래스로 지정하고, 이 클래스 내에 @Bean 메서드를 사용하여 스프링 빈을 정의합니다.&lt;/li&gt;
&lt;li&gt;@Configuration 클래스 내에서 @Bean으로 정의된 메서드가 스프링 빈으로 등록됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Spring IoC Container&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 컨테이너는 스프링 프레임워크의 핵심 부분으로, 애플리케이션의 객체를 생성, 관리, 조립하는 역할을 담당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;ApplicationContext&lt;/b&gt; 인터페이스를 구현한 &lt;span style=&quot;background-color: #ffffff; color: #222222; text-align: left;&quot;&gt;객체가 스프링 ioC 컨테이너의 역할을 수행합니다. &lt;/span&gt;ApplicationContext는 스프링에서 제공하는 IoC 컨테이너로, 생성된 Bean을 보관하고 있는 보관 창고같은 역할입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 관점 지향 프로그래밍 (AOP, &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Aspect-Oriented Programming)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;AOP란 프로그래밍에 대한 관점을 핵심 관점, 부가 관점으로 나누어서 관심 기준으로 모듈화하는 것을 의미합니다. 여기서 관점(Aspect)란 부가 기능과 그 적용처를 정의하고 합쳐서 모듈로 만든 것입니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;AOP의 목적&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;관점 지향 프로그래밍은 객체 지향 프로그래밍(OOP)을 보완하기 위해 사용합니다. 기존 객체 지향은 목적에 따라 클래스, 즉 객체를 만들었습니다. 따라 핵심 비즈니스이든, 부가 비즈니스이든 객체로 분리하는데 그치고, 그 객체들을 어떻게 바라보고 나눠쓸지에 대한 정의가 부족하다는 단점이 있습니다. 이를 보완하기 위해 AOP를 사용합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. ORM&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;ORM(객체 관계 매핑, Object-Relational Mapping)은 객체 지향 프로그래밍 언어와 관계형 데이터베이스 간의 데이터를 변환하는 기술이며, 객체 모델과 데이터베이스 모델 간의 불일치를 해결하기 위해 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;일반적으로 객체는 클래스와 속성으로 구성되어 있고, 데이터베이스는 테이블과 열로 구성되어 있습니다. ORM은 이러한 객체와 데이터베이스 간의 불일치를 해결하기 위해 객체를 데이터베이스 테이블에 매핑하고, 객체 간의 관계를 데이터베이스의 관계로 매핑합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #0d0d0d;&quot;&gt;&lt;span style=&quot;background-color: #ffffff;&quot;&gt;ORM의 장점&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SQL을 직접 작성하지 않고 사용하는 언어로 데이터베이스에 접근할 수 있습니다.&lt;/li&gt;
&lt;li&gt;객체 지향적으로 코드를 작성할 수 있기 때문에 비즈니스 로직에만 집중할 수 있습니다.&lt;/li&gt;
&lt;li&gt;데이터베이스 시스템이 추상화되어 있기 때문에 MySQL에서 PostgreSQL로 전환한다고 해도 추가로 드는 작업이 거의 없습니다. 즉, 데이터베이스 시스템에 대한 종속성이 줄어들게 됩니다.&lt;/li&gt;
&lt;li&gt;매핑하는 정보가 명확하기 때문에 ERD에 대한 의존도를 낮출 수 있고 유지보수할 때 유리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;ORM의 단점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로젝트의 복잡성이 커질수록 사용 난이도도 올라갑니다.&lt;/li&gt;
&lt;li&gt;복잡하고 무거운 쿼리는 ORM으로도 해결이 불가능한 경우가 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;7. JPA (Java Persistence API)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;ORM에도 여러 종류가 있습니다. 자바에서는 JPA를 표준으로 사용합니다. JPA는 자바에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스인데요, 인터페이스이므로 실제 사용을 위해서는 ORM 프레임워크를 추가로 선택해야 합니다. 대표적으로는 하이버네이트를 많이 사용합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;하이버네이트는 JPA 인터페이스를 구현한 구현체이자 자바용 ORM 프레임워크입니다. 하이버네이트 내부적으로는 JDBC API를 사용합니다. 하이버네이트의 목표는 자바 객체를 통해 데이터베이스 종류에 상관없이 데이터베이스를 자유롭게 사용할 수 있게 하는 데 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;JPA와 하이버네이트의 역할&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;JPA(Java Persistence API): 자바 객체와 데이터베이스를 연결해 데이터를 관리합니다. 객체 지향 도메인 모델과 데이터베이스의 다리 역할을 합니다.&lt;/li&gt;
&lt;li&gt;하이버네이트(Hibernate): JPA의 인터페이스를 구현합니다. 내부적으로는 JDBC API를 사용합니다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;엔티티 매니저&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JPA의 중요한 컨셉 중 하나인 엔티티 매니저와 영속성 컨텍스트를 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;엔티티 (Entity)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티는 데이터베이스의 테이블과 매핑되는 객체를 의미합니다. 엔티티는 본질적으로는 자바 객체이므로 일반 객체와 다르지 않습니다. 하지만 &lt;b&gt;데이터베이스의 테이블과 직접 연결&lt;/b&gt;된다는 특징이 있어 구분지어 부릅니다. 즉, 엔티티는 객체이지만 데이터베이스에 영향을 미치는 쿼리를 실행하는 객체입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;엔티티 매니저 (Entity Manager)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티 매니저는 엔티티를 관리해 데이터베이스와 애플리케이션 사이에서 객체를 생성, 수정, 삭제하는 등의 역할을 합니다. 그리고 이런 엔티티 매니저를 만드는 곳이&amp;nbsp;&lt;b&gt;엔티티 매니저 팩토리&lt;/b&gt;입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스에는 여러 사용자가 접근할 수 있습니다. 가령 회원 2명이 동시에 회원 가입을 하려는 경우 엔티티 매니저 팩토리는 각각의 업무에 대해 엔티티 매니저를 생성합니다. 따라 업무마다 생성된 엔티티 매니저를 통해 회원의 정보가 데이터베이스에 저장됩니다. 그리고 필요한 시점에 데이터베이스와 연결한 뒤 쿼리합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 부트 내부에서는 엔티티 매니저 팩토리를 하나만 생성해서 관리하고 @PersistenceContext 또는 @Autowired 어노테이션을 사용해 엔티티 매니저를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1715605813099&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@PersistenceContext
EntityManager em;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;그리고 스프링 부트는 기본적으로 빈을 하나만 생성해서 공유하므로 동시성 문제가 발생할 수 있습니다. 그래서 실제로는 엔티티 매니저가 아닌 실제 엔티티 매니저와 연결하는 프록시(가짜) 엔티티 매니저를 사용합니다. 필요할 때 데이터베이스 트랜잭션과 실제 엔티티 매니저를 호출하는 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 엔티티 매니저는 Spring Data JPA에서 관리하므로 개발자가 직접 생성하거나 관리할 필요가 없습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;영속성 컨텍스트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 엔티티 매니저는 엔티티를 영속성 컨텍스트에 저장한다는 특징이 있습니다. 영속성 컨텍스트는 JPA의 중요한 특징 중 하나로, 엔티티를 관리하는 가상의 공간입니다. 이것이 있기 때문에 데이터 베이스에서 효과적으로 데이터를 가져올 수 있고, 엔티티를 편하게 사용할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트에는 1차 캐시, 쓰기 지연, 변경 감지, 지연 로딩이라는 특징이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1차 캐시&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;영속성 컨텍스트는 내부에 1차 캐시를 가지고 있습니다. 이때 캐시의 키는 엔티티의 @Id 에너테이션이 달린 기본키 역할을 하는 식별자이며 값은 엔티티입니다. 엔티티를 조회하면 1차 캐시에서 데이터를 조회하고 값이 있으면 반환합니다. 값이 없으면 데이터베이스에서 조회해 1차 캐시에 저장한 다음 반환합니다. 이를 통해 캐시된 데이터를 조회할 때에는 데이터베이스를 거치지 않아도 되므로 매우 빠르게 데이터를 조회할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;쓰기 지연 (transactional write-behind)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쓰기 지연은은 트랜잭션을 커밋하기 전까지는 데이터베이스에 실제로 질의문을 보내지 않고 쿼리를 모았다가 트랜잭션을 커밋하면 모았던 쿼리를 한번에 실행하는 것을 의미합니다. 예를 들어 데이터 추가 쿼리가 3개라면 영속성 컨텍스트는 트랜잭션을 커밋하는 시점에 3개의 쿼리를 한꺼번에 쿼리를 전송합니다. 이를 통해 적당한 묶음으로 쿼리를 요청할 수 있어 데이터베이스 시스템의 부담을 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;변경 감지&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트랜잭션을 커밋하면 1차 캐시에 저장되어 있는 엔티티의 값과 현재 엔티티의 값을 비교해서 변경된 값이 있다면 변경 사항을 감지해 변경된 값을 데이터베이스에 자동으로 반영합니다. 이를 통해 쓰기 지연과 마찬가지로 적당한 묶음으로 쿼리를 요청할 수 있고, 데이터베이스 시스템의 부담을 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;지연 로딩 (lazy loading)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;지연 로딩은 쿼리로 요청한 데이터를 애플리케이션에 바로 로딩하는 것이 아니라 필요할 때 쿼리를 날려 데이터를 조회하는 것을 의미합니다. 반대로 조회할 때 쿼리를 보내 연관된 모든 데이터를 가져오는 즉시 로딩도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 특징들은 모두 데이터베이스 접근을 최소화해 성능을 높일 수 있다는 것입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;엔티티의 상태&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엔티티는 4가지 상태를 가집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;영속성 컨텍스트가 관리하고 있지 않는 분리(detached) 상태&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트가 관리하는 관리(managed) 상태&lt;/li&gt;
&lt;li&gt;영속성 컨텍스트와 전혀 관계가 없는 비영속(transist) 상태&lt;/li&gt;
&lt;li&gt;삭제된(removed) 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 상태는 특정 메서드를 호출해 변경할 수 있고, 필요에 따라 엔티티의 상태를 조절해 데이터를 올바르게 유지하고 관리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 스프링 시큐리티 (Spring Security)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 시큐리티는 스프링 기반의 애플리케이션 보안(인증, 인가, 권한)을 담당하는 스프링 하위 프레임워크입니다. 스프링 시큐리티를 이해하려면 인증과 인가에 대한 개념을 알아야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인증과 인가&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인증(Authentication)은 사용자의 신원을 입증하는 과정입니다. 예를 들어, 사용자가 사이트에 로그인을 할 때 누구인지 확인하는 과정을 인증이라고 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인가(Authorization)는 인증과는 달리&amp;nbsp;&lt;b&gt;사이트의 특정 부분에 접근할 수 있는지 권한을 확인하는 작업&lt;/b&gt;입니다. 예를 들어 관리자가 아닌 유저는 관리자 페이지에 들어갈 수 없지만 관리자는 관리자 페이지에 접근할 수 있습니다. 이런 권한을 확인하는 과정이 인가입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;스프링 시큐리티 동작 과정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 시큐리티는 필터 기반으로 동작합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 이미지와 같이 다양한 필터들로 나누어져 있으며, 각 필터에서 인증, 인가와 관련된 작업을 처리합니다. SpringContextPersistenceFilter부터 시작해서 아래로 내려가며 FilterSecurityInterceptor까지 순서대로 필터를 거칩니다. 필터를 실행할 때는 빨간 화살표로 연결된 오른쪽 박스의 클래스를 거치며 실행됩니다. 특정 필터를 제거하거나 필터 뒤에 커스텀 필터를 넣는 등의 설정도 가능합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;502&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cIP3Tf/btsHqIRQroA/QkHnSy4EZa1jMXTtJwN6nK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cIP3Tf/btsHqIRQroA/QkHnSy4EZa1jMXTtJwN6nK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cIP3Tf/btsHqIRQroA/QkHnSy4EZa1jMXTtJwN6nK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcIP3Tf%2FbtsHqIRQroA%2FQkHnSy4EZa1jMXTtJwN6nK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;700&quot; height=&quot;502&quot; data-origin-width=&quot;700&quot; data-origin-height=&quot;502&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서&amp;nbsp;&lt;b&gt;UsernamePasswordAuthencationFilter&lt;/b&gt;는 아이디와 패스워드가 넘어오면 인증 요청을 위임하는 인증 관리자 역할을 합니다.&amp;nbsp;&lt;b&gt;FilterSecurityInterceptor&lt;/b&gt;는 권한 부여 처리를 위임해 접근 제어 결정을 쉽게 하는 접근 결정 관리자 역할을 합니다.&lt;/p&gt;</description>
      <category>Framework/SpringBoot</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/110</guid>
      <comments>https://hulrud.tistory.com/110#entry110comment</comments>
      <pubDate>Wed, 15 May 2024 15:47:48 +0900</pubDate>
    </item>
    <item>
      <title>[CS] 비선형 자료구조 그래프, 트리, 힙, 맵, 셋, 해시 테이블에 대해 알아보자</title>
      <link>https://hulrud.tistory.com/109</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;비선형 자료구조인 그래프, 트리, 힙, 맵, 셋, 해시테이블에 대해 작성한 글입니다.&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;비선형 자료구조&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비선형 자료구조란 일렬로 나열하지 않고 자료 순서나 관계가 복잡한 구조를 말합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;그래프&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프는 정점(vertex)과 간선(edge)으로 이루어진 자료 구조를 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;정점(Vertex)&lt;/b&gt;: 그래프의 구성 요소 중 하나로, 데이터를 저장하는 노드입니다. 예를 들어, 소셜 네트워크에서 사용자나 지역망에서 장치들이 정점이 될 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간선(Edge)&lt;/b&gt;: 그래프의 정점들을 연결하는 선으로, 노드들 간의 관계를 나타냅니다. 간선은 방향이 있을 수도 있고 없을 수도 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;방향성(Directionality)&lt;/b&gt;: 간선이 방향 그래프(Directed Graph)일 경우, 방향성이 있습니다. 즉, 간선이 한 정점에서 다른 정점으로의 방향을 가집니다. 반면에 무방향 그래프(Undirected Graph)에서는 간선에 방향성이 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;가중치(Weight)&lt;/b&gt;: 간선에 연결된 두 정점 간의 관계를 나타내는 값으로, 예를 들어 거리, 비용, 시간 등을 나타낼 수 있습니다. 이러한 그래프를 가중 그래프(Weighted Graph)라고 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;사이클(Cycle)&lt;/b&gt;: 그래프에서 한 정점에서 시작하여 다시 같은 정점으로 돌아오는 경로를 말합니다.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;트리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리(Tree)는 비선형 자료구조로, 계층적인 관계를 가지는 데이터를 저장하는 데 사용됩니다. 트리는 한 노드가 다수의 자식 노드를 가질 수 있는 구조로, 부모-자식 관계를 가지는 그래프의 특별한 형태입니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;트리의 주요 특징은 다음과 같습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;루트(Root)&lt;/b&gt;: 트리의 최상위 노드로, 다른 모든 노드의 조상이 됩니다. 모든 경로는 루트에서부터 시작됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;부모(Parent)와 자식(Child)&lt;/b&gt;: 트리의 노드들은 부모-자식 관계를 가집니다. 부모 노드는 자식 노드를 가리키며, 자식 노드는 하나의 부모 노드를 가집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;리프(Leaf)&lt;/b&gt;: 자식이 없는 노드를 말합니다. 즉, 리프 노드는 트리의 가장 하위에 위치합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;간선(Edge)&lt;/b&gt;: 부모와 자식 노드를 연결하는 선을 말합니다. 트리에서는 각 노드들을 연결하는 간선의 수가 노드의 수보다 하나 작습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;높이(Height)&lt;/b&gt;: 트리의 최대 레벨을 높이라고 합니다. 즉, 루트 노드부터 리프 노드의 거리를 깊이를 의미합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;깊이(Depth)&lt;/b&gt;: 루트 노드부터 특정 노드까지의 경로 길이를 말합니다. 루트의 깊이는 0이며, 각 노드의 깊이는 부모의 깊이보다 1 증가합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;트리는 계층적인 구조를 효과적으로 표현하기 때문에 다양한 분야에서 사용됩니다. 예를 들어, 데이터베이스의 인덱스 구조, 파일 시스템의 디렉토리 구조, 계층적 조직 구조, 알고리즘의 재귀적 구현 등에 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;트리는 이진 트리(Binary Tree)를 포함하여 여러 종류로 확장될 수 있습니다. 이진 트리는 각 노드가 최대 두 개의 자식을 가지는 트리입니다. 또한, 이진 트리의 특별한 형태로 AVL 트리, 이진 탐색 트리(BST), 레드-블랙 트리 등의 자료구조가 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;트리의 종류&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;정이진 트리(full binary tree)&lt;/b&gt;: 자식 노드가 0 또는 두 개인 이진 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;완전 이진 트리(complete binary tree)&lt;/b&gt;: 왼쪽에서부터 채워져 있는 이진 트리. 마지막 레벨을 제외하고는 모든 레벨이 완전히 채워져 있으며, 마지막 레벨의 경우 왼쪽부터 채워져 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;변질 이진 트리(defenerate binary tree)&lt;/b&gt;: 자식 노드가 하나밖에 없는 이진 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;포화 이진 트리(perfect binary tree)&lt;/b&gt;: 모든 노드가 꽉 차있는 이진 트리&lt;/li&gt;
&lt;li&gt;&lt;b&gt;균형 이진 트리(balanced binary tree)&lt;/b&gt;: 왼쪽과 오른쪽 노드의 높이 차이가 1 이하인 이진 트리를 의미합니다. map, set을 구성하는 레드 블랙 트리는 균형 이진 트리 중 하나입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;이진 탐색 트리(BST)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이진 탐색 트리(Binary Search Tree)는 노드의 오른쪽 하위 츠리에는 노드 값보다 큰 값이 있는 노드만 포함되고, 왼쪽 하위 트리에는 노드 값보다 작은 값만 들어 있는 트리를 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 왼쪽 및 오른쪽 하위 트리도 해당 특성을 가집니다. 이렇게 두면&amp;nbsp;&lt;b&gt;검색&lt;/b&gt;을 하기에 용이합니다. 보통 요소를 찾을 때 이진 탐색 트리의 경우 O(logn)이 걸립니다. 하지만 최악의 경우 O(n)이 걸립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;AVL 트리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AVL 트리(Adelson-Velsky and Landis Tree)는 앞서 설명한 최악의 경우 선형적인 트리가 되는 것을 방지하고 스스로 균형을 잡는 이진 탐색 트리입니다. 두 자식 서브트리의 높이는 항상 최대 1만큼 차이 난다는 특징이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AVL 트리는 탐색, 삽입, 삭제가 모두 시간 복잡도가 O(logn)이며 삽입, 삭제를 할 때마다 균형이 안 맞는 것을 맞추기 위해 트리 일부를 왼쪽 혹은 오른쪽으로 회전시키며 균형을 잡습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;레드 블랙 트리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레드 블랙 트리는 균형 이진 탐색 트리로 탐색, 삽입, 삭제 모두 시간 복잡도가 O(logn)입니다. 각 노드는 빨간색 또는 검은색의 색상을 나타내는 추가 비트를 저장하며, 삽입 및 삭제 중에 트리가 균형을 유지하도록 하는 데 사용됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;힙 (Heap)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙은 완전 이진 트리 기반의 자료 구조이며, 최소힙과 최대합 두 가지가 있고 해당 힙에 따라 특정한 특징을 지킨 트리를 말합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;최대힙&lt;/b&gt;: 루트 노드에 있는 키는 모든 자식에 있는 키 중에서 가장 커야 합니다. 또한, 각 노드의 자식 노드와의 관계도 이와 같은 특징이 재귀적으로 이루어져야 합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;최소힙&lt;/b&gt;: 최소힙에서 루트 노드에 있는 키는 모든 자식에 있는 키 중에서 최소값이어야 합니다. 또한, 각 노드의 자식 노드와의 관계도 이와 같은 특징이 재귀적으로 이루어져야 합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;힙에는 어더한 값이 들어와도 특정 힙의 규칙을 지키게 만들어져 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;맵 (Map)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맵(Map)은 키(Key)와 값(Value)의 쌍으로 이루어진 자료구조입니다. 각 키는 고유하며, 키에 대응하는 값은 중복될 수 있습니다. 맵은 키를 사용하여 값을 검색하거나 저장하는 데 사용됩니다. 맵은 보통&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;맵의 주요 특징은 다음과 같습니다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;고유한 키&lt;/b&gt;: 맵은 각 키가 고유해야 합니다. 즉, 중복된 키를 허용하지 않습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;키-값 쌍 저장&lt;/b&gt;: 맵은 각 키와 값의 쌍을 저장합니다. 이를 통해 키를 사용하여 값에 빠르게 접근할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;검색과 삽입&lt;/b&gt;: 맵은 키를 사용하여 값을 검색하거나 삽입하는 데 효과적입니다. 키를 사용하여 값을 검색할 때는 일반적으로 O(1) 또는 O(log n)의 시간 복잡도를 가집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순서가 없음&lt;/b&gt;: 맵은 키-값 쌍의 순서를 보장하지 않습니다. 즉, 값들이 저장된 순서대로 반환되지 않습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;셋(Set)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Set은 유일한 요소들의 집합을 표현하며, 요소들의 순서를 보장하지 않습니다. Set은 중복을 허용하지 않고 고유한 요소를 저장하고 관리해야 할 때 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;해시 테이블 (Hash Table)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;해시 테이블은 무한에 가까운 데이터들을 유한한 개수의 해시 값으로 매핑한 테이블입니다. 삽입, 삭제, 탐색 시 평균적으로 O(1)의 시간 복잡도를 가집니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>CS</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/109</guid>
      <comments>https://hulrud.tistory.com/109#entry109comment</comments>
      <pubDate>Tue, 7 May 2024 23:51:04 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 컬렉션 프레임워크의 HashSet과 HashMap, HashTable과 Hashing이란</title>
      <link>https://hulrud.tistory.com/108</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;자바의 컬렉션 프레임워크인 HashSet, Hash Map과 HashTable과 Hashing에 대한 개념을 작성한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;HashSet&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;HashSet은 자&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;바 컬렉션 프레임워크(Collection Framework)에서 제공하는 Set 인터페이스를 구현한 클래스 중 하나입니다. Set의 특징대로 HashSet은 중복된 요소를 저장하지 않습니다. 또한 저장 순서를 유지하지 않으므로 저장 순서를 유지하고자 한다면 LinkedHashSet을 이용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;HashSet은 해시 테이블을 기반으로 하기 때문에 해시 함수에 의해 요소들이 저장되는 공간인 버킷(Bucket)으로 구성됩니다. 요소의 해시 코드를 계산하여 해당하는 버킷에 요소를 저장하고, 동일한 해시 코드를 가진 요소는 동일한 버킷에 저장됩니다. 따라서 HashSet에서 요소의 추가, 제거, 검색 연산은 요소의 해시 코드를 계산하여 해당하는 버킷에서만 수행하므로 상수 시간에 이루어집니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;HashSet에 새로운 요소를 추가할 때는 add 메서드나 addAll 메서드를 사용하는데, 만일 HashSet에 이미 저장되어 있는 요소와 중복된 요소를 추가하고자 한다면 이 메서드들은 false를 반환함으로써 중복된 요소이기 때문에 추가에 실패했다는 것을 알립니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 중복인 요소는 어떻게 알 수 있을까요? HashSet의 add 메서드는 새로운 요소를 추가하기 전에 기존에 저장된 요소와 같은 것으인지 판별하기 위해 추가하려는 요소의 equals()와 hashCode()를 호출하기 때문에 equals()와 hashCode()를 목적에 맞게 오버라이딩 해야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;중복 허용 안 함&lt;/b&gt;: HashSet은 중복된 요소를 허용하지 않습니다. 따라서 동일한 요소를 여러 번 추가해도 내부적으로는 하나의 요소만 유지됩니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순서가 없음&lt;/b&gt;: HashSet은 요소들의 순서를 보장하지 않습니다. 즉, 요소가 추가된 순서대로 저장되지 않으며, 반복문을 통해 요소를 순회할 때 예상한 순서대로 요소가 반환되지 않을 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;빠른 검색, 추가, 제거 연산&lt;/b&gt;: HashSet은 내부적으로 해시 함수를 사용하여 요소를 저장하므로, 검색, 추가, 제거 연산이 평균적으로 상수 시간(O(1))에 이루어집니다. (하지만 해시 충돌이 일났을 땐 O(n)의&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동기화 지원하지 않음&lt;/b&gt;: HashSet은 스레드 안전하지 않습니다. 따라서 멀티스레드 환경에서 사용할 때는 동기화 처리가 필요합니다. 동기화를 지원하는 HashSet의 대안으로는 ConcurrentHashMap을 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;null 요소 허용&lt;/b&gt;: HashSet은 null 값을 요소로 허용합니다. 따라서 null을 추가할 수 있고, null을 포함하는 HashSet을 생성할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 코드&lt;/h3&gt;
&lt;pre id=&quot;code_1714994042836&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.HashSet;

public class HashSetExample {
    public static void main(String[] args) {
        // HashSet 객체 생성
        HashSet&amp;lt;String&amp;gt; wordSet = new HashSet&amp;lt;&amp;gt;();

        // 문자열 배열에 단어 추가
        String[] words = {&quot;apple&quot;, &quot;banana&quot;, &quot;orange&quot;, &quot;apple&quot;, &quot;grape&quot;, &quot;banana&quot;, &quot;kiwi&quot;};

        // HashSet에 단어 추가
        for (String word : words) {
            wordSet.add(word);
        }

        // 중복된 단어가 제거된 HashSet 출력
        System.out.println(&quot;유일한 단어 목록:&quot;);
        for (String word : wordSet) {
            System.out.println(word);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;위 예제 코드의 출력 결과로는&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714994062116&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;유일한 단어 목록:
banana
grape
kiwi
orange
apple&lt;/code&gt;&lt;/pre&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;HashMap&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;HashMap은 자바 컬렉션 프레임워크(Collection Framework)에서 제공하는 Map 인터페이스를 구현한 클래스 중 하나입니다. HashMap은 키(key)와 값(value)으로 이루어진 데이터를 저장하는 자료구조로, 특정 키를 사용하여 값을 검색하거나 저장할 수 있습니다. HashMap은 해시 테이블(Hash Table)을 기반으로 구현되어 있어서 매우 빠른 검색, 삽입, 삭제 연산을 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;사실 앞서 소개한 HashSet도 내부적으로 HashMap으로 구현되어 있습니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;키-값 쌍 저장&lt;/b&gt;: HashMap은 키와 값의 쌍으로 이루어진 데이터를 저장합니다. 각 키는 고유해야 하며, 중복된 키는 허용되지 않습니다. 값은 중복되어도 상관없습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;해시 테이블 기반&lt;/b&gt;: HashMap은 내부적으로 해시 테이블을 사용하여 데이터를 저장합니다. 이는 매우 빠른 검색, 삽입, 삭제 연산을 가능하게 합니다. 평균적으로 이러한 연산들은 상수 시간(O(1))에 이루어집니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;동기화 지원하지 않음&lt;/b&gt;: HashMap은 스레드 안전하지 않습니다. 따라서 멀티스레드 환경에서 사용할 때는 동기화 처리가 필요합니다. 동기화를 지원하는 HashMap의 대안으로는 ConcurrentHashMap을 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;null 허용&lt;/b&gt;: HashMap은 키와 값으로 null을 허용합니다. 따라서 null을 키나 값으로 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;순서가 없음&lt;/b&gt;: HashMap은 내부적으로 해시 테이블을 사용하기 때문에 저장된 요소들의 순서를 보장하지 않습니다. 따라서 저장된 순서대로 요소를 접근할 수 없습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 코드&lt;/h3&gt;
&lt;pre id=&quot;code_1714995029493&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import java.util.HashMap;

public class HashMapExample {
    public static void main(String[] args) {
        // HashMap 객체 생성
        HashMap&amp;lt;String, Integer&amp;gt; hashMap = new HashMap&amp;lt;&amp;gt;();

        // 키-값 쌍 추가
        hashMap.put(&quot;apple&quot;, 100);
        hashMap.put(&quot;banana&quot;, 200);
        hashMap.put(&quot;orange&quot;, 150);

        // 값 검색
        int value = hashMap.get(&quot;banana&quot;);
        System.out.println(&quot;banana의 값: &quot; + value);

        // 키가 존재하는지 확인
        boolean containsKey = hashMap.containsKey(&quot;apple&quot;);
        System.out.println(&quot;apple이 존재하는가? &quot; + containsKey);

        // 키-값 쌍 제거
        hashMap.remove(&quot;orange&quot;);

        // 모든 키-값 쌍 출력
        System.out.println(&quot;HashMap의 모든 요소:&quot;);
        for (String key : hashMap.keySet()) {
            System.out.println(&quot;키: &quot; + key + &quot;, 값: &quot; + hashMap.get(key));
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;로드 팩터와 리해싱&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로드 팩터와 리해싱은 해시맵과 해시셋의 성능과 동적 크기 조정에 관하여 매우 중요한 개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;로드 팩터 (Load Factor)&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;로드 팩터 = (현재 요소 개수) / (해시 테이블 크기)&lt;/b&gt;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;로드 팩터가 1에 가까울수록 해시 테이블이 많이 채워져 있고, 충돌이 발생할 가능성이 높아집니다. 따라서 로드 팩터가 너무 높으면 해시 테이블의 성능이 저하될 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;로드 팩터는 해시맵이 얼마나 채워져 있는지를 나타내는 지표입니다. 보통 로드 팩터는 0.75로 설정됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;리해싱&lt;/h4&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;리해싱은 해시맵이 로드 팩터를 기준으로 자동으로 크기를 조정하는 과정을 말합니다. 해시맵이 로드 팩터의 임계값을 초과하면(예: 0.75), 해시맵은 내부적으로 크기를 두 배로 확장합니다. 이 과정에서 모든 요소는 새로운 크기의 배열에 다시 해싱됩니다. 이렇게 하면 해시 충돌이 줄어들고 성능이 유지됩니다. 반대로 해시맵이 로드 팩터의 하한값 미만으로 요소를 제거하면, 해시맵은 크기를 축소할 수도 있습니다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;자바에서는 해시맵과 해시셋의 생성자에서 로드 팩터 값을 지정할 수 있습니다.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;해싱과 해시함수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해싱(Hashing)이란 해시 함수(hash function)를 이용해서 데이터를 해시 테이블(hash table)에 저장하고 검색하는 기법을 말합니다. 해시 함수는 데이터가 저장되어 있는 곳을 알려 주기 때문에 다량의 데이터 중에서도 원하는 데이터를 빠르게 찾을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해싱을 구현한 컬렉션 클래스로는 HashSet, HashMap, Hashtable 등이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해싱에서 사용하는 자료구조는 배열이랑 링크드 리스트의 조합으로 되어 있습니다. 저장할 데이터의 키를 해시 함수에 넣으면 배열의 한 요소를 얻게 되고, 다시 그 곳에 연결되어 있는 링크드 리스트에 저장하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 링크드 리스트는 검색에 불리한 자료구조이기 때문에 링크드 리스트의 크기가 커질수록 검색 속도가 떨어지게 됩니다. 반면에 배열은 배열의 크기가 커져도 원하는 요소가 몇 번째에 있는지만 알면 아래의 공식에 의해 빠르게 원하는 값을 찾을 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;배열의 인덱스가 n인 요소의 주소 = 배열의 시작 주소 + type의 size * n&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 하나의 배열 요소에 긴 링크드 리스트가 저장되어 있는 형태보단 많은 서랍에 하나의 데이터만 저장되어 있는 형태가 더 빠른 검색결과를 얻을 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하나의 링크드 리스트에 최소한의 데이터만 저장되려면, 저장될 데이터의 크기를 고려해서 HashMap의 크기를 적절하게 지정해주어야 하고, 해시함수가 서로 다른 키에 대해 중복된 해시코드의 반환을 최소화해야 합니다. 그래야 HashMap에서 빠른 검색시간을 얻을 수 있다. 따라 해싱을 구현하는 과정에서 제일 중요한 것은 해시 함수의 알고리즘입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자바에서는 Object 클래스에 정의된 hashCode()를 사용합니다. Object 클래스에서 정의된 hashCode()는 객체의 주소를 이용하는 알고리즘으로 해시코드를 만들어내기 때문에 모든 객체에 대해 hashCode()를 호출한 결과가 서로 유일한 훌륭한 방법이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming Language/Java</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/108</guid>
      <comments>https://hulrud.tistory.com/108#entry108comment</comments>
      <pubDate>Mon, 6 May 2024 22:46:31 +0900</pubDate>
    </item>
    <item>
      <title>[CS]  선형 자료구조에 대해 알아보자 (연결 리스트 / 배열 / 백터 / 스택 / 큐)</title>
      <link>https://hulrud.tistory.com/107</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;선형 자료구조인 연결 리스트, 배열, 벡터, 스택, 큐에 대해 작성한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;선형 자료구조 (Linear Data Structure)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;선형 자료구조(Linear Data Structure)는 데이터 요소들이 선형적인 순서로 배열되어 있는 자료구조를 의미합니다. 이러한 자료구조에서는 데이터 요소들이 일렬로 연결되어 있으며, 각 요소는 이전 요소와 다음 요소로 직접적으로 연결되어 있습니다. 주요 특징으로는 데이터 요소들의 순서가 고정되어 있고, 각 요소들 간에는 순차적인 관계가 존재합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;연결 리스트 (Linked List)&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;연결 리스트(Linked List)는 데이터 요소(Node)가 &lt;b&gt;데이터와 다음 요소를 가리키는 포인터로 이루어진 노드들의 집합&lt;/b&gt;입니다. 각 노드는 다음 노드를 가리키는 포인터(참조)를 가지고 있어서 이전 노드와 다음 노드 사이의 연결을 형성합니다. 연결 리스트에서는 &lt;b&gt;데이터 요소들이 메모리에 연속적으로 저장되지 않고, 동적으로 할당된 메모리 공간에 흩어져 있습니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;b&gt;삽입과 삭제가 O(1)&lt;/b&gt;이 걸리며&lt;b&gt; 탐색에서는 O(n)&lt;/b&gt;이 걸립니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연결 리스트에는 크게 세가지 유형이 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #ffffff; color: #0d0d0d; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;단일 연결 리스트: 각 노드가&lt;b&gt; 데이터와 다음 노드를 가리키는 포인터&lt;/b&gt;로 이루어져 있습니다.&lt;/li&gt;
&lt;li&gt;이중 연결 리스트: 각 노드가 &lt;b&gt;데이터와 이전 노드를 가리키는 포인터와 다음 노드를 가리키는 포인터&lt;/b&gt;로 이루어져 있습니다.&lt;/li&gt;
&lt;li&gt;원형 연결 리스트: &lt;b&gt;마지막 노드가 첫 번째 노드를 가리키는 원형 형태&lt;/b&gt;로 구성된 연결 리스트입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2516&quot; data-origin-height=&quot;908&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpVWmY/btsHdeVZoVC/MaWejdiYQjQKnDHL4ekXc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpVWmY/btsHdeVZoVC/MaWejdiYQjQKnDHL4ekXc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpVWmY/btsHdeVZoVC/MaWejdiYQjQKnDHL4ekXc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbpVWmY%2FbtsHdeVZoVC%2FMaWejdiYQjQKnDHL4ekXc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2516&quot; height=&quot;908&quot; data-origin-width=&quot;2516&quot; data-origin-height=&quot;908&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원형 연결 리스트는 마지막 next가 head를 가리킵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 연결 리스트를 자바 코드로 구현해보면 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1714829843160&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Node {
    int data;
    Node next;

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}

class SinglyLinkedList {
    private Node head;

    public SinglyLinkedList() {
        this.head = null;
    }

    // 연결 리스트에 요소 추가
    public void add(int data) {
        Node newNode = new Node(data);
        if (head == null) {
            head = newNode;
        } else {
            Node current = head;
            while (current.next != null) {
                current = current.next;
            }
            current.next = newNode;
        }
    }

    // 연결 리스트 출력
    public void display() {
        Node current = head;
        while (current != null) {
            System.out.print(current.data + &quot; &quot;);
            current = current.next;
        }
        System.out.println();
    }
}

public class Main {
    public static void main(String[] args) {
        SinglyLinkedList list = new SinglyLinkedList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.display(); // 출력: 1 2 3
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;배열 (Array)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 정적 배열 기반으로 설명합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;배열은 &lt;b&gt;동일한 데이터 형식의 요소들을 순차적으로 저장하는 선형 자료구조&lt;/b&gt;입니다. 배열은 &lt;b&gt;메모리에 연속적으로 할당&lt;/b&gt;되며 각 요소는 인덱스를 사용하여 접근할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;탬색에 O(1)이 되어 랜덤 액세스가 가능합니다. 하지만 &lt;b&gt;삽입과 삭제에는 O(n)이 걸립니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;배열은 인덱스에 해당하는 원소를 빠르게 접근해야 할 때 주로 사용합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;랜덤 액세스와&amp;nbsp; 시퀄셜 액세스&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;랜덤 액세스(random access)란 데이터 구조에서 임의의 위치에 있는 데이터 요소에 직접적으로 접근할 수 있는 능력을 가리킵니다. 이는 데이터 구조에서 요소들이 연속적으로 저장되어 있고 각 요소가 고유한 인덱스를 가지고 있어 특정 인덱스를 사용하여 요소에 빠르게 접근할 수 있는 경우를 의미합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;순차적 액세스(Sequential Access)는 데이터 구조에서 요소들을 순차적으로 접근하는 방법을 의미합니다. 즉, 특정 요소에 접근하기 위해서는 그 이전 요소들을 순차적으로 탐색해야 함을 의미합니다. 앞서 소개한 연결 리스트가 순차적 접근 방식을 사용하기 때문에 탐색에 소요되는 시간 복잡도가 O(n)입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;벡터 (Vector)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;벡터(Vector)&quot;는 프로그래밍에서 &lt;b&gt;동적 배열(dynamic array)&lt;/b&gt;을 구현하는 자료구조 중 하나입니다. 벡터는 배열과 유사하게 &lt;b&gt;연속된 메모리 공간에 요소들을 저장하지만, 크기가 동적으로 조절될 수 있습니다.&lt;/b&gt; 즉, 배열과 달리 &lt;b&gt;초기에 크기를 지정하지 않고도 요소를 추가하거나 삭제할 수 있다는 것을 의미&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;b&gt;탐색과 맨 앞 또는 맨 뒤의 요소를 삭제하는 데 O(1)&lt;/b&gt;이 걸리며, 맨 뒤나 맨 앞이 아닌 &lt;b&gt;요소를 삭제하고 삽입하는 데 O(n)&lt;/b&gt;이 걸립니다. 뒤에서부터 삽입하는 경우 벡터의 크기가 증가되는 시간 복잡도가 amortized 복잡도, 즉 상수 시간 복잡도와 유사한 복잡도를 가지고 있기 때문에 O(1)의 시간 복잡도를 가지게 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서는 java.util 패키지에 있는 Vector 클래스를 사용하여 벡터를 구현할 수 있습니다. Vector 클래스는 동적으로 크기가 조절되는 배열을 구현하며, 배열의 크기가 부족할 때마다 자동으로 크기를 조절합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 자바의 Vertor 클래스는 &lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;스레드 안전(thread-safe)하도록 동기화되어 있습니다. 따라서 멀티스레드 환경에서 안전하게 사용할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;스택 (Stack)&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;스택은 &lt;b&gt;LIFO(Last In First Out)&lt;/b&gt;을 가진 자료 구조입니다. 즉, 가장 마지막으로 들어간 데이터가 가장 첫번째로 나오는 성질이 있습니다. 스택은&amp;nbsp;&lt;b&gt;재귀적인 함수, 알고리즘에 사용&lt;/b&gt;됩니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;스택에서 요소를 추가하는 작업을 &quot;&lt;b&gt;push&lt;/b&gt;&quot;라고 하고, 요소를 제거하는 작업을 &quot;&lt;b&gt;pop&lt;/b&gt;&quot;이라고 합니다. push와 pop 연산은 O(1)이 걸립니다. 하지만 탐색에서는 O(n)이 걸립니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;1406&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGBKOa/btsHa32VY45/9kgywzxuLduRkaXRxDNWGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGBKOa/btsHa32VY45/9kgywzxuLduRkaXRxDNWGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGBKOa/btsHa32VY45/9kgywzxuLduRkaXRxDNWGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGBKOa%2FbtsHa32VY45%2F9kgywzxuLduRkaXRxDNWGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;545&quot; height=&quot;507&quot; data-origin-width=&quot;1510&quot; data-origin-height=&quot;1406&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Java에서는 java.util 패키지에 있는 Stack 클래스를 사용하여 스택을 구현할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;아래 예제 코드에서는 Stack 클래스를 사용하지 않고 Stack을 구현해 보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714831962507&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Stack {
    private int maxSize;    // 스택의 최대 크기
    private int[] stackArray; // 스택을 저장할 배열
    private int top;        // 스택의 맨 위 요소를 가리키는 인덱스

    // 생성자: 스택의 크기를 지정하여 스택을 초기화합니다.
    public Stack(int size) {
        this.maxSize = size;
        this.stackArray = new int[maxSize];
        this.top = -1;  // 스택이 비어있음을 나타내는 값
    }

    // push: 스택에 요소를 추가합니다.
    public void push(int value) {
        if (isFull()) {
            System.out.println(&quot;스택이 가득 찼습니다. 요소를 추가할 수 없습니다.&quot;);
            return;
        }
        stackArray[++top] = value;
    }

    // pop: 스택의 맨 위 요소를 제거하고 반환합니다.
    public int pop() {
        if (isEmpty()) {
            System.out.println(&quot;스택이 비어있습니다. 요소를 제거할 수 없습니다.&quot;);
            return -1;  // 임의의 값 반환
        }
        return stackArray[top--];
    }

    // peek: 스택의 맨 위 요소를 반환합니다.
    public int peek() {
        if (isEmpty()) {
            System.out.println(&quot;스택이 비어있습니다. 요소를 확인할 수 없습니다.&quot;);
            return -1;  // 임의의 값 반환
        }
        return stackArray[top];
    }

    // isEmpty: 스택이 비어있는지 확인합니다.
    public boolean isEmpty() {
        return (top == -1);
    }

    // isFull: 스택이 가득 찼는지 확인합니다.
    public boolean isFull() {
        return (top == maxSize - 1);
    }
    
    // 스택의 내용을 출력합니다.
    public void display() {
        System.out.print(&quot;현재 스택: &quot;);
        for (int i = 0; i &amp;lt;= top; i++) {
            System.out.print(stackArray[i] + &quot; &quot;);
        }
        System.out.println();
    }
    
    public static void main(String[] args) {
        Stack stack = new Stack(5);  // 크기가 5인 스택 생성

        // 요소 추가
        stack.push(10);
        stack.push(20);
        stack.push(30);

        // 스택 출력
        stack.display(); // 출력: 10 20 30

        // 맨 위 요소 확인
        System.out.println(&quot;맨 위 요소: &quot; + stack.peek()); // 출력: 30

        // 요소 제거
        stack.pop();

        // 스택 출력
        stack.display(); // 출력: 10 20
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;br /&gt;큐 (Queue)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;큐는 &lt;b&gt;FIFO(First In First Out)&lt;/b&gt;성질을 가진 자료구조 입니다. 즉, 먼저 삽입된 데이터가 가장 첫번째로 나옵니다. 나중에 집어넣은 데이터가 가장 먼저 나오는 스택과는 반대되는 개념을 가졌습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;큐에서 요소를 추가하는 작업을 &quot;&lt;b&gt;enqueue&lt;/b&gt;&quot;라고 하고, 요소를 제거하는 작업을 &quot;&lt;b&gt;dequeue&lt;/b&gt;&quot;라고 합니다.&amp;nbsp; &lt;/span&gt;&lt;b&gt;삽입 및 삭제에 O(1), 탐색에 O(n)&lt;/b&gt;이 걸립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: left;&quot;&gt;큐를 사용하면 선입선출의 특성을 활용하여 요소들을 순서대로 처리할 수 있습니다. 예를 들어, 너비 우선 탐색(Breadth-First Search, BFS)과 같은 알고리즘에서 사용됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2232&quot; data-origin-height=&quot;1166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlZwF4/btsHcsNVUyG/NLeF5FY2XvcZMRCg41hN5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlZwF4/btsHcsNVUyG/NLeF5FY2XvcZMRCg41hN5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlZwF4/btsHcsNVUyG/NLeF5FY2XvcZMRCg41hN5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdlZwF4%2FbtsHcsNVUyG%2FNLeF5FY2XvcZMRCg41hN5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2232&quot; height=&quot;1166&quot; data-origin-width=&quot;2232&quot; data-origin-height=&quot;1166&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;Java에서는 java.util 패키지에 있는 Queue 인터페이스를 사용하여 큐를 구현할 수 있습니다. Queue 인터페이스를 구현한 여러 클래스 중에서 가장 일반적인 것은 LinkedList 클래스입니다. LinkedList는 이중 연결 리스트를 기반으로하여 큐를 구현합니다. 그리고 java.util.concurrent 패키지에 있는 ConcurrentLinkedQueue 클래스는 스레드 세이프(concurrent) 큐를 제공합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1714833075609&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Queue {
    private int maxSize;    // 큐의 최대 크기
    private int[] queueArray; // 큐를 저장할 배열
    private int front;       // 큐의 맨 앞 요소를 가리키는 인덱스
    private int rear;        // 큐의 맨 뒤 요소를 가리키는 인덱스
    private int nItems;      // 현재 큐에 있는 요소의 개수

    // 생성자: 큐의 크기를 지정하여 큐를 초기화합니다.
    public Queue(int size) {
        this.maxSize = size;
        this.queueArray = new int[maxSize];
        this.front = 0;
        this.rear = -1;
        this.nItems = 0;
    }

    // enqueue: 큐에 요소를 추가합니다.
    public void enqueue(int value) {
        if (isFull()) {
            System.out.println(&quot;큐가 가득 찼습니다. 요소를 추가할 수 없습니다.&quot;);
            return;
        }
        if (rear == maxSize - 1) {
            rear = -1; // rear 인덱스를 0으로 되돌립니다.
        }
        queueArray[++rear] = value; // rear를 증가시킨 후 요소를 추가합니다.
        nItems++; // 요소 개수를 증가시킵니다.
    }

    // dequeue: 큐에서 요소를 제거하고 반환합니다.
    public int dequeue() {
        if (isEmpty()) {
            System.out.println(&quot;큐가 비어있습니다. 요소를 제거할 수 없습니다.&quot;);
            return -1; // 임의의 값 반환
        }
        int temp = queueArray[front++]; // front를 증가시킨 후 요소를 반환합니다.
        if (front == maxSize) {
            front = 0; // front 인덱스를 0으로 되돌립니다.
        }
        nItems--; // 요소 개수를 감소시킵니다.
        return temp;
    }

    // peek: 큐의 맨 앞 요소를 반환합니다.
    public int peek() {
        if (isEmpty()) {
            System.out.println(&quot;큐가 비어있습니다. 요소를 확인할 수 없습니다.&quot;);
            return -1; // 임의의 값 반환
        }
        return queueArray[front];
    }

    // isEmpty: 큐가 비어있는지 확인합니다.
    public boolean isEmpty() {
        return (nItems == 0);
    }

    // isFull: 큐가 가득 찼는지 확인합니다.
    public boolean isFull() {
        return (nItems == maxSize);
    }

    // 현재 큐의 내용을 출력합니다.
    public void display() {
        System.out.print(&quot;현재 큐: &quot;);
        int current = front;
        for (int i = 0; i &amp;lt; nItems; i++) {
            System.out.print(queueArray[current++] + &quot; &quot;);
            if (current == maxSize) {
                current = 0; // current 인덱스가 배열의 끝에 도달하면 0으로 되돌립니다.
            }
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Queue queue = new Queue(5);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족한 글이 도움이 되길 바랍니다. 읽어주셔서 감사합니다!&lt;/p&gt;</description>
      <category>CS</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/107</guid>
      <comments>https://hulrud.tistory.com/107#entry107comment</comments>
      <pubDate>Sat, 4 May 2024 23:34:45 +0900</pubDate>
    </item>
    <item>
      <title>[SpringBoot] Github Action을 이용한 CI/CD (ElasticBeanstalk)</title>
      <link>https://hulrud.tistory.com/106</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;CI/CD란 무엇인지, SpringBoot 프로젝트를 Github Action을 이용하여 CI/CD를 하는 방법에 대해 작성한 글입니다.&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  준비 사항&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 배포할 SpringBoot 프로젝트&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. (1) 프로젝트와 연동되어있는 Github Repository&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. SpringBoot 프로젝트가 배포되어 있는 우분투 서버&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚡️ 참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 스프링 버전 3.2.3을 사용하고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. Elastic Beanstalk 서버를 배포중입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CI/CD란?&amp;nbsp;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #151515; text-align: start;&quot;&gt;CI/CD는 지속적 통합(Continuous Integration) 및 지속적 제공/배포(Continuous Delivery/Deployment)를 의미하며, 소프트웨어 개발 라이프사이클을 간소화하고 가속화하는 것을 목표로 하는 방법론 입니다.&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&amp;nbsp;(도구를 의미하는 것이 아닙니다!) &lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;CI/CD 방법론을 따르면 빌드부터 배포까지의 과정을 자동화할 수 있고, 배포가 잘 되는지 모니터링 할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;CI와 CD를 나눠서 설명해 보겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;CI : 지속적 통합&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;CI는 Continuous Intergration(지속적 통합)을 줄인 표현입니다. 좀 더 구체적으로는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;빌드와 테스트를 자동화 하는 과정&lt;/span&gt;이라고 설명할 수 있습니다. CI는 변경 사항을 자동으로 테스트해 애플리케이션에 문제가 없다는 것을 보장합니다. 그리고 코드를 정기적으로 빌드하고, 테스트하므로 여려 명이 동시에 작업을 하는 경우 충돌을 방지하고 모니터링 할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;코드 변경 사항이 코드 저장소에 업로드되면 CI를 시작하고, CI 도중 문제가 생기면 실패하드로 코드의 오류도 쉽게 파악할 수 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;CD : 지속적 제공과 지속적 배포&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;CD는 CI 작업을 끝낸 다음 실행하는 작업입니다.&lt;b&gt; 배포 준비가 된 코드를 자동으로 서버에 배포&lt;/b&gt;하는 작업을 자동화하는 것입니다. CI가 통과되면 개발자가 수작업으로 코드를 배포하지 않아도 자동으로 배포하니 개발자는 더욱 편리해 지겠죠. 따라 CD는 Continuous Delivery라는 지속적 제공과 Continuous Deployment라는 두 가지 의미를 가집니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;지속적 제공&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;애플리케이션에 적용한 코드의 빌드와 테스트를 성공적으로 진행했을 때 깃허브와 같은 코드 저장소에 자동으로 업로드하는 과정을 말합니다. 최소의 노력으로 코드 배포를 쉽게 하는 것을 목표로 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;지속적 배포&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;지속적 제공을 통해 성공적으로 병합한 코드 내역을 AWS와 같은 배포 환경으로 보내는 것을 의미합니다. (실무에서는 릴리즈라고 합니다.) 지속적인 배포는 지속적 제공의 다음 단계까지 자동화합니다. 즉, 개발자가 애플리케이션에 변경 사항을 커밋한 후 몇 분 이내에 애플리케이션을 자동으로 배포되어 적용됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;깃허브 액션&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브 액션(Github Actions)은 깃허브에서 제공하는 서비스입니다. 리포지토리에 특정 이벤트가 발생하면 특정 작업을 하거나 주기적으로 특정 작업을 반복할 수 있게 합니다. 예를 들어 누군가 코드를 작성해 깃허브에 업데이트하면 해당 코드에 문제가 없는지 자동으로 코드를 빌드, 테스트한 이후 배포까지 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CI 스크립트 작성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 프로젝트를 열어주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 루트에 .github 폴더 를 생성하고, 그 안에 workflows 폴더를 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;workflows 폴더 안에 ci.yml 파일을 추가합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;196&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AQDD2/btsGZMTD2Dg/dFXEChuXsKbk86PiX19ikk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AQDD2/btsGZMTD2Dg/dFXEChuXsKbk86PiX19ikk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AQDD2/btsGZMTD2Dg/dFXEChuXsKbk86PiX19ikk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAQDD2%2FbtsGZMTD2Dg%2FdFXEChuXsKbk86PiX19ikk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;818&quot; height=&quot;196&quot; data-origin-width=&quot;818&quot; data-origin-height=&quot;196&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ci.yml의 다음 코드를 작성합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1714197814543&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 워크플로우의 이름
name: CI

# 워크플로우가 시작될 조건
# main branch에서 push작업이 일어났을 때
on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest # 실행 환경
    # 실행 스텝 지정
    steps:
      # uses: 지정한 리포지터리를 확인하고 코드에 대한 작업 실행
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
            distribution: 'zulu'
            java-version: '17'
      # name: 스텝의 이름
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      - name: Build with Gradle
        run: ./gradlew clean build&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;추가한 파일을 다음 명령어로 리포지토리에 푸시합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1714197856423&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git add .
git commit -m &quot;CI 추가&quot;
git push origin main&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리포지토리에 Actions에 워크플로우가 보이고 파란색 체크 모양이 보인다면 성공입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2600&quot; data-origin-height=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNMYFp/btsG0GkXXD1/zNKzKTwxN2zqkRuwbVqyt1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNMYFp/btsG0GkXXD1/zNKzKTwxN2zqkRuwbVqyt1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNMYFp/btsG0GkXXD1/zNKzKTwxN2zqkRuwbVqyt1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNMYFp%2FbtsG0GkXXD1%2FzNKzKTwxN2zqkRuwbVqyt1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2600&quot; height=&quot;750&quot; data-origin-width=&quot;2600&quot; data-origin-height=&quot;750&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2178&quot; data-origin-height=&quot;1758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TyfcC/btsGYQWVqz4/s0MMmmWyxkZOCjDvJi1Vg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TyfcC/btsGYQWVqz4/s0MMmmWyxkZOCjDvJi1Vg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TyfcC/btsGYQWVqz4/s0MMmmWyxkZOCjDvJi1Vg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTyfcC%2FbtsGYQWVqz4%2Fs0MMmmWyxkZOCjDvJi1Vg1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2178&quot; height=&quot;1758&quot; data-origin-width=&quot;2178&quot; data-origin-height=&quot;1758&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 추가로 secret을 사용하여 gitignore 상태의 파일을 만드는 것까지 했는데, 이와 관련된 게시물을 추후에 작성하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;CD 작성하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 build.gradle에서 빌드 jar 파일만 생성하도록 그레이들 파일에 다음 코드를 작성해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1714199391732&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;jar {
     enabled = false
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 ci.yml 파일을 cicd.yml로 파일 이름을 바꿉니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;182&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUCiOH/btsGZVJHwPF/TdeErHhV9pjOIVRkTa3fJ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUCiOH/btsGZVJHwPF/TdeErHhV9pjOIVRkTa3fJ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUCiOH/btsGZVJHwPF/TdeErHhV9pjOIVRkTa3fJ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUCiOH%2FbtsGZVJHwPF%2FTdeErHhV9pjOIVRkTa3fJ0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;786&quot; height=&quot;182&quot; data-origin-width=&quot;786&quot; data-origin-height=&quot;182&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일의 맨 아래에 다음 코드를 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY는 AWS IAM 사용자의 Key ID와 Secret입니다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1714200269907&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;      # CD
      # 현재 시간 가져오기
      - name: Get current Time
        uses: josStorer/get-current-time@v2.0.2
        id: current-time
        with:
          format: YYYY-MM-DDTHH-mm-ss
          utcOffset: &quot;+09:00&quot;

      # 배포용 패키지 경로 저장
      - name: Set artifact
        run: echo &quot;artifact=$(ls ./build/libs)&quot; &amp;gt;&amp;gt; $GITHUB_ENV

      # 빈스토크 배포
      - name: Beanstalk Deploy
        uses: einaregilsson/beanstalk-deploy@v20
        with:
          aws_access_key: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws_secret_key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          application_name: byeolukye
          environment_name: Byeolukye-env
          version_label: github-action-${{steps.current-time.outputs.formattedTime}}
          region: ap-northeast-2
          deployment_package: ./&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;깃허브 시크릿을 추가하도록 하겠습니다. 프로젝트 리포지토리 &amp;gt; Setting &amp;gt; Security &amp;gt; Secrets and variables &amp;gt; New Repository Secret&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Secret에는 각각 IAM 사용자의 Key ID와 Secret을 작성합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/J0761/btsGZXAFaHf/cKPKz4YkvkspNeufDMfDO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/J0761/btsGZXAFaHf/cKPKz4YkvkspNeufDMfDO0/img.png&quot; data-origin-width=&quot;2554&quot; data-origin-height=&quot;1464&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4945%; margin-right: 10px;&quot; data-widthpercent=&quot;50.08&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/J0761/btsGZXAFaHf/cKPKz4YkvkspNeufDMfDO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJ0761%2FbtsGZXAFaHf%2FcKPKz4YkvkspNeufDMfDO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2554&quot; height=&quot;1464&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Z2nQ1/btsG0dQSw9l/abNkotIVNvuPZIWsQO015K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Z2nQ1/btsG0dQSw9l/abNkotIVNvuPZIWsQO015K/img.png&quot; data-origin-width=&quot;2814&quot; data-origin-height=&quot;1618&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.3427%;&quot; data-widthpercent=&quot;49.92&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Z2nQ1/btsG0dQSw9l/abNkotIVNvuPZIWsQO015K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FZ2nQ1%2FbtsG0dQSw9l%2FabNkotIVNvuPZIWsQO015K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2814&quot; height=&quot;1618&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cicd 파일을 커밋 한 후 push 하면 빌드 완료 후 ElasticBeanstalk를 통해 배포됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2236&quot; data-origin-height=&quot;1562&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Iq13D/btsGZy82ZhT/DTtNuVD9BR6eOck5ToW6Y0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Iq13D/btsGZy82ZhT/DTtNuVD9BR6eOck5ToW6Y0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Iq13D/btsGZy82ZhT/DTtNuVD9BR6eOck5ToW6Y0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIq13D%2FbtsGZy82ZhT%2FDTtNuVD9BR6eOck5ToW6Y0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2236&quot; height=&quot;1562&quot; data-origin-width=&quot;2236&quot; data-origin-height=&quot;1562&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2288&quot; data-origin-height=&quot;368&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cGtYPy/btsGYOyaTDu/gtwYV6N7oT2bL3Ev3xrPx0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGtYPy/btsGYOyaTDu/gtwYV6N7oT2bL3Ev3xrPx0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGtYPy/btsGYOyaTDu/gtwYV6N7oT2bL3Ev3xrPx0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGtYPy%2FbtsGYOyaTDu%2FgtwYV6N7oT2bL3Ev3xrPx0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2288&quot; height=&quot;368&quot; data-origin-width=&quot;2288&quot; data-origin-height=&quot;368&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족한 글 읽어주셔서 감사합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;궁금한 점이 있다면 댓글을 달아주세요 :)&lt;/p&gt;</description>
      <category>Framework/SpringBoot</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/106</guid>
      <comments>https://hulrud.tistory.com/106#entry106comment</comments>
      <pubDate>Sat, 27 Apr 2024 15:51:55 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] AWS S3를 알아보고 버킷 만들어보기</title>
      <link>https://hulrud.tistory.com/105</link>
      <description>&lt;blockquote data-ke-style=&quot;style3&quot;&gt;S3를 알아보고, 실제 S3 서비스를 이용하는 방법을 작성한 글입니다&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  사전 준비&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. AWS 회원가입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. SpringBoot 3.2.3 버전 프로젝트 (3.x.x 버전은 모두 무관합니다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Amazon S3&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Amazone Simple Storage Service(S3)&lt;/b&gt;는 AWS에서 제공하는 객체 스토리지 서비스입니다. &lt;b&gt;스토리지&lt;/b&gt;란 데이터를 저장하는 장소를 말하며, &lt;b&gt;객체&lt;/b&gt;란 텍스트 파일이나 이미지 파일과 같은 데이터를 말합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객체 스토리지는 기존의 파일 스토리지처럼 폴더 구조는 갖지 않고 객체 키로 데이터를 고유하게 식별해 데이터의 입출력과 관리를 수행합니다. 키만으로 데이터를 관리하기 때문에 간편하게 대용량의 데이터를 저장하고 관리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3는 정적 콘텐츠만 있는 HTML 페이지를 만들고 싶다면 이미지, HTML, CSS 파일 등을 저장해 웹사이트처럼 운영할 수 있고, 로그 분석 시스템을 만들기 위해 응용 프로그램의 로그를 실시간으로 저장하는 용도로 사용할 수도 있습니다. (객체 키만으로 관리되기 때문에 대량 로그 보존에도 충분히 활용할 수 있습니다.)&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;S3의 특징&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3는 다음과 같은 특징을 가집니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;용량 무제한&lt;/span&gt;: 객체당 5TB라는 제약이 있지만 객체 수나 데이터 용량에는 제한이 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;높은 내구성&lt;/span&gt;: 일반적으로 데이터가 3개 이상의 AZ로 복사됩니다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;저렴한 비용&lt;/span&gt;: 서울 리전의 표준 스토리지 요금은 1개월당 0.025USD로 매우 저렴한 편입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;S3에서 사용되는 용어&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 S3에 사용되는 용어들입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;버킷&lt;/span&gt;: 객체를 저장하는 장소입니다. 버킷의 이름은 모든 리전에서 고유해야 합니다. 즉, 중복되는 이름의 버킷을 생성할 수 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;객체&lt;/span&gt;: 버킷에 저장된 데이터를 말합니다. 버킷에는 객체를 무제한으로 저장할 수 있지만 한 객체의 최대 크기는 5TB를 넘을 수 없습니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;키&lt;/span&gt;: 객체의 저장 URL 경로입니다. 버킷 이름과 키 이름, 객체 이름을 조합해 고유하게 설정됩니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예시: s3://example-bucket/folder/object.png&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;S3 API&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S3는 데이터를 등록하거나 삭제하는 API를 제공합니다. 따라 이를 호출해 S3의 객체를 조작할 수 있습니다.&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;GET&lt;/span&gt;: S3에서 객체를 다운로드&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;PUT&lt;/span&gt;: S3에 객체를 업로드, 신규 업로드, 갱신, 하나의 PUT 작업은 최대 5GB까지로 더 많은 데이터를 업로드 하는 경우 멀티 파트 업로드라는 기능을 이용해 여러 파트로 나눠 최대 5TB의 데이터를 업로드 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;LIST&lt;/span&gt;: S3 버킷 내의 객체 목록을 표시합니다. 데이터 추출 또한 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;COPY&lt;/span&gt;: S3 내에서 객체를 복사, 다른 버킷과 리전간의 복사가 가능합니다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;DELETE&lt;/span&gt;: S3 내에 있는 객체를 삭제합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;S3 서비스 이용하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS 콘솔 &amp;gt; S3 &amp;gt; 버킷 &amp;gt; 버킷 만들기 클릭&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2958&quot; data-origin-height=&quot;852&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qYpeg/btsGZXUTJ2Q/CaU7IDQFuPoWhstJdNVL51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qYpeg/btsGZXUTJ2Q/CaU7IDQFuPoWhstJdNVL51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qYpeg/btsGZXUTJ2Q/CaU7IDQFuPoWhstJdNVL51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqYpeg%2FbtsGZXUTJ2Q%2FCaU7IDQFuPoWhstJdNVL51%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2958&quot; height=&quot;852&quot; data-origin-width=&quot;2958&quot; data-origin-height=&quot;852&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;범용 설정, 버킷 이름 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 AWS 리전이 서울이 아니라면 오른쪽 상단에서 리전을 서울로 바꿔줍니다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;690&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UQDFT/btsGY9V5CTD/9UGvIn671uIJmLYSIkvmK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UQDFT/btsGY9V5CTD/9UGvIn671uIJmLYSIkvmK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UQDFT/btsGY9V5CTD/9UGvIn671uIJmLYSIkvmK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUQDFT%2FbtsGY9V5CTD%2F9UGvIn671uIJmLYSIkvmK1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1568&quot; height=&quot;690&quot; data-origin-width=&quot;1568&quot; data-origin-height=&quot;690&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 업로드 및 조회 서비스를 구현하거나, 정적 콘텐츠를 서빙하실 분들은&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;퍼블릭 액세스 차단 설정을 모두 해제합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 노란색 박스 안 체크박스에 체크를 눌러주세요&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;1204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1wUgV/btsGY8v6XNy/BfqeJGTAta4u3g4RoZvV2K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1wUgV/btsGY8v6XNy/BfqeJGTAta4u3g4RoZvV2K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1wUgV/btsGY8v6XNy/BfqeJGTAta4u3g4RoZvV2K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1wUgV%2FbtsGY8v6XNy%2FBfqeJGTAta4u3g4RoZvV2K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1522&quot; height=&quot;1204&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;1204&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 버킷이 생성됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2102&quot; data-origin-height=&quot;382&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6EbSt/btsGZA6PxJH/AW99DgIba18qXcWvNMAYr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6EbSt/btsGZA6PxJH/AW99DgIba18qXcWvNMAYr1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6EbSt/btsGZA6PxJH/AW99DgIba18qXcWvNMAYr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6EbSt%2FbtsGZA6PxJH%2FAW99DgIba18qXcWvNMAYr1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2102&quot; height=&quot;382&quot; data-origin-width=&quot;2102&quot; data-origin-height=&quot;382&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일을 업로드해보겠습니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버킷 이름 &amp;gt; 업로드 &amp;gt; 파일 추가 &amp;gt; 업로드&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;1656&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t7653/btsG0s1pYMP/EV8y56tLFFJ0JRJi2kflAk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t7653/btsG0s1pYMP/EV8y56tLFFJ0JRJi2kflAk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t7653/btsG0s1pYMP/EV8y56tLFFJ0JRJi2kflAk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft7653%2FbtsG0s1pYMP%2FEV8y56tLFFJ0JRJi2kflAk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1826&quot; height=&quot;1656&quot; data-origin-width=&quot;1826&quot; data-origin-height=&quot;1656&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;업로드 하고 나서 객체를 클릭하면 S3 URI와 URL을 볼 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2862&quot; data-origin-height=&quot;490&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dktIOb/btsGY5TLSRB/8HMldLKCXNb38QRWrOrrz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dktIOb/btsGY5TLSRB/8HMldLKCXNb38QRWrOrrz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dktIOb/btsGY5TLSRB/8HMldLKCXNb38QRWrOrrz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdktIOb%2FbtsGY5TLSRB%2F8HMldLKCXNb38QRWrOrrz0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2862&quot; height=&quot;490&quot; data-origin-width=&quot;2862&quot; data-origin-height=&quot;490&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 본인의 서비스에서 S3 버킷을 사용하는 분들이라면 (파일 업로드 및 조회 기능 등...) 다음 IAM 설정도 따라해 주시길 바랍니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IAM 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;콘솔 &amp;gt; IAM &amp;gt; 사용자 &amp;gt; 사용자 생성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2982&quot; data-origin-height=&quot;966&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dbOkIz/btsGZlWnBal/H8PSnru9uuy5AK4WLapcJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dbOkIz/btsGZlWnBal/H8PSnru9uuy5AK4WLapcJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dbOkIz/btsGZlWnBal/H8PSnru9uuy5AK4WLapcJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdbOkIz%2FbtsGZlWnBal%2FH8PSnru9uuy5AK4WLapcJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2982&quot; height=&quot;966&quot; data-origin-width=&quot;2982&quot; data-origin-height=&quot;966&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이름 입력 &amp;gt; 다음&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2254&quot; data-origin-height=&quot;982&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c6qWpJ/btsGY5lWkX7/9VBAMZiv0SBjfHgTndwYe0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c6qWpJ/btsGY5lWkX7/9VBAMZiv0SBjfHgTndwYe0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c6qWpJ/btsGY5lWkX7/9VBAMZiv0SBjfHgTndwYe0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc6qWpJ%2FbtsGY5lWkX7%2F9VBAMZiv0SBjfHgTndwYe0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2254&quot; height=&quot;982&quot; data-origin-width=&quot;2254&quot; data-origin-height=&quot;982&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직접 정책 연결 선택&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; 권한 정책에서 AmazonS3FullAccess 검색 후 체크&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; 다음&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;gt; 사용자 생성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2296&quot; data-origin-height=&quot;1432&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JGB5s/btsGZA6PJhq/WpGS0bEeMGUTVq6XChqfT0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JGB5s/btsGZA6PJhq/WpGS0bEeMGUTVq6XChqfT0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JGB5s/btsGZA6PJhq/WpGS0bEeMGUTVq6XChqfT0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJGB5s%2FbtsGZA6PJhq%2FWpGS0bEeMGUTVq6XChqfT0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2296&quot; height=&quot;1432&quot; data-origin-width=&quot;2296&quot; data-origin-height=&quot;1432&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS Console &amp;gt; IAM &amp;gt; 엑세스 관리자 &amp;gt; 사용자 &amp;gt; 생성한 사용자 이름 클릭 &amp;gt; 보안 자격 증명 &amp;gt; 엑세스 키 만들기 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2960&quot; data-origin-height=&quot;1588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bd8MSu/btsGZUjG84e/bty3aIr8xDtJL0kZaIHLBK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bd8MSu/btsGZUjG84e/bty3aIr8xDtJL0kZaIHLBK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bd8MSu/btsGZUjG84e/bty3aIr8xDtJL0kZaIHLBK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbd8MSu%2FbtsGZUjG84e%2Fbty3aIr8xDtJL0kZaIHLBK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2960&quot; height=&quot;1588&quot; data-origin-width=&quot;2960&quot; data-origin-height=&quot;1588&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기타 선택 후(다른거 선택해도 무관) 다음 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2774&quot; data-origin-height=&quot;1564&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cd6Dy7/btsGY4AzIa7/15Bcp81kYKLUpk9aSWnIwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cd6Dy7/btsGY4AzIa7/15Bcp81kYKLUpk9aSWnIwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cd6Dy7/btsGY4AzIa7/15Bcp81kYKLUpk9aSWnIwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcd6Dy7%2FbtsGY4AzIa7%2F15Bcp81kYKLUpk9aSWnIwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2774&quot; height=&quot;1564&quot; data-origin-width=&quot;2774&quot; data-origin-height=&quot;1564&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그 입력후 액세스 키 만들기 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;712&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2eEjn/btsGYz19Rf8/ZZqXqD9wZuTXkU4Akiy8k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2eEjn/btsGYz19Rf8/ZZqXqD9wZuTXkU4Akiy8k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2eEjn/btsGYz19Rf8/ZZqXqD9wZuTXkU4Akiy8k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2eEjn%2FbtsGYz19Rf8%2FZZqXqD9wZuTXkU4Akiy8k1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2012&quot; height=&quot;712&quot; data-origin-width=&quot;2012&quot; data-origin-height=&quot;712&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비밀 액세스 키는 다시 검색할 수 없으니 어딘가에 메모 해놓으시고 cvs 파일도 다운로드 받으시길 바랍니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1696&quot; data-origin-height=&quot;1340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ViSWY/btsGYfpkY4z/xa43c1V3WOj75V8jogsrk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ViSWY/btsGYfpkY4z/xa43c1V3WOj75V8jogsrk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ViSWY/btsGYfpkY4z/xa43c1V3WOj75V8jogsrk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FViSWY%2FbtsGYfpkY4z%2Fxa43c1V3WOj75V8jogsrk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1696&quot; height=&quot;1340&quot; data-origin-width=&quot;1696&quot; data-origin-height=&quot;1340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;br /&gt;그럼 S3에 접근할 수 있는 권한을 가진 유저도 추가가 완료됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부족한 글 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>Deploy/AWS</category>
      <author>hurlud</author>
      <guid isPermaLink="true">https://hulrud.tistory.com/105</guid>
      <comments>https://hulrud.tistory.com/105#entry105comment</comments>
      <pubDate>Sat, 27 Apr 2024 14:15:03 +0900</pubDate>
    </item>
  </channel>
</rss>