전체 글 167

WebSocket이란? Spring Boot로 간단한 실시간 통신 구현하기

일반적인 HTTP 통신에서는 클라이언트가 요청해야 서버가 응답할 수 있다.클라이언트 → 요청 → 서버클라이언트 ← 응답 ← 서버예를 들어 새로운 채팅이나 알림이 있는지 확인하려면 클라이언트가 서버에 반복해서 요청해야 한다.클라이언트: 새로운 메시지가 있나요?서버: 없습니다.클라이언트: 지금은 있나요?서버: 없습니다.클라이언트: 지금은요?서버: 있습니다.이 방식은 새로운 데이터가 없어도 요청을 계속 보내야 한다는 단점이 있다.WebSocket을 사용하면 클라이언트와 서버가 한 번 연결된 후 그 연결을 계속 유지한다.클라이언트 ↔ WebSocket 연결 유지 ↔ 서버연결된 상태에서는 클라이언트뿐만 아니라 서버도 원하는 시점에 메시지를 보낼 수 있다. 이처럼 양쪽이 자유롭게 데이터를 주고받는 방식을 양방향 전..

개발공부/WEB 2026.09.04

동시성 문제와 락: 비관적 락, 낙관적 락, 분산 락 이해하기

서비스에 사용자가 많아지면 여러 요청이 같은 데이터를 동시에 변경하는 상황이 발생한다.대표적인 예가 다음과 같다.동일한 계좌에서 동시에 출금한정된 상품의 재고 동시 차감포인트 동시 적립과 사용선착순 쿠폰 발급동일한 게시글을 여러 사용자가 동시에 수정이러한 상황에서는 단순히 데이터를 조회하고 수정하는 것만으로는 데이터의 정확성을 보장하기 어렵다.1. 동시성이란?동시성은 여러 요청이 같은 시간대에 동일한 데이터에 접근하는 상황을 의미한다.서버가 여러 대일 때만 발생하는 문제가 아니다. Spring Boot 서버가 한 대여도 여러 요청을 서로 다른 스레드에서 동시에 처리하기 때문에 동시성 문제는 발생할 수 있다.계좌 출금 예시계좌 잔액이 10,000원이고 두 요청이 동시에 1,000원씩 출금한다고 가정해 보자..

DB 인덱스 제대로 이해하기: B+Tree부터 복합 인덱스와 EXPLAIN까지

데이터가 적을 때는 인덱스의 효과를 체감하기 어렵다. 하지만 데이터가 수십만 건, 수백만 건으로 늘어나면 원하는 행을 찾기 위해 테이블 전체를 읽는 작업은 큰 비용이 된다.이때 필요한 것이 인덱스(Index)다.인덱스는 테이블에 새로운 칼럼을 추가하는 것이 아니라, 특정 칼럼의 값을 빠르게 찾기 위해 DB가 별도로 관리하는 탐색 자료구조다.1. 인덱스는 단순한 정렬표가 아니다MySQL의 InnoDB 인덱스는 일반적으로 B+Tree 계열 구조로 관리된다.인덱스는 컬럼 값을 정렬해서 보관할 뿐만 아니라, 트리의 분기를 따라 원하는 값이 있는 위치까지 빠르게 이동할 수 있게 한다. [50] / \ [20] [70] / \..

캐시는 왜 필요할까? Spring Cache와 Redis 제대로 이해하기

1. 캐시란 무엇인가?캐시는 자주 사용하는 데이터를 더 빠른 저장 공간에 임시로 보관하는 것이다.일반적인 데이터 조회 흐름은 다음과 같다.클라이언트 요청 ↓Spring Boot 서버 ↓데이터베이스 연결 ↓SQL 실행 ↓조회 결과 반환캐시를 적용하면 먼저 캐시에 데이터가 있는지 확인한다.클라이언트 요청 ↓캐시 조회 ├─ 데이터가 있음 → 캐시 데이터 반환 └─ 데이터가 없음 → DB 조회 → 캐시에 저장 → 결과 반환캐시에 데이터가 있는 경우를 Cache Hit, 없는 경우를 Cache Miss라고 한다.Cache Hit요청 → 캐시 조회 성공 → 바로 응답DB를 조회하지 않기 때문에 응답 속도가 빠르고 DB 부하도 줄어든다.Cache Miss요청 → 캐시에 데이터 없..

개발공부/Redis 2026.09.01

HandlerMethodArgumentResolver와 NativeWebRequest 이해하기

