본문 바로가기

springboot314

스케줄러가 멈췄어요! 스프링 @Scheduled 단일 스레드 병목 원인과 ThreadPool 완벽 해결법 안녕하세요, 여러분의 든든한 IT 길잡이 데브프리입니다. 백엔드 서버를 운영하다 보면 특정 시간에 자동으로 실행되어야 하는 배치(Batch) 작업이나 알림 기능이 필수적으로 요구됩니다. 스프링 부트(Spring Boot)에서는 이를 위해 메서드 위에 @Scheduled(cron = "...") 어노테이션 하나만 툭 얹어주면 마법처럼 타이머가 작동하는 아주 편리한 기능을 제공합니다. 하지만 개발 서버에서는 한 치의 오차도 없이 잘 돌던 스케줄러가, 실서버에 배포하고 데이터가 쌓이기 시작하면 갑자기 이상하게 동작하곤 합니다. 아침 9시에 정확히 발송되어야 할 '출근 알림' 메시지가 9시 10분에 발송되거나, 아예 실행조차 되지 않고 서버가 조용히 침묵하는 무시무시한 현상이 발생하죠. 콘솔을 확인해 봐도 빨간.. 2026. 8. 16.
N+1 잡으려다 서버가 터졌다? JPA MultipleBagFetchException 원인과 실무 최적화 가이드 안녕하세요, 여러분의 든든한 IT 길잡이 데브프리입니다. 스프링 부트(Spring Boot)로 게시판이나 쇼핑몰을 만들 때, 백엔드 개발자라면 누구나 한 번쯤 'N+1 문제'라는 거대한 벽에 부딪힙니다. 게시글(Post)을 조회할 때 딸려있는 댓글(Comments) 때문에 수십 개의 추가 쿼리가 발생하는 현상이죠. 우리는 이를 해결하기 위해 자랑스럽게 JOIN FETCH를 도입합니다. "좋아, 쿼리가 1개로 줄었군! 그럼 게시글을 가져올 때 '댓글'이랑 '첨부파일(Files)' 컬렉션 2개를 한꺼번에 Fetch Join으로 가져오면 성능이 2배로 좋아지겠지?" 그리고 기대에 부풀어 서버를 실행하는 순간, 앱이 켜지기도 전에 아래와 같은 시뻘건 런타임 에러가 콘솔 창을 뒤덮습니다.Plaintextorg.h.. 2026. 8. 15.
@Transactional을 붙였는데 롤백이 안 된다고요? 스프링 AOP 프록시 내부 호출(Self-Invocation)의 함정 안녕하세요, 여러분의 든든한 IT 길잡이 데브프리입니다. 스프링 부트(Spring Boot)로 백엔드를 개발하다 보면 특정 로직이 실패했을 때 데이터베이스를 이전 상태로 되돌리기 위해 @Transactional 어노테이션을 숨 쉬듯이 사용하게 됩니다. 그런데 개발 서버에서 테스트를 하던 중 등골이 서늘해지는 상황을 마주할 때가 있습니다. 명백하게 데이터베이스 저장 도중 런타임 예외(RuntimeException)가 발생해서 에러 로그가 시뻘겋게 찍혔는데, DB를 확인해 보니 데이터가 롤백(Rollback)되지 않고 버젓이 저장되어 있는 기현상입니다. "어? 분명히 메서드 위에 @Transactional을 예쁘게 붙여놨는데 왜 롤백이 안 된 거지?" 오늘은 실무에서 백엔드 개발자들이 가장 많이 당하는 함정.. 2026. 8. 14.
예외 처리(try-catch)를 했는데 왜 롤백될까? UnexpectedRollbackException 완벽 해결법 안녕하세요, 여러분의 든든한 IT 길잡이 데브프리입니다. 스프링 부트(Spring Boot)로 백엔드 비즈니스 로직을 짜다 보면 이런 요구사항을 흔히 마주합니다. "고객이 주문을 완료하면 핵심 데이터(주문 정보)는 무조건 DB에 저장되어야 하고, 부가적인 데이터(주문 이력 로그) 저장에 실패하더라도 메인 주문은 절대 취소(롤백)되면 안 됩니다!" 이 요구사항을 구현하기 위해 백엔드 개발자들은 아주 자연스럽게 이력 저장 로직을 try-catch 문으로 감싸서 에러를 무시하도록 코드를 작성합니다. 하지만 실서버에 배포하고 로그 저장이 실패하는 순간, 잡았다고 생각했던 에러는 온데간데없고 뜬금없이 아래와 같은 시뻘건 에러가 터지며 주문까지 통째로 롤백(Rollback)되어 버립니다.Javaorg.springf.. 2026. 8. 13.
로그인 성공했는데 403 에러? 스프링 시큐리티 6 (Spring Boot 3) CSRF와 /error 3분 해결법 안녕하세요, 여러분의 든든한 IT 길잡이 데브프리입니다. 스프링 부트(Spring Boot) 3.x 버전으로 프로젝트를 세팅하고 JWT(JSON Web Token) 기반의 로그인을 멋지게 구현했습니다. 포스트맨(Postman)으로 로그인 API를 찔러보니 200 OK와 함께 토큰이 예쁘게 발급되네요. "좋아, 인증은 완벽해!"라고 생각하며 발급받은 토큰을 헤더에 넣고 게시글 작성(POST) API를 호출해 봅니다. 그런데 웬걸, 화면에 시뻘건 403 Forbidden 에러가 튀어나옵니다. 분명히 인증(Authentication)을 통과했는데, 서버는 왜 저의 접근을 단호하게 거부하는 걸까요? 스프링 시큐리티(Spring Security) 6.x 버전으로 넘어오면서 기본 보안 정책이 훨씬 엄격해졌습니다.오.. 2026. 8. 12.
"따닥!" 두 번 결제되는 버그 막기: API 멱등성(Idempotency) 완벽 가이드와 Redis 분산 제어 안녕하세요, 여러분의 든든한 IT 길잡이 데브프리입니다. 스마트폰으로 쇼핑몰에서 결제를 하거나, 커뮤니티에 게시글을 등록할 때 네트워크가 살짝 느려져 화면이 멈춘 적 있으신가요? 답답한 마음에 '결제하기' 버튼을 "따닥!" 하고 두세 번 연속으로 누르는 사용자는 실무에서 생각보다 정말 많습니다. 프론트엔드에서 자바스크립트로 버튼을 비활성화(Disable) 처리해두었다고요? 아쉽게도 그것만으로는 부족합니다. 악의적인 매크로 봇이나, 모바일 네트워크 불안정으로 인해 재전송(Retry)된 패킷은 언제든 백엔드 서버로 동시에 밀고 들어올 수 있습니다. 아무런 방어 로직이 없는 서버는 결국 고객의 신용카드에서 똑같은 금액을 두 번 결제해 버리는 최악의 사고를 터뜨리고 맙니다. 오늘은 이렇게 중복으로 들어오는 트래.. 2026. 8. 11.