<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>no-merit.log</title>
        <link>https://velog.io/</link>
        <description>ㅡ/ㅡ</description>
        <lastBuildDate>Sat, 31 May 2025 07:58:04 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>no-merit.log</title>
            <url>https://velog.velcdn.com/images/no-merit/profile/7251511a-dc9f-4255-86f6-e48293a94cd5/image.webp</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. no-merit.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/no-merit" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[테스팅]]></title>
            <link>https://velog.io/@no-merit/%ED%85%8C%EC%8A%A4%ED%8C%85</link>
            <guid>https://velog.io/@no-merit/%ED%85%8C%EC%8A%A4%ED%8C%85</guid>
            <pubDate>Sat, 31 May 2025 07:58:04 GMT</pubDate>
            <description><![CDATA[<p>네, 일반적으로 단위 테스트를 위한 클래스와 통합 테스트를 위한 클래스는 따로 두는 편입니다. 이것은 테스트 전략에서 권장되는 모범 사례 중 하나입니다.</p>
<p>분리하는 이유
테스트의 목적 및 범위 명확화:</p>
<p>단위 테스트: 개별 코드 단위(메서드, 클래스)의 독립적인 기능이 올바르게 작동하는지 확인하는 데 집중합니다. 외부 의존성은 Mocking합니다.
통합 테스트: 여러 단위(클래스, 모듈)가 서로 연동하여 올바르게 작동하는지 확인하는 데 집중합니다. 실제 의존성(DB, 외부 API 등)과의 연동을 포함합니다.
이렇게 목적과 범위가 명확해지면 테스트 코드의 가독성과 유지보수성이 높아집니다.
테스트 실행 속도:</p>
<p>단위 테스트: Mocking을 사용하므로 Spring 컨텍스트 로딩이나 외부 시스템 연동이 없어 매우 빠르게 실행됩니다. 개발 중 자주, 그리고 많이 실행되어야 합니다.
통합 테스트: Spring 컨텍스트를 로드하고, 실제 데이터베이스나 메시지 큐 등 외부 시스템과 연동해야 하므로 단위 테스트보다 훨씬 느립니다. 자주 실행하기는 부담스러울 수 있습니다.
테스트 유형에 따라 실행 속도가 다르기 때문에, 개발자는 빠른 피드백을 위해 단위 테스트를 우선적으로 실행하고, 필요할 때 통합 테스트를 실행할 수 있도록 분리하는 것이 효율적입니다.
테스트 환경 설정의 복잡성:</p>
<p>단위 테스트: 간단한 JUnit, Mockito 설정만으로 충분한 경우가 많습니다.
통합 테스트: @SpringBootTest, @EmbeddedKafka, Testcontainers 등 복잡한 Spring 환경 설정이나 외부 시스템 연동 설정이 필요합니다.
하나의 테스트 클래스에 이 모든 설정을 혼합하면 코드가 지저분해지고 관리하기 어려워집니다.
클린 코드 및 가독성:</p>
<p>단위 테스트와 통합 테스트는 설정 방식, Mocking 여부, 검증 방식 등에서 차이가 큽니다. 이를 한 파일에 섞어두면 코드를 읽고 이해하기 어려워집니다.
각 테스트 유형에 맞는 전용 클래스를 사용함으로써 코드를 깔끔하게 유지하고, 어떤 유형의 테스트인지 쉽게 파악할 수 있습니다.
일반적인 파일/패키지 구조
Spring Boot 프로젝트에서는 src/test/java 아래에 다음과 같은 패키지 구조를 사용하여 테스트를 분리하는 것이 일반적입니다.</p>
<pre><code>src/test/java
└── com/example/myproject
    └── service
        ├── UserServiceTest.java           // UserService에 대한 단위 테스트 (Mocking 위주)
        └── UserServiceIntegrationTest.java // UserService가 다른 컴포넌트(예: UserRepository)와 연동되는 통합 테스트

    └── controller
        ├── MemberControllerTest.java      // MemberController에 대한 단위 테스트 (직접 인스턴스화 또는 최소 Spring 컨텍스트)
        └── MemberControllerWebMvcTest.java // MemberController에 대한 웹 계층 통합 테스트 (@WebMvcTest)

    └── repository
        └── MemberRepositoryTest.java      // MemberRepository에 대한 단위 테스트 (DB 연동 없이 로직만)
        └── MemberRepositoryIntegrationTest.java // MemberRepository의 실제 DB 연동 통합 테스트 (@DataJpaTest)

    └── kafka
        └── KafkaProducerServiceTest.java       // KafkaProducerService 단위 테스트 (KafkaTemplate Mocking)
        └── KafkaProducerServiceIntegrationTest.java // KafkaProducerService 통합 테스트

또는 
src/test/java
└── com/example/myproject
    └── unit
        └── service
            └── UserServiceTest.java
        └── controller
            └── MemberControllerTest.java
        └── kafka
            └── KafkaProducerServiceTest.java
    └── integration
        └── service
            └── UserServiceIntegrationTest.java
        └── controller
            └── MemberControllerWebMvcTest.java
        └── repository
            └── MemberRepositoryIntegrationTest.java
        └── kafka
            └── KafkaProducerServiceIntegrationTest.java
</code></pre><pre><code class="language-java">@ExtendWith(MockitoExtension.class) // JUnit5에서 Mockito 사용을 위함
class MemberServiceTest {
    @InjectMocks private MemberService memberService; // 테스트 대상 서비스
    @Mock private MemberRepository memberRepository; // 레포지토리 Mocking
    @Spy private BCryptPasswordEncoder passwordEncoder; // 실제 암호화 로직을 사용하기 위해 Spy 사용 [14]

    @DisplayName(&quot;회원가입 성공: 유효한 아이디와 비밀번호&quot;)
    @Test
    void signUp_Successful_When_ValidRequestProvided() {
        // Given
        String username = &quot;newuser&quot;;
        String password = &quot;newpassword123&quot;;
        SignUpRequestDto requestDto = new SignUpRequestDto(username, password);

        // 중복 회원 없음으로 Stubbing
        when(memberRepository.findByUsername(username)).thenReturn(Optional.empty());

        // save 호출 시 Member 객체 반환하도록 Stubbing (id는 테스트에서 중요하지 않으므로 생략)
        Member savedMember = new Member(username, passwordEncoder.encode(password));
        when(memberRepository.save(any(Member.class))).thenReturn(savedMember);

        // When
        MemberResponseDto response = memberService.signUp(requestDto);

        // Then
        assertThat(response.getUsername()).isEqualTo(username);
        // 실제 암호화된 비밀번호와 요청 비밀번호가 일치하는지 확인
        assertThat(passwordEncoder.matches(password, response.getPassword())).isTrue();

        // Verify
        verify(memberRepository, times(1)).findByUsername(username); // 중복 검사 호출 확인
        verify(passwordEncoder, times(1)).encode(password); // encode 메서드가 1번 호출되었는지 검증
        verify(memberRepository, times(1)).save(any(Member.class)); // save 메서드가 1번 호출되었는지 검증
    }
}
</code></pre>
<pre><code class="language-java">@DisplayName(&quot;회원가입 실패: 중복된 아이디 존재 시 예외 발생&quot;)
@Test
void signUp_ThrowsException_When_DuplicateUsername() {
    // Given
    String username = &quot;existinguser&quot;;
    String password = &quot;password123&quot;;
    SignUpRequestDto requestDto = new SignUpRequestDto(username, password);

    // memberRepository.findByUsername() 호출 시 이미 존재하는 회원 반환하도록 Stubbing
    when(memberRepository.findByUsername(username)).thenReturn(Optional.of(new Member(username, &quot;hashedpassword&quot;)));

    // When &amp; Then
    // assertThrows를 사용하여 특정 예외가 발생하는지 검증 [5, 11]
    IllegalStateException thrown = assertThrows(
        IllegalStateException.class,
        () -&gt; memberService.signUp(requestDto),
        &quot;이미 존재하는 회원입니다.&quot; // 예상되는 예외 메시지
    );
    assertThat(thrown.getMessage()).contains(&quot;이미 존재하는 회원입니다.&quot;);

    // Verify: save 메서드는 호출되지 않아야 함
    verify(memberRepository, times(1)).findByUsername(username); // 중복 검사 호출 확인
    verify(memberRepository, never()).save(any(Member.class)); // save 메서드는 호출되지 않았는지 검증
    verify(passwordEncoder, never()).encode(any(String.class)); // encode 메서드도 호출되지 않았는지 검증
}
</code></pre>
<pre><code class="language-yml">spring_blog/src/test/resources/junit-platform.properties


junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.classes.default=concurrent
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=1</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[트랜잭션 아웃박스, Saga 역할과 범위]]></title>
            <link>https://velog.io/@no-merit/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%95%84%EC%9B%83%EB%B0%95%EC%8A%A4</link>
            <guid>https://velog.io/@no-merit/%ED%8A%B8%EB%9E%9C%EC%9E%AD%EC%85%98%EC%95%84%EC%9B%83%EB%B0%95%EC%8A%A4</guid>
            <pubDate>Mon, 26 May 2025 09:45:43 GMT</pubDate>
            <description><![CDATA[<h2 id="트랜잭션-아웃박스-패턴과-saga-패턴의-역할과-범위">트랜잭션 아웃박스 패턴과 Saga 패턴의 역할과 범위</h2>
<ul>
<li>아웃박스 패턴으로 이벤트 발행의 성공을 보장</li>
<li>Saga 패턴과 보상 트랜잭션</li>
</ul>
<blockquote>
<p>&quot;메시지 발행의 성공&quot; 과 &quot;분산된 비즈니스 프로세스의 성공&quot; 간의 차이</p>
</blockquote>
<h3 id="트랜잭션-아웃박스-패턴의-보장-범위">트랜잭션 아웃박스 패턴의 보장 범위</h3>
<h4 id="보장-내용">보장 내용</h4>
<ul>
<li>Service A가 자신의 로컬 DB에 데이터를 저장하고, 동시에 OutboxEvent를 저장하는 과정의 원자성(Atomicity)을 보장 </li>
<li>Outbox Relayer에 의해 이 OutboxEvent가 메시지 브로커(Kafka)에 최소 한 번(At-Least-Once) 발행될 것을 보장<h4 id="보장하지-않는-것">보장하지 않는 것</h4>
</li>
<li>메시지 브로커에 발행된 이벤트가 컨슈머 서비스(Service B, C 등)에서 성공적으로 처리될지 여부는 보장하지 않음<h4 id="saga-패턴과-보상-트랜잭션이-필요한-이유">Saga 패턴과 보상 트랜잭션이 필요한 이유</h4>
</li>
<li>Saga 패턴은 여러 서비스에 걸쳐 있는 하나의 큰 비즈니스 프로세스(분산 트랜잭션)의 &quot;결과적 일관성&quot;을 보장하는 것이 목표 </li>
<li>트랜잭션 아웃박스 패턴은 이 Saga의 각 단계에서 이벤트를 &quot;안전하게 발행&quot;하는 것을 돕는 보조적인 패턴</li>
</ul>
<h4 id="어떤-상황에서-보상-트랜잭션이-필요한가">어떤 상황에서 보상 트랜잭션이 필요한가</h4>
<blockquote>
<p>가장 흔한 예시는 &quot;주문 생성 및 결제&quot; Saga</p>
</blockquote>
<h4 id="시나리오-주문-생성-및-결제-order-creation--payment-saga">시나리오: 주문 생성 및 결제 (Order Creation &amp; Payment Saga)</h4>
<ul>
<li><p>Saga 단계</p>
<ul>
<li>Order Service: 주문을 생성하고 OrderCreatedEvent를 발행 (트랜잭션 아웃박스 사용)</li>
<li>Payment Service: OrderCreatedEvent를 구독하여 결제를 시도하고, 결제 성공 시 PaymentProcessedEvent를, 실패 시 PaymentFailedEvent를 발행 (트랜잭션 아웃박스 사용)</li>
<li>Inventory Service: PaymentProcessedEvent를 구독하여 상품 재고를 차감하고, 재고 차감 성공 시 InventoryDeductedEvent를 발행 (트랜잭션 아웃박스 사용)</li>
</ul>
</li>
<li><p>문제 발생 상황과 보상 트랜잭션의 필요성</p>
<ul>
<li>상황 1: Payment Service에서 결제 실패</li>
</ul>
</li>
</ul>
<blockquote>
<ul>
<li>발생: Order Service가 OrderCreatedEvent를 성공적으로 발행했고, Payment Service가 이를 받음. </li>
</ul>
</blockquote>
<ul>
<li>하지만 실제 결제 승인 과정(외부 PG사 연동 등)에서 문제가 발생하여 결제가 실패<ul>
<li>필요성: Order Service는 이미 주문을 생성한 상태 </li>
</ul>
</li>
<li>결제가 실패했으니, 이 주문은 &quot;취소 상태&quot; 가 되어야 함<ul>
<li>보상 트랜잭션: Payment Service는 PaymentFailedEvent를 발행</li>
</ul>
</li>
<li>Order Service는 이 PaymentFailedEvent를 구독하여 생성했던 주문을 취소 상태로 변경(보상) 하는 로직을 실행</li>
</ul>
<ul>
<li>상황 2: Inventory Service에서 재고 부족으로 차감 실패</li>
</ul>
<blockquote>
<ul>
<li>발생: Order Service가 주문 생성, Payment Service가 결제 승인까지 성공하여 PaymentProcessedEvent를 발행 </li>
</ul>
</blockquote>
<ul>
<li>Inventory Service가 이를 받음</li>
<li>하지만 재고 부족으로 인해 해당 상품의 재고를 차감 실패<ul>
<li>필요성: 재고가 없으니 주문을 완료할 수 없음 </li>
</ul>
</li>
<li>이미 결제된 금액은 환불되어야 하고, 주문은 취소<ul>
<li>보상 트랜잭션: Inventory Service는 InventoryDeductionFailedEvent를 발행</li>
</ul>
</li>
<li>Payment Service는 이 이벤트를 구독하여 결제된 금액을 환불(보상) 하는 로직을 실행</li>
<li>Order Service는 이 이벤트를 구독하여 주문을 취소 상태로 변경(보상) 하는 로직을 실행</li>
</ul>
<ul>
<li>상황 3: 컨슈머 서비스 자체의 비즈니스 로직 오류 (DB 제약 조건 위반 등)</li>
</ul>
<blockquote>
<ul>
<li>발생: Order Service가 이벤트를 성공적으로 발행</li>
</ul>
</blockquote>
<ul>
<li>Payment Service가 이벤트를 받았지만, Payment Service의 내부 DB에 결제 정보를 저장하려는데 유효성 검증 실패나 비즈니스 규칙 위반(예: 사용자에게 이미 미납된 결제가 있음)으로 저장이 실패 (Kafka 메시지 발행은 문제가 없었지만, 비즈니스 로직 실패).<ul>
<li>필요성: 주문은 취소되어야 함</li>
<li>보상 트랜잭션: Payment Service는 이 비즈니스 로직 실패를 감지  </li>
</ul>
</li>
<li>PaymentFailedEvent를 발행하여 Order Service가 주문을 보상(취소)하도록 트리거</li>
</ul>
<h4 id="트랜잭션-아웃박스--saga의-관계">트랜잭션 아웃박스 + Saga의 관계</h4>
<ul>
<li>트랜잭션 아웃박스 패턴<ul>
<li>각 서비스(Order, Payment, Inventory)가 자신의 로컬 DB 변경(주문 생성, 결제 기록, 재고 차감)과 해당 이벤트를 메시지 브로커에 &quot;확실하게 발행&quot;하는 것을 보장  +  이는 이중 쓰기 문제를 해결하여 메시지 유실을 방지</li>
</ul>
</li>
<li>Saga 패턴<ul>
<li>아웃박스 패턴으로 안전하게 발행된 이벤트들을 사용하여 분산된 비즈니스 프로세스(주문 -&gt; 결제 -&gt; 재고 차감)를 단계별로 진행</li>
<li>만약 어떤 단계에서 비즈니스적인 실패가 발생하면, 이전 단계들을 보상 트랜잭션으로 되돌려 전체 프로세스의 일관성을 유지</li>
</ul>
</li>
</ul>
<blockquote>
<p>트랜잭션 아웃박스 패턴은 &quot;메시지가 브로커에 도착하는 것&quot; 을 보장
Saga 패턴은 &quot;비즈니스 프로세스가 분산된 환경에서 최종적으로 일관된 상태가 되는 것&quot; 을 보장
이를 위해 보상 트랜잭션이 필수적인 역할</p>
</blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[동기/비동기 , 블로킹/논블로킹]]></title>
            <link>https://velog.io/@no-merit/%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9</link>
            <guid>https://velog.io/@no-merit/%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9</guid>
            <pubDate>Mon, 12 May 2025 01:44:36 GMT</pubDate>
            <description><![CDATA[<h1 id="동기-vs-비동기">동기 vs 비동기</h1>
<blockquote>
<p>두 개념은 호출하는 쪽(call site)이 결과를 기다리느냐(동기) 아니면 기다리지 않느냐(비동기)를 구분</p>
</blockquote>
<ul>
<li><p>동기(Synchronous)
– 호출한 메서드가 작업 완료(또는 오류) → 결과 반환 전까지 호출 스레드가 대기
– 장점: 제어 흐름이 단순하고 디버깅하기 쉬움
– 단점: 긴 I/O나 연산 중 호출 스레드가 묶여 있어 전체 처리량이 떨어짐</p>
</li>
<li><p>비동기(Asynchronous)
– 호출한 메서드가 즉시 반환 → 별도 콜백, Future/Promise, Reactive 스트림 등을 통해 나중에 결과 수신
– 장점: 호출 스레드는 다른 작업 계속 수행 → 자원 활용 효율이 높음
– 단점: 콜백 헬, 흐름 제어 복잡도 증가</p>
</li>
</ul>
<hr>
<h1 id="블로킹-vs-논블로킹">블로킹 vs 논블로킹</h1>
<blockquote>
<p>블로킹/논블로킹은 스레드 관점에서 자원이 사용 가능해질 때까지 대기하느냐를 말합</p>
</blockquote>
<ul>
<li><p>블로킹(Blocking I/O)
– I/O 함수 호출 시 데이터 준비가 안 돼 있으면 호출 스레드가 OS 레벨에서 멈춰 있다가(park) 준비되면 깨어나 처리
– 예: java.io.InputStream.read()</p>
</li>
<li><p>논블로킹(Non-Blocking I/O)
– I/O 함수가 즉시 반환 → 데이터가 준비되지 않았으면 즉시 0바이트나 EAGAIN 같은 상태를 알려줌
– 호출 스레드는 깨어 있고 다른 작업을 수행하거나 재시도 로직을 구현해야 함
– 예: Java NIO 채널(Channel).read(), select()/poll() 기반 구조</p>
</li>
</ul>
<hr>
<h1 id="동기--비동기--블로킹--논블로킹">동기 . 비동기 . 블로킹 . 논블로킹</h1>
<ul>
<li><p>동기 블로킹: 가장 익숙한 형태. 함수 호출 뒤 응답·파일 읽기·DB 쿼리 완료 시까지 스레드가 멈춤</p>
<pre><code class="language-java">printAfterSeconds(&quot;Task A&quot;, 3000); // 3초 대기
printAfterSeconds(&quot;Task B&quot;, 2000); // Task A가 끝난 후 2초 대기
printAfterSeconds(&quot;Task C&quot;, 1000); // Task B가 끝난 후 1초 대기</code></pre>
</li>
<li><p>동기 논블로킹: 호출 즉시 반환하되, 호출자가 직접 폴링(poll)하거나 select()로 상태를 감시</p>
<pre><code class="language-java">Future&lt;String&gt; task = es.submit(() -&gt; 
returnValueAfterSeconds(&quot;Task&quot;, 10000));
while(!task.isDone()) {
  // 다른 작업 수행
}</code></pre>
</li>
<li><p>비동기 블로킹: 작업을 비동기로 위임했지만, 호출자가 임시로 Future.get()처럼 블로킹 호출을 함</p>
</li>
</ul>
<pre><code class="language-java">Future&lt;String&gt; task = es.submit(() -&gt; 
returnValueAfterSeconds(&quot;Task&quot;, 10000));
String result = task.get(); // 결과가 나올 때까지 블로킹</code></pre>
<ul>
<li>비동기 논블로킹: 대표적으로 콜백, 이벤트 루프, Reactor·RxJava 같은 Reactive 스트림이 여기에 속함<ul>
<li>웹 브라우저의 파일 다운로드: 사용자가 파일 다운로드를 시작해도 브라우저는 다른 작업(탭 이동, 스크롤 등)을 계속할 수 있습니다. 다운로드가 끝나면 완료 알림만 따로 받습니다. 이 과정에서 브라우저는 다운로드가 끝날 때까지 기다리지 않고, 다른 작업을 논블로킹으로 처리합니다</li>
</ul>
</li>
</ul>
<pre><code class="language-java">fs.readFile(&#39;/file.md&#39;, (err, data) =&gt; {
  if (err) throw err;
  console.log(data); // 파일 읽기 끝난 후 콜백 실행
});
console.log(&#39;다른 작업&#39;); // 파일 읽는 동안에도 실행됨</code></pre>
<p><img src="https://velog.velcdn.com/images/no-merit/post/b2709ed9-bc62-4fa4-86b8-7e4dabd31d47/image.png" alt=""></p>
<blockquote>
<p>블로킹 비용은 단순히 &quot;시간&quot;만 의미하지 않습니다.
CPU 관점: 블로킹 중인 스레드는 실제로 CPU를 점유하지 않지만, OS는 해당 스레드를 관리해야 하며, 많은 스레드가 블로킹되면 스케줄링·컨텍스트 스위칭 등 부가적인 컴퓨팅 자원이 소모됩니다.
메모리 관점: 블로킹 스레드마다 스택·상태를 보관해야 하므로, 많은 동시 요청이 들어오면 메모리 사용량이 급증합니다.
확장성: 블로킹 방식은 동시 접속이 많아질수록 서버 자원이 빠르게 고갈됩니다.
즉, 블로킹 비용은 단순 대기 시간뿐 아니라, 시스템 자원(메모리, 스레드 관리, 스케줄링 등) 전체에 영향을 미치는 &quot;컴퓨팅 파워&quot;의 낭비를 의미합니다.</p>
</blockquote>
<blockquote>
<p>콜백과 이벤트 루프는 비동기 논블로킹의 핵심 메커니즘입니다.
작업 요청 → 즉시 반환 → 완료 시 콜백 등록 → 이벤트 루프가 콜백 실행
이 과정에서 스레드가 대기하지 않으므로, 자원을 효율적으로 활용하고 높은 동시 처리가 가능합니다.</p>
</blockquote>
<hr>
<h3 id="반응형reactive-스택">반응형(Reactive) 스택</h3>
<p>Spring 생태계에서 ‘반응형 스택(reactive stack)’은 Non-Blocking I/O와 Back-Pressure를 지원하는 라이브러리들을 모아, 비동기·이벤트 기반으로 데이터를 처리하는 기술 집합</p>
<ul>
<li>논블로킹<ul>
<li>요청 처리 중 입출력 작업이 발생해도 스레드가 블로킹되지 않고 다른 작업을 수행하도록 설계</li>
</ul>
</li>
<li>이벤트 기반 처리<ul>
<li>네트워크 I/O, 사용자 이벤트 등 변화에 ‘반응’하는 모델로, 선언적 프로그래밍 패러다임을 통해 무엇을 처리할지 기술하고 어떻게 처리할지는 런타임에 위임</li>
</ul>
</li>
<li>백프레셔<ul>
<li>소비자가 처리 가능한 속도에 맞춰 생산자의 배출 속도를 제어하는 메커니즘. Reactive Streams 사양에 정의되어 있으며, 생산자가 속도를 늦추지 못할 경우 버퍼링·드롭·예외 처리 등이 선택.</li>
</ul>
</li>
</ul>
<blockquote>
<p>Spring WebFlux: Spring 5.0부터 도입된 완전 Non-Blocking 웹 프레임워크로, Netty·Undertow·Servlet 3.1+ 같은 서버에서 구동되며 Reactive Streams Back-Pressure를 내장 지원</p>
</blockquote>
<blockquote>
<p>구독 지연(Laziness): Flux/Mono는 subscribe() 호출 전까지 어떤 연산도 수행하지 않습니다.
데이터 흐름: subscribe() 시 Subscription이 생성되고, 구독자가 request(n)로 소비량을 알리면 Publisher가 onNext()로 데이터를 흘려 보냅니다.
연산자(Operator): map, filter, flatMap 같은 연산자를 연결해 선언적으로 파이프라인을 정의합니다. 이들은 데이터 스트림 중간에서 값을 변환·조합·제어합니다.
종료 신호: 데이터 방출이 끝나면 onComplete(), 오류 발생 시 onError()로 스트림이 종료됩니다.</p>
</blockquote>
<pre><code class="language-java">lux&lt;Integer&gt; flux = Flux.range(1, 5)          // 1부터 5까지 발행  
    .filter(i -&gt; i % 2 == 0)                   // 짝수 필터링  
    .map(i -&gt; i * 10);                         // 값 변환  

flux.subscribe(                              
    data -&gt; System.out.println(data),       // onNext  
    err  -&gt; System.err.println(err),        // onError  
    ()   -&gt; System.out.println(&quot;완료&quot;),      // onComplete  
    sub  -&gt; sub.request(2)                  // 최초 2개 요청(백프레셔)  
);</code></pre>
<hr>
<h1 id="http11-http2">Http/1.1 Http/2</h1>
<blockquote>
<p>HTTP 프로토콜과 동시성
HTTP/1.1에서는 하나의 TCP 연결에서 한 번에 하나의 요청-응답만 처리할 수 있습니다. 여러 요청을 동시에 처리하려면 여러 TCP 연결이 필요합니다. 브라우저는 이를 위해 여러 연결을 병렬로 사용합니다.
HTTP/2에서는 하나의 연결에서 여러 요청을 동시에 스트림(stream) 단위로 처리하는 멀티플렉싱이 지원되어, 한 서버가 동시에 여러 요청을 처리할 수 있습니다.</p>
</blockquote>
<ul>
<li>HTTP/1.1은 순차적 처리, HTTP/2는 멀티플렉싱을 통한 병렬 처리</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/07 면접준비/정규화, 트랜잭션,인덱싱, 조인]]></title>
            <link>https://velog.io/@no-merit/0507-%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84-%EC%9D%B8%EB%8D%B1%EC%8B%B1</link>
            <guid>https://velog.io/@no-merit/0507-%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84-%EC%9D%B8%EB%8D%B1%EC%8B%B1</guid>
            <pubDate>Wed, 07 May 2025 05:09:23 GMT</pubDate>
            <description><![CDATA[<h1 id="정규화">정규화</h1>
<ul>
<li>정규화는 데이터베이스 설계에서 데이터의 중복을 최소화하고, 데이터 무결성을 보장하기 위해 테이블을 분리하는 과정</li>
<li>삽입, 갱신, 삭제 시 발생할 수 있는 이상 현상(Anomaly)을 방지하고, 데이터의 일관성과 효율성을 높일 수 있음</li>
<li>지나친 정규화는 JOIN 연산이 많아져 성능 저하를 유발<ul>
<li>상황에 따라 반정규화도 고려</li>
</ul>
</li>
</ul>
<hr>
<h1 id="트랜잭션">트랜잭션</h1>
<blockquote>
<p>트랜잭션(Transaction)은 데이터베이스에서 하나의 논리적인 작업 단위로, 여러 작업을 하나로 묶어 모두 성공하거나 모두 실패해야 합니다. 트랜잭션은 데이터의 신뢰성과 일관성을 보장하기 위해 ACID 원칙</p>
</blockquote>
<hr>
<h1 id="인덱스">인덱스</h1>
<ul>
<li>인덱스(Index)는 데이터베이스에서 데이터를 빠르게 검색하기 위해 사용하는 자료구조</li>
<li>특정 컬럼의 값을 기준으로 데이터의 위치를 빠르게 찾아줌</li>
<li>인덱스를 사용하면 전체 테이블을 모두 탐색하지 않고도 원하는 데이터를 효율적으로 조회할 수 있어 검색 성능이 크게 향상</li>
<li>인덱스를 생성하면 추가적인 저장 공간이 필요하고, 데이터의 삽입·수정·삭제 시 인덱스도 함께 관리해야 하므로 쓰기 작업의 성능이 저하</li>
<li>일반적으로 조회가 빈번하고, 카디널리티(값의 다양성)가 높은 컬럼에 인덱스를 적용</li>
</ul>
<hr>
<h1 id="조인">조인</h1>
<blockquote>
<p>조인(Join)은 두 개 이상의 테이블을 연결하여 관련된 데이터를 하나의 결과로 조회하는 SQL 연산</p>
</blockquote>
<ul>
<li><p>조인(Join)은 데이터베이스에서 여러 테이블의 데이터를 결합하는 강력한 기능이지만, 잘못 사용하거나 최적화가 안 된 경우에는 DB에 상당한 부담을 줌</p>
<ul>
<li>조인이 항상 느리거나 비효율적인 것은 아니며, 상황과 설계에 따라 다름</li>
</ul>
</li>
<li><p>조인이 부담이 되는 경우</p>
<ul>
<li>인덱스가 없을 때: 조인하는 컬럼(외래키 등)에 인덱스가 없으면, DB는 모든 행을 일일이 비교(풀 스캔)해야 하므로 매우 느려짐</li>
<li>대용량 테이블 조인: 수백만~수천만 건의 대형 테이블끼리 조인하면, 연산량이 급격히 늘어남</li>
<li>필터(WHERE) 없이 불필요한 데이터까지 조인: 필요한 데이터만 선별하지 않고 전체 데이터를 조인하면, 네트워크와 DB 모두에 부담이 커짐</li>
<li>너무 많은 테이블 조인: 5개 이상 테이블을 한 번에 조인하면, 실행 계획이 복잡해지고 성능 저하가 발생할 수 있습니다.</li>
</ul>
</li>
<li><p>조인이 부담이 적은 경우</p>
<ul>
<li>조인 컬럼에 인덱스가 있을 때: 인덱스를 잘 사용하면 조인 성능이 크게 향상됩니다.</li>
<li>필요한 데이터만 선택(SELECT 컬럼 지정, WHERE 조건 사용): 불필요한 데이터까지 가져오지 않으면 부담이 줄어듭니다.</li>
<li>적절한 테이블 구조와 쿼리 최적화: 쿼리와 테이블 구조를 잘 설계하면, 현대의 DBMS는 조인을 매우 효율적으로 처리할 수 있습니다.</li>
</ul>
</li>
</ul>
<hr>
<p>#</p>
<ol>
<li>DDL (Data Definition Language, 데이터 정의어)
설명: 데이터베이스의 구조(테이블, 스키마 등)를 생성·변경·삭제하는 명령어입니다.</li>
</ol>
<p>대표 명령어 및 예시:</p>
<p>CREATE : 테이블/데이터베이스 생성
CREATE TABLE user (id INT PRIMARY KEY, name VARCHAR(20));</p>
<p>ALTER : 테이블 구조 변경
ALTER TABLE user ADD email VARCHAR(50);</p>
<p>DROP : 테이블/데이터베이스 삭제
DROP TABLE user;</p>
<p>RENAME : 테이블 이름 변경
RENAME TABLE user TO member;</p>
<p>TRUNCATE : 테이블의 모든 데이터 삭제(구조는 남음)
TRUNCATE TABLE user;</p>
<ol start="2">
<li>DML (Data Manipulation Language, 데이터 조작어)
설명: 테이블에 저장된 실제 데이터를 조회·삽입·수정·삭제하는 명령어입니다.</li>
</ol>
<p>대표 명령어 및 예시:</p>
<p>SELECT : 데이터 조회
SELECT * FROM user;</p>
<p>INSERT : 데이터 삽입
INSERT INTO user (id, name) VALUES (1, &#39;Alice&#39;);</p>
<p>UPDATE : 데이터 수정
UPDATE user SET name = &#39;Bob&#39; WHERE id = 1;</p>
<p>DELETE : 데이터 삭제
DELETE FROM user WHERE id = 1;</p>
<ol start="3">
<li>DCL (Data Control Language, 데이터 제어어)
설명: 데이터베이스의 보안, 권한, 트랜잭션 제어 등을 담당하는 명령어입니다.</li>
</ol>
<p>대표 명령어 및 예시:</p>
<p>GRANT : 권한 부여
GRANT SELECT ON user TO &#39;user1&#39;;</p>
<p>REVOKE : 권한 회수
REVOKE SELECT ON user FROM &#39;user1&#39;;</p>
<p>COMMIT : 트랜잭션 확정(변경 내용 저장)
COMMIT;</p>
<p>ROLLBACK : 트랜잭션 취소(변경 내용 되돌림)
ROLLBACK;</p>
<p>요약</p>
<p>DDL: 데이터 구조 정의/변경/삭제 (CREATE, ALTER, DROP, TRUNCATE, RENAME)</p>
<p>DML: 데이터 조회/삽입/수정/삭제 (SELECT, INSERT, UPDATE, DELETE)</p>
<p>DCL: 권한/보안/트랜잭션 제어 (GRANT, REVOKE, COMMIT, ROLLBACK)</p>
<p>이 세 가지는 SQL의 기본적인 분류이며, 데이터베이스를 다루는 데 필수적으로 알아야 하는 개념입니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/07 면접 준비/자바의 실행 과정, 스프링과 스프링 부트, 의존성 주입, 스프링 빈]]></title>
            <link>https://velog.io/@no-merit/0507-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84%EC%9E%90%EB%B0%94%EC%9D%98-%EC%8B%A4%ED%96%89-%EA%B3%BC%EC%A0%95-%EC%8A%A4%ED%94%84%EB%A7%81%EA%B3%BC-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8</link>
            <guid>https://velog.io/@no-merit/0507-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84%EC%9E%90%EB%B0%94%EC%9D%98-%EC%8B%A4%ED%96%89-%EA%B3%BC%EC%A0%95-%EC%8A%A4%ED%94%84%EB%A7%81%EA%B3%BC-%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8</guid>
            <pubDate>Tue, 06 May 2025 17:22:30 GMT</pubDate>
            <description><![CDATA[<h1 id="자바-실행">자바 실행</h1>
<ul>
<li><p>소스 코드 작성</p>
<ul>
<li>개발자가 .java 확장자의 자바 소스 파일을 작성</li>
</ul>
</li>
<li><p>컴파일</p>
<ul>
<li>자바 컴파일러(javac)가 소스 코드를 바이트코드(.class 파일)로 변환</li>
<li>바이트코드는 사람이 읽을 수 없고, JVM이 이해할 수 있는 중간 언어</li>
</ul>
</li>
<li><p>클래스 로딩</p>
<ul>
<li>실행 시, <strong>클래스 로더(Class Loader)</strong>가 .class 파일을 JVM 메모리로 동적으로 로드</li>
<li>과정에서 로딩 → 링크(검증, 준비, 해석) → 초기화 단계가 진행</li>
</ul>
</li>
<li><p>실행 엔진 동작</p>
<ul>
<li>JVM의 <strong>실행 엔진(Execution Engine)</strong>이 메모리에 올라온 바이트코드를 실행</li>
<li>인터프리터: 바이트코드를 한 줄씩 해석하며 실행</li>
<li>코드 수정 후 바로 실행 가능해 개발 속도가 빠름</li>
<li>실행 시마다 해석하므로 실행 속도가 느릴 수 있고, 코드 최적화가 어려움</li>
<li>JIT(Just-In-Time) 컴파일러: 자주 실행되는 코드를 기계어로 변환해 성능 향상.</li>
<li>미리 변환된 실행 파일을 사용하므로 실행 속도가 빠르고, 코드 최적화가 가능</li>
<li>초기 컴파일 시간이 오래 걸릴 수 있고, 코드 수정 시마다 다시 컴파일해야 하며, 디버깅이 불편</li>
</ul>
</li>
<li><p>실행 및 메모리 관리</p>
<ul>
<li>JVM은 Stack, Heap, Method Area 등 다양한 메모리 영역을 활용해 프로그램을 실행</li>
<li>Garbage Collector가 사용하지 않는 객체를 자동으로 정리</li>
</ul>
</li>
<li><p>Method Area는 클래스 정보, static 변수, 상수, 메서드 코드 등이 저장되는 공간</p>
<ul>
<li>JVM이 클래스를 로드할 때 이 영역에 정보를 저장</li>
<li>Java 8 이전에는 PermGen(영구 영역)이라 불렸고, 이후에는 Metaspace로 대체</li>
<li>모든 스레드가 공유하는 영역</li>
</ul>
</li>
</ul>
<ul>
<li><p>Heap 영역은 객체와 인스턴스 변수가 저장되는 공간</p>
<ul>
<li>애플리케이션 전체에서 공유됩니다. 객체는 동적으로 생성되며, 명시적으로 해제하지 않아도 됨</li>
<li>불필요해진 객체는 가비지 컬렉터가 자동으로 메모리를 회수</li>
<li>Garbage Collector(가비지 컬렉터)는 Heap 영역에서 더 이상 사용되지 않는 객체를 자동으로 탐지해 메모리를 회수하는 역할</li>
<li>객체의 생존 주기에 따라 Young/Old Generation으로 나눠 효율적으로 관리</li>
<li>개발자는 메모리 해제에 신경 쓰지 않아도 되지만, GC 동작이 성능에 영향을 줄 수 있으므로 이해</li>
</ul>
</li>
<li><p>Stack 영역은 메서드 호출과 지역 변수를 저장하는 메모리 공간</p>
<ul>
<li>각 스레드마다 독립적으로 할당되며, 메서드가 호출될 때마다 프레임이 쌓이고(LIFO 구조), 메서드가 종료되면 자동으로 해제</li>
<li>접근 속도가 빠르지만 크기가 제한적이고, 객체가 아닌 기본 타입이나 참조 변수만 저장</li>
</ul>
</li>
</ul>
<blockquote>
<p>이 과정을 통해 자바는 &quot;한 번 작성, 어디서나 실행&quot;이 가능</p>
</blockquote>
<hr>
<h1 id="스프링">스프링</h1>
<blockquote>
<ul>
<li>스프링은 자바 기반의 오픈 소스 애플리케이션 프레임워크로, <strong>의존성 주입(DI)</strong>과 제어의 역전(IoC) 같은 핵심 개념을 바탕으로 대규모 엔터프라이즈급 애플리케이션 개발에 널리 사용</li>
</ul>
</blockquote>
<ul>
<li>스프링은 객체 간의 의존 관계를 설정하고 관리</li>
<li>초기 설정 파일 작성 등으로 인해 학습 곡선이 다소 높음</li>
</ul>
<h1 id="스프링-부트">스프링 부트</h1>
<blockquote>
<ul>
<li>스프링 부트는 스프링 프레임워크를 더 쉽고 빠르게 사용할 수 있도록 도와주는 도구</li>
</ul>
</blockquote>
<ul>
<li>복잡한 설정 파일을 작성하지 않아도 되고, 필요한 라이브러리와 설정을 자동으로 처리</li>
<li>내장 서버(예: Tomcat) 지원으로 별도의 WAS 설치 없이 바로 실행 가능한 JAR 파일을 만듦</li>
<li>스프링 부트는 기본적으로 자동 설정, 의존성 관리, 모니터링(Actuator) 등 다양한 편의 기능을 제공</li>
</ul>
<hr>
<h1 id="의존성-주입">의존성 주입</h1>
<p>의존성 주입(Dependency Injection, DI)은 객체가 필요로 하는 의존 객체를 직접 생성하지 않고, 외부(주로 스프링 컨테이너)에서 대신 만들어서 주입해주는 방식입니다.
즉, 클래스 내부에서 new로 객체를 만들지 않고,
생성자, 세터(setter), 필드 등에 외부에서 필요한 객체를 넣어줍니다.</p>
<p>스프링에서는 다음과 같은 방식으로 의존성 주입이 이루어집니다:</p>
<p>생성자 주입:
생성자를 통해 필요한 의존 객체를 전달받는 방식입니다.
객체가 생성될 때 한 번만 주입되며, 불변성과 필수 의존성을 보장할 수 있어 가장 권장되는 방식입니다.</p>
<p>수정자(Setter) 주입:
setter 메서드를 통해 의존 객체를 주입합니다.
선택적 의존성이나, 객체 생성 후 변경이 필요한 경우에 사용합니다.</p>
<p>필드 주입:
클래스의 멤버 변수에 직접 주입하는 방식으로,
간편하지만 테스트와 유지보수성이 떨어져 권장되지 않습니다.</p>
<p>이렇게 외부에서 의존성을 주입받으면</p>
<p>객체 간 결합도가 낮아지고(느슨한 결합)</p>
<p>코드의 유연성, 재사용성, 테스트 용이성이 크게 향상됩니다.</p>
<p>정리하면,
의존성 주입은 객체가 필요로 하는 다른 객체를 직접 만들지 않고, 외부에서 주입받아 사용하는 설계 방식이며,
스프링에서는 주로 생성자, 세터, 필드 주입 방식으로 구현</p>
<h1 id="bean">Bean</h1>
<pre><code>- 스프링 빈(Spring Bean)은 **스프링 컨테이너가 생성하고 관리하는 자바 객체**
- **의존성 주입(DI)**: 빈끼리 필요한 의존성을 외부에서 주입받아, 객체 간 결합도를 낮추고 테스트가 쉬워짐
- **등록 방법**: XML, 자바 설정(@Bean), 컴포넌트 스캔(@Component, @Service 등)으로 등록
- 객체 생성과 의존성 관리를 스프링에 맡겨 개발 효율성과 유지보수성을 높이기 위함</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[05/07 면접준비/인터페이스와 클래스의 차이, 제네릭]]></title>
            <link>https://velog.io/@no-merit/0507-%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%98-%EC%B0%A8%EC%9D%B4</link>
            <guid>https://velog.io/@no-merit/0507-%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4%EC%99%80-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%9D%98-%EC%B0%A8%EC%9D%B4</guid>
            <pubDate>Tue, 06 May 2025 16:52:10 GMT</pubDate>
            <description><![CDATA[<h1 id="클래스">클래스</h1>
<ul>
<li><p>클래스는 객체의 속성과 동작(메서드)을 정의하며, 실제 인스턴스를 생성. </p>
</li>
<li><p>객체지향 프로그래밍의 기본 단위</p>
</li>
<li><p>클래스는 멤버 변수와 메서드를 모두 가질 수 있고, 메서드의 구체적인 구현을 포함</p>
</li>
<li><p>클래스는 단일 상속</p>
</li>
<li><p>클래스는 객체의 설계도이자, 기능의 구체적인 구현을 담당</p>
</li>
<li><p>객체를 만들기 위한 설계도</p>
</li>
<li><p>일반 클래스 상속: &quot;모든 기능이 구현되어 있고, 오버라이딩은 선택&quot;, 객체 직접 생성 가능</p>
</li>
</ul>
<h2 id="추상-클래스">추상 클래스</h2>
<ul>
<li><p>추상 클래스는 상속을 통해 기능을 확장하고, 기본 동작이나 공통 속성을 자식 클래스에 제공하기 위해 사용</p>
</li>
<li><p>추상 클래스는 추상 메서드(구현 없는 메서드)와 일반 메서드(구현된 메서드), 멤버 변수, 생성자 등을 모두 가질 수 있음</p>
</li>
<li><p>클래스이기 때문에 단일 상속</p>
</li>
<li><p>추상 클래스는 공통 동작, 속성, 기본 구현을 자식 클래스에 제공하고 코드 재사용에 유리</p>
</li>
<li><p>추상 클래스 상속: &quot;반드시 구현해야 하는 메서드가 있다(강제성)&quot;, 객체 직접 생성 불가.</p>
</li>
</ul>
<h1 id="인터페이스">인터페이스</h1>
<ul>
<li>인터페이스는 클래스가 반드시 구현해야 할 메서드(기능)들의 집합만을 정의 </li>
<li>구현은 없고, 설계만 존재 </li>
<li>인스턴스를 직접 생성할 수 없음</li>
<li>인터페이스는 기본적으로 메서드의 선언만 포함하며, Java 8 이후에는 default/static 메서드에 한해 구현이 가능</li>
<li>인터페이스는 다중 구현이 가능</li>
<li>인터페이스는 여러 클래스가 동일한 동작을 보장하도록 강제하는 역할을 하며, 서로 다른 계층 구조의 클래스에 동일한 기능을 부여할 때 사용</li>
<li>기능 명세서 역할</li>
</ul>
<hr>
<h1 id="제네릭">제네릭</h1>
<blockquote>
<p>제네릭(Generic)은 클래스나 메서드를 정의할 때 데이터 타입을 미리 정하지 않고, 사용하는 시점에 외부에서 타입을 지정할 수 있게 해주는 기능</p>
</blockquote>
<ul>
<li><p>타입 안전성 보장: 컴파일 시점에 타입을 검사해, 잘못된 타입 사용을 미리 막아줌</p>
</li>
<li><p>코드 재사용성: 하나의 클래스나 메서드를 여러 타입에 대해 재사용할 수 있어, 코드 중복이 줄고 유지보수가 쉬워짐</p>
</li>
<li><p>제네릭을 쓰지 않을 때 (Object 기반)</p>
<pre><code class="language-java">List list = new ArrayList();
list.add(&quot;hello&quot;);
String s = (String) list.get(0); // 다운캐스팅 필요</code></pre>
</li>
<li><p>만약 잘못된 타입으로 캐스팅하면 런타임 오류</p>
</li>
</ul>
<ul>
<li>제네릭을 쓸 때<pre><code class="language-java">List&lt;String&gt; list = new ArrayList&lt;&gt;();
list.add(&quot;hello&quot;);
String s = list.get(0); // 캐스팅 불필요</code></pre>
</li>
<li>컴파일 시점에 타입이 체크되어, 잘못된 타입이 들어가면 컴파일 에러가 발생</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/05 면접 준비/ 제어의 역전, 프레임워크와 라이브러리]]></title>
            <link>https://velog.io/@no-merit/0505-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%99%80-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@no-merit/0505-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84-%EC%A0%9C%EC%96%B4%EC%9D%98-%EC%97%AD%EC%A0%84-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%99%80-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Mon, 05 May 2025 18:01:55 GMT</pubDate>
            <description><![CDATA[<p>프레임워크(Framework)와 라이브러리(Library)의 차이는 <strong>&quot;제어 흐름의 주도권(제어의 역전, IoC)&quot;</strong></p>
<ul>
<li><p>라이브러리는 개발자가 필요할 때 직접 호출해서 사용하는 도구</p>
</li>
<li><p><em>애플리케이션의 흐름(Flow)*</em>을 개발자가 직접 제어하며, 필요한 기능만 골라서 가져다 씀</p>
</li>
<li><p>프레임워크는 애플리케이션의 전체 구조와 흐름을 스스로 제어.
개발자는 프레임워크가 정해놓은 틀과 규칙 안에서 필요한 코드만 작성
흐름의 주도권은 프레임워크
(이것을 &quot;제어의 역전(Inversion of Control, IoC)&quot;이라고 부릅니다)</p>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/06 면접 준비/개인키,공개키]]></title>
            <link>https://velog.io/@no-merit/0506-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84</link>
            <guid>https://velog.io/@no-merit/0506-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84</guid>
            <pubDate>Mon, 05 May 2025 17:42:12 GMT</pubDate>
            <description><![CDATA[<h2 id="단방향-해시함수--단방향-암호화">단방향 해시(함수) / 단방향 암호화</h2>
<blockquote>
<ul>
<li>입력값을 고정된 길이의 해시값으로 변환</li>
</ul>
</blockquote>
<ul>
<li>복호화(원래 값 복원)가 불가능, 동일 입력값 → 항상 동일 해시값</li>
<li>대표 예: SHA-256, SHA-512, MD5 등 해시 함수</li>
<li>비밀번호 저장, 데이터 무결성 체크, 디지털 서명</li>
</ul>
<h2 id="양방향-암호화">양방향 암호화</h2>
<blockquote>
<ul>
<li>암호화된 데이터를 <strong>복호화(원래 값 복원)</strong>할 수 있음</li>
</ul>
</blockquote>
<ul>
<li>대칭키(비밀키), 공개키(비대칭키) 방식이 대표적</li>
<li>예: AES, RSA 등</li>
<li>데이터 기밀성 보호, 통신 암호화 </li>
</ul>
<h2 id="해싱hashing과-암호화encryption의-차이">해싱(Hashing)과 암호화(Encryption)의 차이</h2>
<ul>
<li>해싱: 단방향, 복호화 불가, 데이터 무결성·식별 등에 사용</li>
<li>암호화: 양방향, 복호화 가능, 데이터 기밀성 보호에 사용</li>
</ul>
<h2 id="전자서명">전자서명</h2>
<p>서명 생성(송신자)
메시지(문서 등)에 단방향 해시함수를 적용해 해시값(메시지 다이제스트)을 만듭니다.
이 해시값을 개인키(비밀키)로 암호화(=전자서명)합니다.
원본 메시지와 전자서명을 함께 전송합니다.</p>
<p>서명 검증(수신자)
수신자는 원본 메시지에 동일한 해시함수를 적용해 해시값1을 만듭니다.
전자서명을 공개키로 복호화하여 해시값2를 얻습니다.
해시값1과 해시값2가 같으면,
메시지가 변조되지 않았고, 서명자가 맞다는 것을 증명할 수 있습니다.</p>
<p>왜 해시함수를 쓸까?
효율성: 긴 메시지 전체를 암호화하지 않고, 짧은 해시값만 암호화하므로 속도가 빠름
무결성: 메시지가 조금이라도 바뀌면 해시값이 완전히 달라짐
단방향성: 해시값만으로 원본 메시지를 알 수 없음</p>
<p>결론
전자서명은 단방향 해시함수로 메시지 요약값을 만든 뒤, 그 해시값에 공개키 암호(비대칭키)로 서명하는 방식입니다.</p>
<hr>
<h2 id="예시">예시</h2>
<ol>
<li>Alice(송신자)가 메시지와 서명을 만든다
메시지:
&quot;나는 5만원을 Bob에게 보낸다.&quot;</li>
</ol>
<p>해시값 만들기(단방향 해시함수 사용)
예를 들어, 해시값이 ABC123이 나왔다고 가정</p>
<p>해시값을 Alice의 개인키로 암호화(전자서명 생성)
→ 암호화된 해시값(전자서명): XYZ789</p>
<p>Alice가 Bob에게 보내는 것</p>
<p>원본 메시지: &quot;나는 5만원을 Bob에게 보낸다.&quot;</p>
<p>전자서명: XYZ789</p>
<ol start="2">
<li>Bob(수신자)가 메시지와 서명을 검증한다
Bob이 받은 것</li>
</ol>
<p>메시지: &quot;나는 5만원을 Bob에게 보낸다.&quot;</p>
<p>전자서명: XYZ789</p>
<p>Bob이 메시지에 해시함수 적용
→ Bob도 해시값 ABC123을 얻음</p>
<p>전자서명을 Alice의 공개키로 복호화
→ 복호화 결과도 해시값 ABC123이 나옴</p>
<p>둘이 같으면?</p>
<p>메시지가 중간에 바뀌지 않았고,</p>
<p>Alice가 진짜 보낸 것임을 Bob이 확인할 수 있음</p>
<blockquote>
<p>개인키와 공개키는 수학적으로 연결되어 있어,
개인키로 암호화한 데이터는 공개키로만 풀 수 있고,
이를 통해 신원 확인과 데이터 무결성을 보장</p>
</blockquote>
<h4 id="개인키로-암호화-공개키로-복호">개인키로 암호화, 공개키로 복호</h4>
<p>전자서명(Digital Signature) 방식
송신자가 자신의 <strong>개인키로 메시지(또는 해시값)를 암호화(서명)</strong>하고,
수신자는 송신자의 <strong>공개키로 복호화(검증)</strong>해서
메시지가 위변조되지 않았고,송신자가 진짜 서명자임을 확인
즉, &quot;인증·무결성·부인방지&quot;가 목적</p>
<h4 id="공개키로-암호화-개인키로-복호화">공개키로 암호화, 개인키로 복호화</h4>
<p>&quot;기밀성 보장&quot;을 위한 공개키 암호화(Public Key Encryption) 방식.
송신자가 수신자의 공개키로 메시지를 암호화해서 보내면,
오직 수신자만 자신의 개인키로 복호화
즉, &quot;비밀 유지(기밀성)&quot;가 목적</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/05 면접 준비(SpringBoot), HTTP 요청]]></title>
            <link>https://velog.io/@no-merit/0505-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84SpringBoot-HTTP-%EC%9A%94%EC%B2%AD</link>
            <guid>https://velog.io/@no-merit/0505-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84SpringBoot-HTTP-%EC%9A%94%EC%B2%AD</guid>
            <pubDate>Mon, 05 May 2025 11:09:37 GMT</pubDate>
            <description><![CDATA[<h1 id="getmapping">@GetMapping</h1>
<ul>
<li>HTTP GET 요청을 처리</li>
<li>주로 데이터를 조회할 때 사용</li>
<li>요청 데이터는 URL의 쿼리 파라미터로 전달되며, URL에 노출</li>
<li>여러 번 요청해도 결과가 바뀌지 않는 idempotent한 작업에 적합</li>
<li>@GetMapping은 데이터를 URL의 쿼리스트링에 포함시켜 전송하므로, 요청 데이터(예: 아이디, 비밀번호 등)가 주소창이나 서버 로그, 브라우저 기록 등에 노출되어 보안에 취약</li>
</ul>
<h1 id="postmapping">@PostMapping</h1>
<ul>
<li>HTTP POST 요청을 처리</li>
<li>주로 데이터를 생성하거나 서버로 전송할 때 사용</li>
<li>요청 데이터는 HTTP Body에 담겨 전송되어, URL에 노출되지 않음</li>
<li>여러 번 요청하면 결과가 달라질 수 있는 non-idempotent 작업에 적합</li>
<li>@PostMapping은 데이터를 HTTP 요청의 Body에 담아 전송하므로, URL에 노출되지 않아 GET 방식보다 상대적으로 보안이 더 강함</li>
<li>POST 방식도 네트워크 구간에서 암호화(HTTPS)가 적용되지 않으면 데이터가 노출될 수 있으므로, 민감한 정보는 반드시 HTTPS와 함께 사용해야 안전</li>
</ul>
<h1 id="putmapping">@PutMapping</h1>
<ul>
<li>전체 리소스의 수정(덮어쓰기)에 주로 사용</li>
<li>요청에 포함되지 않은 필드는 null이나 기본값으로 바뀔 수 있음.\</li>
<li>기존 리소스의 모든 내용을 새 데이터로 완전히 대체</li>
</ul>
<h1 id="patchmapping">@PatchMapping</h1>
<ul>
<li>리소스의 일부만 부분적으로 수정할 때 사용</li>
<li>변경하고 싶은 필드만 요청에 포함시키면 해당 부분만 수정되고, 나머지 필드는 그대로 유지</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/04 면접 준비(Java), 문자열 리터럴]]></title>
            <link>https://velog.io/@no-merit/0501-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84Java</link>
            <guid>https://velog.io/@no-merit/0501-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84Java</guid>
            <pubDate>Sun, 04 May 2025 12:51:27 GMT</pubDate>
            <description><![CDATA[<h1 id="문자열-리터럴">문자열 리터럴</h1>
<blockquote>
<p>String X = &quot;123&quot;;
X = &quot;0&quot;+X; 의 연산</p>
</blockquote>
<ul>
<li>문자열 리터럴 저장:<ul>
<li>&quot;123&quot;과 &quot;0&quot;은 모두 자바의 String Pool (문자열 상수 풀)에 저장.</li>
<li>이 풀은 힙 메모리 내의 특별한 공간으로, 동일한 문자열 리터럴이 여러 번 등장해도 한 번만 저장되고 여러 참조가 그 객체를 가리킴</li>
</ul>
</li>
<li>문자열 연결(Concatenation):<ul>
<li>자바의 String은 immutable (불변)이기 때문에 기존 객체를 수정하지 않고 항상 새로운 객체를 생성</li>
</ul>
</li>
<li>참조 변경:<ul>
<li>X 변수는 이제 &quot;0123&quot;이라는 새로운 String 객체를 가리킴.</li>
<li>이전에 X가 참조하던 &quot;123&quot; 객체는 더 이상 X와 연결되어 있지 않음.</li>
</ul>
</li>
<li>String Pool과 새 객체:<ul>
<li>만약 &quot;0123&quot;이라는 리터럴이 코드 어딘가에 이미 존재했다면, X는 그 String Pool의 객체를 참조</li>
<li>그렇지 않다면, &quot;0123&quot;이 새로 생성되어 힙에 저장되고, 필요하다면 String Pool에도 추가.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/02 면접준비(Java)/OOP]]></title>
            <link>https://velog.io/@no-merit/2.-0502-%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84JAVA</link>
            <guid>https://velog.io/@no-merit/2.-0502-%EB%A9%B4%EC%A0%91%EC%A4%80%EB%B9%84JAVA</guid>
            <pubDate>Thu, 01 May 2025 16:11:31 GMT</pubDate>
            <description><![CDATA[<h1 id="oop">OOP</h1>
<blockquote>
<p> 프로그램을 객체들의 상호작용으로 구성하는 방식</p>
</blockquote>
<ul>
<li>추상화 <ul>
<li>복잡한 내용을 숨기고 중요한 정보만 보여줌</li>
<li>추상 클래스와, 인터페이스</li>
<li>공통 기능의 틀만 제공하고, 세부 구현은 자식 클래스에서 맡김</li>
</ul>
</li>
<li>캡슐화<ul>
<li>데이터와 메서드를 하나의 객체로 묶고 외부의 접근을 막는 것</li>
<li>내부 구현을 숨기고 접근 제한</li>
<li>private, public 등 접근 제한자 사용</li>
</ul>
</li>
<li>상속<ul>
<li>부모 클래스의 속성과 기능을 자식 클래스가 물려받는 것</li>
<li>코드 재사용성 </li>
</ul>
</li>
<li>다형성<ul>
<li>같은 매서드 이름이지만 다르게 동작</li>
<li>오버라이딩, 오버로딩</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[05/01 면접 준비(DB)/RDBMS,NoSQL]]></title>
            <link>https://velog.io/@no-merit/0501-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84DB</link>
            <guid>https://velog.io/@no-merit/0501-%EB%A9%B4%EC%A0%91-%EC%A4%80%EB%B9%84DB</guid>
            <pubDate>Thu, 01 May 2025 14:08:10 GMT</pubDate>
            <description><![CDATA[<h1 id="rdbms-와-nosql">RDBMS 와 NoSQL</h1>
<blockquote>
<p>RDBMS는 구조화된 데이터와 일관성이 중요한 환경일 때
NoSQL은 대규모, 다양하고 변화가 많은 데이터를 빠르게 처리해야 하는 환경일 때</p>
</blockquote>
<h1 id="rdbms">RDBMS</h1>
<ul>
<li>전통적인 RDBMS는 ACID(원자성, 일관성, 고립성, 지속성)라는 트랜잭션 보장 규칙을 따름.<ul>
<li>원자성(Atomicity) - 트랜잭션에 포함된 모든 작업이 전부 실행하거나 전부 실패해야 함.</li>
<li>일관성(Consistency) - 트랜잭션이 성공적으로 완료되면 데이터베이스는 항상 정의된 규칙(스키마, 제약조건 등)에 맞는 일관된 상태를 유지. 데이터무결성보장</li>
<li>고립성(Isolation) - 여러 트랜잭션이 동시에 실행될 때, 각각의 트랜잭션은 서로의 작업에 영향을 받지 않아야 함.</li>
<li>지속성(Durability) - 트랜잭션이 커밋된 이후에는 그 결과가 영구적으로 데이터베이스에 반영.</li>
</ul>
</li>
</ul>
<h4 id="acid의-각-속성이-실제-서비스-어떤-의미인가">ACID의 각 속성이 실제 서비스 어떤 의미인가</h4>
<blockquote>
<p>실제 서비스에서 ACID 속성은 데이터의 신뢰성과 사용자 경험을 보장하는 데 필수적이다.
예를 들어, 은행 송금과 같은 금융 서비스에서는 원자성이 보장되지 않으면 송금 도중 오류가 발생했을 때 한쪽 계좌에서만 돈이 빠져나가거나 들어오는 문제가 발생할 수 있다. 일관성이 없다면 잘못된 데이터가 저장되어 시스템 전체에 오류를 유발할 수 있고, 격리성이 부족하면 동시에 여러 사용자가 접근할 때 데이터가 꼬일 수 있다. 마지막으로 지속성이 없으면 시스템 장애 시 거래 내역이 유실되어 신뢰를 잃게 된다.</p>
</blockquote>
<h4 id="격리성--대표적인-격리-수준과-그-차이">격리성 : 대표적인 격리 수준과 그 차이</h4>
<blockquote>
</blockquote>
<ul>
<li>Read Uncommitted: 다른 트랜잭션에서 아직 <strong>커밋되지 않은 데이터</strong>를 읽을 수 있어, Dirty Read가 발생할 수 있음.</li>
<li>Read Committed: <strong>커밋된 데이터</strong>만 읽을 수 있어 Dirty Read는 방지되지만, Non-repeatable Read가 발생할 수 있음.</li>
<li>Repeatable Read: <strong>트랜잭션이 시작될 때 스냅샷을 생성해 트랜잭션 동안 읽은 데이터가 항상 동일하게 보장</strong>되어 Non-repeatable Read를 방지하지만, Phantom Read는 발생할 수 있음.(Mysql)<ul>
<li>일반적인 상황에서는 트랜잭션 내 조회는 스냅샷에서 이루어지니까 팬텀리드가 없지만 특수한 상황(범위 쿼리)를  사용하면 스냅샷이 아닌 실제 데이터에 대한 잠금을 시도함. -&gt; 다른 트랜잭션이 넣은 데이터를 조회할 수 있음.</li>
<li>SELECT * FROM table WHERE ... FOR UPDATE;</li>
<li>스냅샷이 아니라, 실행 시점의 최신 커밋 데이터를 읽음</li>
</ul>
</li>
<li>Serializable: 가장 높은 수준으로, <strong>트랜잭션이 완전히 순차적으로 실행된 것과 같은 효과를 보장하여 모든 동시성 문제를 방지</strong>합니다. 하지만 성능 저하가 클 수 있음. 데드락 발생 가능성 높음</li>
</ul>
<hr>
<h1 id="nosql">NoSQL</h1>
<blockquote>
<p>전통적인 관계형 데이터베이스(RDBMS)와 달리 테이블 기반의 고정된 스키마와 데이터 간의 관계를 사용하지 않는 비관계형 데이터베이스&#39;</p>
</blockquote>
<h4 id="특징">특징</h4>
<ul>
<li>비관계형 구조: 데이터 간의 관계(Join, Foreign Key 등)를 정의하지 않고, 다양한 데이터 모델(문서, 키-값, 그래프 등)을 지원</li>
<li>유연한 스키마: 고정된 스키마가 없거나 느슨한 스키마를 사용하여, 데이터 구조를 자유롭게 변경</li>
<li>수평적 확장성: 여러 서버에 데이터를 분산 저장하여 대용량 데이터와 트래픽을 효율적으로 처리</li>
<li>고성능: 단순한 데이터 접근 패턴에 대해 높은 읽기/쓰기 성능을 제공<ul>
<li>데이터를 단순하게(예: 키로 값을 바로 찾거나, 한 번의 쿼리로 필요한 정보를 모두 읽고/쓰는 방식)
→ get(&quot;user:1001&quot;)처럼, 한 번의 키로 바로 값을 읽거나 저장
→ 한 사용자의 정보와 주문 내역을 한 document에 모두 저장
→ 이렇게 하면, 한 번의 쿼리로 모든 정보를 읽거나 쓸 수 있어 IO(입출력) 횟수가 줄고, 성능이 높아짐</li>
</ul>
</li>
<li>최종적 일관성(Eventual Consistency): 대부분의 NoSQL 시스템은 RDBMS의 ACID(강한 일관성) 대신, 가용성과 확장성을 우선시하며 최종적 일관성을 지향<ul>
<li>데이터 업데이트가 모든 노드에 즉시 반영되지 않아도,
→ 일정 시간 후에는 모든 복제본이 동일한 상태로 수렴하는 것을 보장하는 모델.</li>
<li>소셜 미디어 좋아요:
→사용자 A가 포스트에 좋아요 → 즉시 반영되지만, 다른 사용자에게는 몇 초 후에 보일 수 있음</li>
</ul>
</li>
<li>분산 저장과 동시성 처리의 관계(즉시 정확성보다 가용성과 성능을 우선시하는 서비스에 최적화된 설계 방식)
데이터를 여러 노드에 나누어 저장하면,
→ 각 노드가 독립적으로 요청을 처리할 수 있어 병렬 처리 능력이 향상
→ 예시: 1초에 10만 건의 요청이 들어올 때, 10개 노드로 분산하면 노드당 1만 건만 처리하면 됨.</li>
</ul>
<blockquote>
<h3 id="장점">장점</h3>
</blockquote>
<ul>
<li>대용량 데이터 처리 및 분산 환경에 최적화.</li>
<li>스키마가 유연하여 데이터 구조 변경이 용이.</li>
<li>저렴한 비용으로 확장 및 병렬 처리 가능.</li>
<li>비정형 데이터(예: 로그, SNS, IoT 데이터 등) 저장에 적합.</li>
</ul>
<blockquote>
<h3 id="단점">단점</h3>
</blockquote>
<ul>
<li>데이터 일관성이 항상 보장되지 않음(최종적 일관성).</li>
<li>복잡한 쿼리나 조인 연산이 어렵거나 불가능. -&gt;여러번 쿼리를 날려야 함</li>
<li>인덱스 관리 등에서 메모리 자원 소모가 클 수 있음.</li>
<li>트랜잭션 처리 및 데이터 무결성 측면에서 RDBMS에 비해 약함</li>
</ul>
<hr>
<h1 id="비교">비교</h1>
<ul>
<li><p>RDBMS를 선택해야 하는 경우</p>
<ul>
<li>데이터 무결성과 일관성이 매우 중요할 때</li>
<li>데이터 구조가 명확하고 자주 변경되지 않을 때</li>
<li>복잡한 쿼리와 조인이 필요한 경우</li>
<li>트랜잭션 처리가 중요한 업무(예: 금융, 회계 등)</li>
<li>RDBMS는 주로 수직적 확장(서버 성능 업그레이드)에 의존</li>
</ul>
</li>
<li><p>NoSQL을 선택해야 하는 경우</p>
<ul>
<li>대규모, 다양한 형태의 데이터를 빠르게 처리해야 할 때</li>
<li>데이터 구조가 자주 변경되거나 유연성이 필요할 때</li>
<li>높은 확장성과 가용성이 필요한 경우</li>
<li>실시간 분석, 로그, 소셜 미디어 등 비정형 데이터 처리</li>
<li>수평적 확장(서버 추가)을 통해 대규모 데이터와 트래픽을 효율적으로 처리</li>
</ul>
</li>
</ul>
<hr>
]]></description>
        </item>
        <item>
            <title><![CDATA[AWS Linux에 JAVA17 설치하기]]></title>
            <link>https://velog.io/@no-merit/AWS-Linux%EC%97%90-JAVA17-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@no-merit/AWS-Linux%EC%97%90-JAVA17-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 24 Mar 2025 09:30:27 GMT</pubDate>
            <description><![CDATA[<p><a href="https://docs.aws.amazon.com/corretto/latest/corretto-17-ug/amazon-linux-install.html">AWS 문서</a></p>
<p><code>sudo yum install java-17-amazon-corretto</code></p>
<blockquote>
<p>위의 명령어로 자바 17을 설치했는데 javac 가 없어서 찾아봤다.</p>
</blockquote>
<p><code>sudo yum install java-17-amazon-corretto-devel</code></p>
<blockquote>
<p>이걸 써야 javac 까지 설치가 되는 듯 하다.
설치 후 환경변수 설정도 해줘야 함.</p>
</blockquote>
<p><a href="https://green-joo.tistory.com/12">참고 블로그</a> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[필터와 인터셉터]]></title>
            <link>https://velog.io/@no-merit/%ED%95%84%ED%84%B0%EC%99%80-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0</link>
            <guid>https://velog.io/@no-merit/%ED%95%84%ED%84%B0%EC%99%80-%EC%9D%B8%ED%84%B0%EC%85%89%ED%84%B0</guid>
            <pubDate>Thu, 23 May 2024 08:59:29 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>공통적으로 여러 작업을 처리함으로써 중복된 코드를 제거하도록 하는 기능.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/no-merit/post/bc97f5ef-d340-48f9-9da0-22108c92e344/image.png" alt=""></p>
<h2 id="필터">필터</h2>
<blockquote>
<p>디스패처 서블릿에 요청이 전달되기 전/후에 url 패턴에 맞는 모든 요청에 대해 부가 작업을 처리할 수 있는 기능 제공.
디스패처 서블릿은 스프링의 가장 맢단에 존재하는 프론트 컨트롤러이므로, 필터는 스프링 범위 밖에서 처리.
스프링 컨테이너가 아닌 톰캣과 같은 웹 컨테이너(서블릿 컨테이너)에 의해 관리가 되는 것.</p>
</blockquote>
<ul>
<li>필터를 추가하기 위해서는 Filter 인터페이스를 구현해야함<ul>
<li>init, doFilter, destroy 매서드를 가지고 있음</li>
<li>init : 필터 객체를 초기화하고 서비스에 추가하기 위한 매서드</li>
<li>doFilter : url-pattern에 맞는 모든 HTTP 요청이 디스패처 서블릿으로 전달되기 전에 웹 컨테이너에 의해 실행되는 매서드.<ul>
<li>FilterChain 을 파라미터로 받아서 다음 대상으로 요청을 전달.</li>
<li>chain.doFilter 전/후에 우리가 필요한 처리 과정을 넣어줌으로써 원하는 처리를 진행</li>
</ul>
</li>
<li>destroy : 필터 객체를 서비스에서 제거하고 사용하는 자원을 반환하기 위한 매서드.</li>
</ul>
</li>
</ul>
<hr>
<h2 id="인터셉터">인터셉터</h2>
<blockquote>
<p>디스패처 서블릿이 컨트롤러를 호출하기 전과 후에 요청과 응답을 참조하거나 가공할 수 있는 기능을 제공.
웹 컨테이너(서블릿 컨테이너)에서 동작하는 필터와 달리 스프링 컨텍스트에서 동작하는 것.</p>
</blockquote>
<ul>
<li><p>인터셉터를 추가하기 위해서는 HandlerInterceptor 인터페이스를 구현해야 하며 이는 다음의 3가지 매서드를 가지고 있음.</p>
<ul>
<li>preHandle, postHandle, afterCompletion 매서드</li>
<li>preHandle : 컨트롤러가 호출되기 전에 실행. 전처리 작업이나 요청 정보를 가공하는 경우<ul>
<li>반환 타입이 boolean이라 true이면 다음 단계 진행, false라면 작업 중단</li>
</ul>
</li>
<li>postHandle : 컨트롤러가 호출될 후 실행</li>
<li>afterCompletion : 모든 뷰에서 최종 결과를 생성하는 일을 포함해 모든 작업이 완료된 후에 실행됨<ul>
<li>요청 처리 중에 사용한 리소스를 반환할 때 사용하기에 적합</li>
</ul>
</li>
</ul>
</li>
<li><p>인터셉터/AOP 비교</p>
<ul>
<li>다음과 같은 이유들로 컨트롤러의 호출 과정에 적용되는 부가기능들은 인터셉터를 사용하는 편이 나음</li>
<li>컨트롤러는 타입과 실행 메소드가 모두 제각각이라 포인트컷의 작성이 어려움</li>
<li>컨트롤러는 파라미터나 리턴 값이 일정하지 않음</li>
<li>AOP에서는 req,res 객체를 얻기 어렵지만 인터셉터에서는 파라미터로 넘어옴</li>
</ul>
</li>
</ul>
<hr>
<h2 id="필터와-인터셉터">필터와 인터셉터</h2>
<p><img src="https://velog.velcdn.com/images/no-merit/post/6075a304-2e6e-41bb-ba7f-b70803a5e160/image.png" alt=""></p>
<ul>
<li><p>컨테이너</p>
<ul>
<li>필터와 인터셉터는 관리되는 영역이 다름</li>
<li>필터는 스프링 이전의 서블릿 영역에서 관리되지만, 인터셉터는 스프링 영역에서 관리되는 영역이기 때문에 필터는 스프링이 처리해주는 내용들을 적용 받을 수 없음.<ul>
<li>필터는 스프링에 의한 예외처리가 되지 않음</li>
</ul>
</li>
</ul>
</li>
<li><p>스프링의 예외 처리 여부</p>
<ul>
<li>일반적으로 스프링을 사용하면 ControllerAdvice와 ExceptionHandler를 이용한 예외처리 기능을 주로 사용.</li>
<li>하지만 필터는 스프링의 앞의 서블릿 영역에서 관리되기 때문에 스프링의 지원을 받을 수 없음.</li>
<li>그래서 필터에서 Exception이 던져지면 에러가 처리되지 않고 서블릿까지 전달.</li>
<li>서블릿은 예외가 핸들링 되기를 기대했지만 예외가 그대로 올라와서 예상치 못한 Exception을 만나 500 응답.</li>
</ul>
</li>
<li><p>req,res 객체 조작 가능 여부</p>
<ul>
<li>필터는 req, res 객체를 바꿀 수 있지만 인터셉터는 아님.</li>
</ul>
</li>
</ul>
<h4 id="필터-1">필터</h4>
<ul>
<li><p>공통된 보안 및 인증/인가 관련 작업</p>
</li>
<li><p>모든 요청에 대한 로깅 또는 감사</p>
</li>
<li><p>이미지/ 데이터 압축 및 문자열 인코딩</p>
</li>
<li><p>Spring과 분리되어야 하는 기능</p>
<blockquote>
<p>필터에서는 기본적으로 스프링과 무관하게 전역적으로 처리해야 하는 작업들을 처리할 수 있음.</p>
</blockquote>
</li>
<li><p>보안 공통 작업 : 필터는 인터셉터보다 앞단에서 동작하므로 전역적으로해야하는 보안 검사를 해서 올바른 요청이 아닐 경우 차단을 할 수 있음.</p>
<ul>
<li>스프링 컨테이너까지 요청이 전달되지 못하고 차단되므로 안정성을 더 높일 수 있음.</li>
</ul>
</li>
<li><p>필터는 이미지나 데이터의 압축이나 문자열 인코딩과 같이 웹 애플리케이션에 전반적으로 사용되는 기능을 구현하기 적당함.</p>
</li>
<li><p>req,res 객체를 조작할 수 있다는 점에서 인터셉터보다 강력함</p>
<h4 id="인터셉터-1">인터셉터</h4>
</li>
<li><p>세부적인 보안 및 인증/인가 공통 작업</p>
</li>
<li><p>API 호출에 대한 로깅 또는 감사</p>
</li>
<li><p>Controller로 넘겨주는 정보의 가공</p>
<blockquote>
<p>인터셉터에서는 클라이언트의 요청과 관련되어 전역적으로 처리해야 하는 작업들을 처리할 수 있음.</p>
</blockquote>
</li>
<li><p>req,res 객체를 가공할 수 있음</p>
<ul>
<li>사용자의 ID를 기반으로 조회한 사용자 정보를 HttpServletRequest에 넣어줄 수 있음</li>
</ul>
</li>
</ul>
<hr>
<h2 id="delegatingfilterproxy">DelegatingFilterProxy</h2>
<blockquote>
<p>서블릿 컨테이너에서 관리되는 프록시용 필터로써 우리가 만든 필털르 가지고 있음
우리가 만든 필터는 스프링 컨테이너의 빈으로 등록되는데 요청이 오면 DelegatetingFilterProxy가 요청을 받아서 우리가 만든 필터에게 요청을 위임함</p>
</blockquote>
<ol>
<li>Filter 구현체가 스프링 빈으로 등록됨</li>
<li>ServletContext가 Filter 구현체를 갖는 DelegatingFilterProxy를 생성함</li>
<li>ServletContext가 DelegatingFilterProxy를 서블릿 컨테이너에 필터로 등록</li>
<li>요청이 오면 DelegatingFilterProxy가 필터 구현체에게 요청을 위임하여 필터 처리를 진행함</li>
</ol>
<ul>
<li>SpringBoot가 등장한 이후<ul>
<li>DelegatingFilterProxy에 등록할 필요가 없음</li>
<li>SpringBoot가 내장 웹서버를 지원하면서 톰캣과 같은 서블릿 컨테이너까지 SpringBoot가 제어가능하기 때문.</li>
<li>SpringBoot가 서블릿 필터의 구현체 빈을 찾으면 DelegatingFilterProxy없이 바로 필터 체인에 필터를 등록해주기 때문</li>
</ul>
</li>
</ul>
<ul>
<li>등장 배경 : 필터에서 다른 스프링 빈의 주입이 필요해짐</li>
<li>등장 이전 : 스프링 빈으로 등록 및 다른 빈 주입이 불가능 했음</li>
<li>등장 이후 : DelegatingFilterProxy를 통해 스프링 빈으로 등록 및 다른 빈 주입이 가능해짐</li>
<li>SpringBoot의 등장 이후 : 웹서버를 직접 관리하면서 DelegatingFilterProxy 조차 필요없게 됨.</li>
</ul>
<hr>
<h3 id="출처">출처</h3>
<p><a href="https://mangkyu.tistory.com/221">망나니개발자님 블로그</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[6. 프레임워크와 라이브러리]]></title>
            <link>https://velog.io/@no-merit/6.-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%99%80-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</link>
            <guid>https://velog.io/@no-merit/6.-%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EC%99%80-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC</guid>
            <pubDate>Wed, 22 May 2024 14:18:43 GMT</pubDate>
            <description><![CDATA[<h2 id="프레임워크와-라이브러리의-차이">프레임워크와 라이브러리의 차이</h2>
<h3 id="프레임워크">프레임워크</h3>
<blockquote>
<p>개발자가 소프트웨어를 개발함에 있어 코드를 구현하는 개발 시간을 줄이고 코드의 재사용성을 증가 시키기 위해 일련의 클래스 묶음이나 뼈대, 틀을 라이브러리 형태로 제공되는 것.
  제어의 역전 개념이 적용된 기술(작성한 객체나 메서드의 제어를 개발자가 아니라 애플리케이션이나 프레임워크에 위임하는 것)</p>
</blockquote>
<ul>
<li><p>프레임워크의 특징</p>
<ol>
<li>개발자가 따라야 하는 가이드를 제공함</li>
<li>개발할 수 있는 범위가 정해져있음</li>
<li>개발자를 위한 다양한 도구, 플러그인을 지원함</li>
</ol>
</li>
<li><p>장단점</p>
<ol>
<li><p>개발 시간을 줄일 수 있음</p>
</li>
<li><p>정형화 되어 있어 일정 수준 이상의 품질을 기대</p>
</li>
<li><p>유지 보수가 쉬움</p>
</li>
<li><p>너무 의존하면 스스로 개발하는 능력이 없어짐</p>
</li>
<li><p>프레임위크를 배워야함.</p>
</li>
</ol>
<ul>
<li>종류</li>
</ul>
<ol>
<li>영속성 프레임워크(Mybatis, Hibernate)</li>
<li>자바 프레임워크(Spring)</li>
<li>화면 구성 프레임워크(Bootstrap)</li>
<li>기능 및 지원 프레임워크(Log4j, JUnit5)</li>
</ol>
</li>
</ul>
<hr>
<h3 id="라이브러리">라이브러리</h3>
<p>  개발자가 만든 클래스들의 나열, 다른 프로그램들에서 사용할 수 있도록 제공하는 방식.</p>
<hr>
<ul>
<li><p>둘의 차이
라이브러리와 프레임워크의 차이는 제어 흐름에 대한 주도성이 누구에게/ 어디에게 있는가.</p>
<ol>
<li>프레임워크는 스스로 제어 흐름의 주도성을 가지고 있음. vs 라이브러리는 개발자가 가지고 있음.</li>
<li>프레임워크는 집이고, 라이브러리는 가구이다.</li>
<li>라이브러리와 달리 프레임워크는 프로그래밍에 대한 규칙을 가지고 있음.(설정파일의 태그성정이나, DB연동 방법등에 대한 규칙을 가지고 있고 개발자는 이를 따라야함.)</li>
</ol>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[자율 프로젝트 마무리 Security 정리]]></title>
            <link>https://velog.io/@no-merit/%EC%9E%90%EC%9C%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%88%EB%AC%B4%EB%A6%AC-Security-%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@no-merit/%EC%9E%90%EC%9C%A8-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%88%EB%AC%B4%EB%A6%AC-Security-%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Wed, 22 May 2024 14:16:20 GMT</pubDate>
            <description><![CDATA[<h1 id="springsecurity">SpringSecurity</h1>
<blockquote>
<p>스프링 기반 애플리케이션의 보안(인증과 권한, 인가)등을 담당하는 하위 프레임워크.</p>
</blockquote>
<ul>
<li><p>인증(로그인,Authentication)과 권한(접근권한,Authorization)을 Filter 흐름에 따라 처리.</p>
</li>
<li><p>Filter와 Interceptor</p>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[FormLogin]]></title>
            <link>https://velog.io/@no-merit/FormLogin</link>
            <guid>https://velog.io/@no-merit/FormLogin</guid>
            <pubDate>Wed, 10 Apr 2024 12:40:56 GMT</pubDate>
            <description><![CDATA[<blockquote>
<ul>
<li>사용자가 서버에 특정 URL을 요청하면 해당 URL이 인증이 필요한 경우 서버는 Login 페이지를 return</li>
</ul>
</blockquote>
<ul>
<li>사용자가 username과 password를 입력하여 로그인 요청을 하면 해당 데이터가 서버에 전송됨</li>
<li>서버는 해당 로그인 정보를 확인 후 해당 유저 정보가 존재한다면 Session과 Token을 생성하고 저장</li>
<li>이런 과정을 거친 후 사용자가 원래 접속하려던 url에 접속 요청을 할 경우 세션에 저장된 인증 토큰으로 접근할 수 있게 되며 세션에 인증토큰이 있는 동안은 해당 사용자가 인증된 사용자가 됨.</li>
</ul>
<pre><code class="language-java">protected void configure(HttpSecurity http) throws Exception {
    http.formLogin()
       .loginPage(“/login.html&quot;)               // 사용자 정의 로그인 페이지
       .defaultSuccessUrl(&quot;/home)            // 로그인 성공 후 이동 페이지
       .failureUrl(＂/login.html?error=true“)            // 로그인 실패 후 이동 페이지
       .usernameParameter(&quot;username&quot;)            // 아이디 파라미터명 설정
       .passwordParameter(“password”)            // 패스워드 파라미터명 설정
       .loginProcessingUrl(“/login&quot;)            // 로그인 Form Action Url
       .successHandler(loginSuccessHandler())        // 로그인 성공 후 핸들러
       .failureHandler(loginFailureHandler())        // 로그인 실패 후 핸들러
}</code></pre>
<ul>
<li>loginPage(): 인증이 필요할 때 이동하는 페이지를 설정하는 api.<ul>
<li>해당 api를 설정하지 않으면 기본적으로 spring security가 제공하는 템플릿으로 연결.</li>
<li>작성한 코드로 인증이 필요할 때 해당 URL로 mapping</li>
</ul>
</li>
<li>defaultSuccessUrl(): 인증이 성공했을 때 default로 이동하는 URL을 지정하는 api</li>
<li>loginProcessingUrl: 폼태그의 action url을 설정하는 api</li>
</ul>
<ol>
<li><p>Form Login을 사용하게 된다면 인증 필터인 UsernamePasswordAuthenticationFilter가 실행</p>
</li>
<li><p>AntPathRequestMatcher가 요청정보를 체크해서 일치하지 않으면 Filter로 보냄</p>
</li>
<li><p>일치하면 username과 password 정보가 담긴 Authentication 객체를 생성해서 AuthenticationManager에 넘김</p>
</li>
<li><p>AuthenticationManager는 이전 과정에서 받은 Authentication 객체를 AuthenticationProvider에 넘김</p>
</li>
<li><p>AuthenticationProvider는 실직적으로 인증을 체크.
인증에 성공하면 인증된 Authentication 객체를 생성</p>
</li>
<li><p>AuthenticationManager 가 인증된 Authentication 객체를 넘김</p>
</li>
<li><p>최종 Authentication 객체가 Security Context에 저장</p>
</li>
<li><p>이후에는 SecurityContextHolder.getContext().getAuthentication()코드를 통해 인증객체를 꺼내 쓸 수 있음.</p>
</li>
</ol>
<hr>
<ul>
<li>requestMatchers()<ul>
<li>요청 타입에 따라 URL 패턴을 지정</li>
<li>requestMatchers(HttpMethod.GET,&quot;/&quot;) HTTP 매서드 중 GET 요청 처리 가능</li>
</ul>
</li>
<li>antMatchers()<ul>
<li>URL 패턴에 대한 접근 권한을 설정</li>
<li>일반적으로 사용</li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[해시]]></title>
            <link>https://velog.io/@no-merit/%ED%95%B4%EC%8B%9C</link>
            <guid>https://velog.io/@no-merit/%ED%95%B4%EC%8B%9C</guid>
            <pubDate>Mon, 08 Apr 2024 08:57:40 GMT</pubDate>
            <description><![CDATA[<h2 id="해시-자료구조">해시 자료구조</h2>
<blockquote>
<p>여러 길이의 데이터를 효율적으로 관리하기 위해 해시함수를 통해 일정한 길이의 값으로 매핑하는 것.
해시는 내부적으로 배열을 사용하여 데이터를 저장하기 때문에 검색 속도가 빠름.</p>
</blockquote>
<ol>
<li>해당 원소의 해시 함수를 이용해서 해시값을 얻음</li>
<li>해시값을 주소로 하는 위치에 원소를 저장</li>
<li>저장 후 검색 시에도 원소의 해시값으로 계산해 해당 위치로 이동</li>
</ol>
<h3 id="해시충돌">해시충돌</h3>
<blockquote>
<p>데이터가 많아지면 같은 키 값을 갖는 데이터가 생긴다는 것, 특정 키의 버켓에 데이터가 집중 된다는 뜻.
너무 많은 해시 충돌은 해시테이블의 성능을 떨어뜨림.
해시함수를 잘 정의해서 해시 충돌을 최소화 하는 것이 성능 개선에 도움이 됨.
해시함수의 입력값은 무한하지만, 출력값의 가짓수는 유한.</p>
</blockquote>
<h3 id="해시함수">해시함수</h3>
<blockquote>
<p>임의의 길이의 데이터를 고정된 길이의 해시 값으로 변환하는 함수.
데이터를 고르제 분포된 버킷에 할당하기 위해 사용.</p>
</blockquote>
<h4 id="충돌이-적은-해시-함수의-설계">충돌이 적은 해시 함수의 설계</h4>
<blockquote>
<p>동일한 해시 값을 가진 데이터가 두 개 이상인 경우 충돌이 발생할 수 있음.</p>
</blockquote>
<ul>
<li><p>체이닝</p>
<ul>
<li>해시 충돌이 발생하면 연결리스트를 사용해 중복된 값을 저장. 주로 구현이 간단한 체이닝 방법 사용</li>
<li>버켓이 꽉 차더라도 연결리스트로 계속 늘려가므로, 데이터의 주소값은 바뀌지 않음.</li>
<li>복잡한 계산식을 사용할 필요가 개방주소법에 비해 적음</li>
<li>해시테이블이 채워질수록, Lookup 성능저하가 Linear하게 발생</li>
<li>이 경우 최악의 경우 수행 시간이 O(n)이 됨.</li>
<li>해시를 사용하는 이유는 O(1)이라는 장점인데 O(n)이된다는 문제 발생.<ul>
<li>트리로 구성해서 더 시간 복잡도를 줄일 수 있음.</li>
</ul>
</li>
</ul>
</li>
<li><p>개방 주소법</p>
<ul>
<li>인덱스가 중복되었다면 다른 빈 인덱스를 찾아 저장함<ul>
<li>linear probing: 충돌시 빈 slot이 나올 때까지 탐색 후, 가장 가까운 빈 인덱스를 사용<ul>
<li>primary clustering 문제 발생.</li>
<li>한 번 충돌이 나면 집중적으로 충돌이 발생하는 것.</li>
<li>평균 검색 시간이 증가</li>
</ul>
</li>
<li>quadratic probing: 2의 제곱수로 탐색하여 빈 인덱스를 사용<ul>
<li>secondary clustering 문제 발생.</li>
<li>처음 충돌한 위치가 같다면 앞으로도 발생할 충돌위치도 반복적으로 계속 충돌</li>
</ul>
</li>
<li>double hashing probing : 빈 인덱스를 찾을 때까지 해시 함수를 사용해서 탐색</li>
<li>체이닝처럼 포인터가 필요없고, 지정한 메모리 외 추가적인 저장공간도 필요없음</li>
<li>삽입, 삭제시 오버헤드가 적음</li>
<li>저장할 데이터가 적을 때 더 유리</li>
</ul>
</li>
</ul>
</li>
<li><p>동적 해싱</p>
<ul>
<li>해시 테이블의 크기를 동적으로 조절해서 해시 충돌 최소화하고 효율적인 해시 테이블 유지</li>
</ul>
</li>
<li><p>자바는 개별체이닝, 파이썬은 오픈 어드레싱</p>
</li>
</ul>
<h4 id="double-hashing의-장점과-단점-해결방안">Double Hashing의 장점과 단점, 해결방안</h4>
<blockquote>
<p>충돌이 발생한 버킷에 다른 버킷에 데이터를 저장하는 방식.
두 개의 해시 함수를 사용해서 다음 이동 위치를 결정</p>
</blockquote>
<p>+장점</p>
<ul>
<li>해시 테이블의 공간 사용을 최소화하고 버킷들 사이의 균형을 맞추어 해시 충돌을 감소시킬 수 있다는 점<ul>
<li>단점</li>
</ul>
</li>
<li>해시 함수의 선택이 중요함</li>
<li>연산량이 많음. 캐시의 효율이 좋지 않음</li>
</ul>
<ul>
<li><p>군집화(clustering)</p>
<ul>
<li>개방 주소법을 사용하면 해시값이 몰리는 군집화가 발생함.</li>
<li>선형조사는 1차 군집화</li>
<li>이차, 랜덤 조사는 2,3차 군집화가 발생</li>
<li>이중 해싱은 동의어들이 저마다 제 2의 해시함수를 갖고 있기 때문에 점프 시퀀스가 일정하지 않음</li>
<li>이중해싱은 군집화의 해결방법</li>
</ul>
<p><code>(h(key)+jXd(key))%M, j=0,1,2,3...</code>
기본적인 해시함수 h로 키를 인덱스로 변환하고 두번째 함수 d는 다음 위치를 위한 점프 크키를 규칙에 따라 정함.
d는 점프 크기를 정하는 함수이므로 0을 리턴해서는 안됨.
그리고 d의 해시값과 해시테이블의 크기 M은 서로소 관계일 때 좋은 성능을 만들어냄.
(M을 소수로 선택하면 자연스럽게 만족)</p>
</li>
</ul>
<h4 id="load-factor적재율람다-자바의-해시-자료구조는-load-factor-정책">Load Factor(적재율,람다) 자바의 해시 자료구조는 Load Factor 정책</h4>
<ul>
<li>로드 팩터<ul>
<li>해시 테이블에 저장된 데이터 개수 n을 버킷의 개수 k로 나눈 것</li>
<li>로드 팩터의 비율에 따라서 해시 함수를 재작성하거나 해시 테이블의 크기를 조정</li>
<li>자바 10에서는 해시 맵 디폴트 로트 팩터를 0.75로 정해서 이를 넘는 경우 해시 테이블의 공간을 재할당</li>
</ul>
</li>
</ul>
<h3 id="자바">자바</h3>
<blockquote>
<p>jdk 7 까지는 linked list를 사용한 separate chaining 사용, O(N)
jdk 8 에서 linked list와 red black tree를 혼용한 separate chaining 활용
충돌이 적을 떄는 linkedlist, 많을 때는 red black tree로 작동, O(logN)</p>
</blockquote>
<ul>
<li>linkedlist는 탐색하는데 O(n)이들지만 red-black tree는 O(logN)이 들기 때문에 성능 개선임</li>
</ul>
<ul>
<li>동일하지 않은 어떤 객체 X와 Y가 있을 때</li>
<li>즉, X.equals(Y)가 거짓일 때, X.hashCode() != Y.hashCode()가 같지 않다면</li>
<li>이 때 사용하는 해시 함수는 완전한 해시 함수<ul>
<li>Integer, Long, Double같은 Number 객체는 객체가 나타내려는 값 자체를 해시 값으로 사용할 수 있기 때문에 완전한 해시 함수 대상으로 삼을 수 있음.</li>
<li>하지만 String 이나 POJO에 대해 완전한 해시 함수를 제작하는 것은 불가능</li>
<li>자바는 기본적으로 hashcode() 함수의 리턴값을 int로 지정해놓았기 때문에 2^32개의 객체를 다르게 저장할 수 있지만 가능한 키 범위가 더 많을 수도 있고, 가능한 키 범위와 동일하게 배열의 크기를 할당해 놓는게 아니라 동적으로 늘려가기 때문에 충돌이 발생할 수 밖에 없음.</li>
</ul>
</li>
<li>인덱스를 정하는 방법은 int index = X.hasgCode()%M;<ul>
<li>M은 배열의 크기</li>
<li>이 식에서 알 수 있는 것은 hashcode의 값이 달랐더라도 M 모듈러 연산을 하면서 한번 더 해쉬충돌이 일어날 수 있어 총 2번의 충돌이 가능하다는 점</li>
</ul>
</li>
</ul>
<h4 id="멀티스레드-환경에서의-해시-테이블">멀티스레드 환경에서의 해시 테이블</h4>
<ul>
<li>Map 인터페이스의 구현체<ul>
<li>HashMap, HashTable, ConcurrentHashMap</li>
</ul>
</li>
</ul>
<ul>
<li>HashMap<ul>
<li>key와 value에 null을 허용</li>
<li>동기화를 보장하지 않음</li>
<li>thread-safe하지 않아 싱글 스레드 환경에서 사용해야함.</li>
<li>동기화 처리를 하지 않아서 데이터 탐색 속도가 빠름.</li>
<li>HashTable과 ConcorrentHashMap보다 데이터를 찾는 속도는 빠르지만, 신뢰성과 안정성이 떨어짐.</li>
</ul>
</li>
<li>HashTable<ul>
<li>key와 value에 null을 허용하지 않음</li>
<li>동기화를 보장</li>
<li>멀티 스레드 환경에 사용할 수 있음.</li>
<li>데이터를 다루는 get(), put(), remove()등의 메소드에 syncronized 키워드가 붙어 있음.(메소드 전체가 임계구역으로 설정)</li>
<li>해당 키워드를 메소드를 호출하기 전에 스레드간 동기화 락을 검<ul>
<li>멀티 스레드 환경에서 데이터의 무결성 보장.</li>
<li>스레드간 동기화 락은 매우 느린 동작이라는 단점</li>
<li>객체마다 Lock을 하나씩 다지고 있기 때문에 동시에 여러 작업을 해야할 때 병목현상이 발생.</li>
</ul>
</li>
</ul>
</li>
<li>ConcurrentHashMap<ul>
<li>key와 value에 null을 허용하지 않음</li>
<li>동기화를 보장</li>
<li>HashMap의 동기화 문제를 보완하기 위해 나타남.</li>
<li>동기화 처리를 할 때, 어떤 Entry를 조작하는 경우에 해당 Entry에 대해서만 락을 검.</li>
<li>HashTable보다 데이터를 다루는 속도가 빠름.</li>
<li>Entry 아이템 별로 락을 걸어 멀티 스레드 환경에서의 성능을 향상시킴.</li>
<li>get()에는 syncronized가 없어서 여러 스레드에서 동시에 읽을 수 있음</li>
<li>put()에는 특정 세그먼트 or 버킷에 Lock을 사용해서 스레드 세이프하게 사용가능</li>
<li>버킷 단위로 lock을 사용하기 때문에 같은 버킷만 아니라면 lock을 기다릴 필요가 없음.</li>
<li>같은 버킷만 아니라면 여러 쓰레드가 동시에 쓰는 작업을 할 수 있기 때문에
읽기 작업보다 쓰기 작업 성능이 중요한 작업에서 적합</li>
<li>읽기 작업은 동기화가 적용되지 않아서 검색직전 가장 최근에 완료된 업데이트 작업의 결과가 반영, 삭제된 게시글을 보려고 누르면 삭제된 게시글입니다 뜨고 끝</li>
</ul>
</li>
</ul>
<ul>
<li>thread-safe 하기 위해 syncronized 키워드를 사용<ul>
<li>여러개의 스레드가 한개의 자원을 사용하고자 할 떄, 현재 데이터를 사용하고 있는 스레드를 제외하고 나머지 스레드들은 데이터에 접근할 수 없도록 막는 것</li>
<li>변수와 함수에 사용해서 동기화 할 수 있음.</li>
<li>너무 사용하면 프로그램 성능 저하가 일어남</li>
<li>자바 내부적으로 block과 unblock을 처리하게 되어서 </li>
</ul>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[스택과 큐]]></title>
            <link>https://velog.io/@no-merit/%EC%8A%A4%ED%83%9D%EA%B3%BC-%ED%81%90</link>
            <guid>https://velog.io/@no-merit/%EC%8A%A4%ED%83%9D%EA%B3%BC-%ED%81%90</guid>
            <pubDate>Mon, 08 Apr 2024 02:27:34 GMT</pubDate>
            <description><![CDATA[<h4 id="스택-2개로-큐fifo">스택 2개로 큐(FIFO)</h4>
<ul>
<li>stack 1과 stack 2 생성</li>
<li>enqueue : stack 1에 원소를 push, O(1)</li>
<li>dequeue : stack 2가 비어있을 경우 stack 1의 원소를 pop한 뒤 stack 2에 push 후 stack 2의 top을 pop, O(n)</li>
<li>dequeue : stack 2가 차있을 경우, stack 2의 top을 pop, O(1)</li>
</ul>
<h4 id="큐-2개로-스택lifo">큐 2개로 스택(LIFO)</h4>
<ul>
<li>queue 1과 queue 2 생성</li>
<li>push: queue 1이 비어있으면 queue 2에 enqueue, 아니면 queue 1에 enqueue, O(1)</li>
<li>pop : 두 개의 queue 중 비어있지 않은 queue의 원소를 1개만 제외하고 다 다른 queue로 이동한 뒤 마지막 남은 원소를 반환, O(n)</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열과 리스트]]></title>
            <link>https://velog.io/@no-merit/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@no-merit/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Fri, 05 Apr 2024 08:38:55 GMT</pubDate>
            <description><![CDATA[<h4 id="배열과-링크드-리스트">배열과 링크드 리스트</h4>
<blockquote>
<p>배열과 링크드리스트는 데이터를 저장하고 관리하는데 사용되는 두 가지 기본적인 자료구조</p>
</blockquote>
<h3 id="배열과-링크드-리스트의-비교">배열과 링크드 리스트의 비교</h3>
<h4 id="배열">배열</h4>
<ul>
<li><p>연속된 메모리 공간에 데이터를 저장</p>
</li>
<li><p>인덱스를 사용해서 원소에 빠르게 접근이 가능, O(1)의 시간복잡도.</p>
<ul>
<li><p>인덱스 : 추가적인 쓰기 작업과 저장 공간을 활용해서 검색속도를 향상시키는 자료구조</p>
</li>
<li><p>인덱스를 활용하면 검색 뿐 아니라 수정, 삭제의 성능도 향상되는데 이유는 이 작업들에 항상 검색이 선행되기 때문</p>
</li>
<li><p>장점</p>
<ul>
<li>테이블 조회 속도 상승으로 인한 성능 향상</li>
<li>전반적인 시스템의 부하를 줄일 수 있음</li>
</ul>
</li>
<li><p>단점</p>
<ul>
<li>인덱스를 관리하기 위해 추가적인 저장공간이 필요</li>
<li>검색을 자주하는 테이블에 인덱스를 거는게 좋음</li>
<li>수정, 삭제, 입력이 잦은 테이블에 인덱스를 걸게 되면 인덱스의 크기가 비대해져서 성능이 오히려 저하됨<ul>
<li>규모가 큰 테이블</li>
<li>입력이 자주 발생하지 않는 컬럼</li>
<li>JOIN 이나 WHERE, ORDER BY에 자주 사용되는 컬럼</li>
<li>데이터의 중복도가 낮은 컬럼</li>
</ul>
</li>
</ul>
</li>
<li><p>인덱스는 해시 테이블이나 B+Tree로 구현함</p>
<ul>
<li>해시 테이블 기반의 DB 인덱스는 검색에 유리하지만 해시가 = 연산에 특화되었기 때문에 해시 함수의 특성상 값이 1이라도 달라지면 완전히 다른 해시 값을 생성하므로 부등호 연산이 자주 사용되는 데이터 베이스 검색에는 적합하지 않음</li>
<li>B+Tree는 리프노드만이 인덱스와 함께 value(데이터)를 가지고 있고 나머지 노드들은 인덱스만을 가지고 있음.<ul>
<li>리프노드들은 LinkedList로 연결되어 있음</li>
<li>데이터베이스의 인덱스 컬럼은 부등호를 이용한 순차 검색 연산이 자주 발생될 수 있으므로 B+Tree의 리프노드들을 LinkdedList로 연결해 순차검색을 용이하게 하는 등 B+Tree를 인덱스에 맞게 최적화.</li>
<li><a href="https://mangkyu.tistory.com/96">인덱스 공부에 참고한 블로그</a></li>
</ul>
</li>
</ul>
</li>
<li><p>고정된 크기를 가지고 크기 변경이 어려움. 미리 할당된 메모리 크기를 초과하면 새로운 메모리 공간을 할당하고 데이터를 복사해야함.</p>
</li>
<li><p>원소를 삽입하거나 삭제할 때 원소들을 이동시켜야 해서 시간이 오래 걸릴 수 있음. O(n)의 시간복잡도.</p>
</li>
<li><p>메모리 사용이 효율적. 각 원소는 인덱스로 접근되고 추가적인 메모리를 사용하지 않음</p>
</li>
</ul>
</li>
</ul>
<h4 id="링크드-리스트">링크드 리스트</h4>
<ul>
<li>각 노드가 데이터와 다음 노드에 대한 참조 포인터를 포함</li>
<li>노드들이 연속되지 않은 메모리 공간에 저장됨</li>
<li>원소에 접근하기 위해서는 리스트를 순차적으로 탐색해야함, O(n)의 시간복잡도</li>
<li>크기 변경이 쉬움. 새 노드를 동적으로 할당하거나 제거함으로써 리스트의 크기를 변경할 수 있음.</li>
<li>원소를 삽입하거나 삭제할 때 주소만 바꿔주면 되므로 O(1)의 시간복잡도를 가지지만 해당 위치를 검색하는 O(n)의 시간이 듦</li>
</ul>
<blockquote>
<p>배열은 인덱스를 사용한 빠른 접근이 필요하거나 크기가 고정된 경우에 적합,
링크드 리스트는 데이터의 삽입과 삭제가 빈번하거나 크기가 가변적인 경우에 적합</p>
</blockquote>
<ul>
<li><a href="https://www.nextree.co.kr/p6506/">배열과 링크드 리스트의 비교</a></li>
</ul>
<h3 id="링크드-리스트를-사용해서-구현할-수-있는-다른-자료구조">링크드 리스트를 사용해서 구현할 수 있는 다른 자료구조</h3>
<blockquote>
<p>배열로 구현할 수 있는 자료구조는 대부분 만들 수 있음.
대표적으로 스택이나 큐.</p>
</blockquote>
]]></description>
        </item>
    </channel>
</rss>