Spring의 컨트롤러를 작성하다 보면 메서드의 매개변수에 @RequestParam, @PathVariable, @RequestBody, HttpServletRequest, HttpSession 등을 선언하기만 해도 Spring이 알아서 값을 전달해준다.@GetMapping("/members/{id}")public MemberResponse getMember( @PathVariable Long id, @RequestParam String name, HttpServletRequest request) { // ...}개발자는 id, name, request 객체를 직접 생성하지 않았다. 그런데도 컨트롤러가 호출될 때는 각각의 값이 정상적으로 전달되는 이유는 Spri..

카테고리 없음 2026.08.05

코딩 테스트에서 중간값을 변수로 분리해야 하는 이유

들어가며코딩 테스트를 풀다 보면 식 자체는 거의 맞는데, 상태(State)를 끝까지 추적하는 능력이 부족해서 정답을 맞히지 못하는 경우가 있었다. https://school.programmers.co.kr/learn/courses/30/lessons/132267최근 콜라 문제를 풀면서도 비슷한 실수를 했다.처음에는 현재 가진 빈 병의 개수를 n이라고 두고, a개의 빈 병을 주면 b개의 콜라를 받을 수 있다는 조건을 다음과 같이 구현했다.answer += (n / a) * b;n = n / a + n % a;첫 번째 줄에서는 (n / a) * b를 이용해 새로 받은 콜라의 개수를 정확하게 계산했다. 하지만 다음 반복에서 사용할 빈 병의 개수를 갱신할 때는 n / a만 사용했다. 이때 n / a는 받은 콜라..

코딩테스트 2026.08.04

Spring Security에서 왜 Entity의 User가 아닌org.springframework.security.core.userdetails.User를 사용해야 할까?

Spring Security를 학습하면서 한 가지 의문이 생겼다.“어디에서는 내가 작성한 User를 가져다가 쓰고, 어디에서는 spring에서 제공하는 User를 써야하는 것일까?”나 역시 게시글 작성 기능을 구현하던 중 다음과 같은 오류를 만나면서 그 이유를 명확하게 이해하게 되었다.발생한 오류java.lang.NullPointerException: Cannot invoke "org.example.advance.common.entity.User.getUsername()" because "user" is nullat org.example.advance.domain.post.controller.PostController.createPost(PostController.java:24)처음에는 뭐가 문제인지 감..

🤦🏻‍♀️ 메서드가 몇 개 없는데도 공통 메서드를 분리해야 할까?

프로젝트를 진행하면서 Service 클래스 하나에 메서드가 4개 정도 있었다.각 메서드에서 동일한 로직이 반복되고 있었지만, 처음에는 굳이 private 공통 메서드로 분리하지 않았다.솔직히 메서드가 몇 개 되지도 않는데 오히려 메서드만 하나 더 늘어나는 것 같아 비효율적이라고 생각했기 때문이다.예를 들면 아래와 같은 코드였다.public CustomerResponse findCustomer(Long id) { Customer customer = customerRepository.findById(id) .orElseThrow(() -> new CustomException(...)); ...}public CustomerResponse updateCustomer(Long id,..

Git Cherry-pick이란? Staging Area에서 파일을 선택하는 것과 무엇이 다를까?

상황팀 프로젝트를 진행하면서 패키지 경로를 변경한 후 main 브랜치와 Merge하는 과정에서 충돌이 발생했다.충돌을 해결하는 방법을 찾아보던 중 Cherry-pick이라는 기능을 처음 접하게 되었다.설명을 읽어보니 “원하는 것만 가져온다.“는 점에서 문득 이런 의문이 들었다.“아직 커밋되지 않은 내 작업 공간(Workspace)에서 필요한 파일만 골라서 Staging Area에 올리는 것과 Cherry-pick은 무엇이 다를까?”처음에는 둘 다 “원하는 것만 선택한다.“는 공통점이 있기 때문에 비슷한 기능이라고 생각했다.하지만 공부해 보니 두 기능은 다루는 대상 자체가 완전히 달랐다.Staging Area는 ‘파일’을 선택하는 기능이다.우리가 가장 많이 사용하는 Git 명령어는 git add이다.git..

Spring Data JPA의 JpaSpecificationExecutor란? 동적 검색을 깔끔하게 구현하기

관리자 목록 조회 기능을 구현하면서 여러 검색 조건을 조합해야 하는 상황이 있었다.이름으로 검색이메일로 검색상태(PENDING, ACTIVE)로 검색이름 + 상태 검색이메일 + 상태 검색이름 + 이메일 + 상태 검색처럼 검색 조건이 계속 늘어났다.처음에는 Repository에 메서드를 하나씩 추가하면 되지 않을까 생각했다.findByName(String name)findByEmail(String email)findByStatus(AdminStatus status)findByNameAndStatus(String name, AdminStatus status)findByEmailAndStatus(String email, AdminStatus status)findByNameAndEmailAndStatus(.....

개발공부/JPA 2026.07.14