java 39

[Spring Plus] DTO Projection으로 N+1 문제 해결하기

상황CommentController 클래스의 getComments() API를 호출할 때 N+1 문제가 발생하고 있어요. N+1 문제란, 데이터베이스 쿼리 성능 저하를 일으키는 대표적인 문제 중 하나로, 특히 연관된 엔티티를 조회할 때 발생해요.해당 문제가 발생하지 않도록 코드를 수정해주세요. N+1 로그 원인 분석우선 Comment와 User와의 관계를 알아보기 위해 Comment 엔티티를 확인해보자.Comment 엔티티의 정의를 보니 Comment와 User는 N:1 관계, 즉 한 명의 user가 여러 comment를 가질 수 있는 구조이다.그리고 CommentRepository에서 N+1을 발생시키는 메서드를 확인해보자.getComments() 메서드 실행 시 날아가는 JPQL은 일반 JOIN을 사..

[Spring Plus] JPA Cascade 옵션 지정하기

상황할 일을 새로 저장할 시, 할 일을 생성한 유저는 담당자로 자동 등록되어야 합니다.JPA의 cascade 기능을 활용해 할 일을 생성한 유저가 담당자로 등록될 수 있게 해주세요.해결 방법하나의 할일은 여러 담당자를 가진다(리스트 형태). 따라서 할일이 생성될 때 할일을 생성한 사용자는 managers라는 list에 add 되어야 한다. 할 일이 생성될 때만 유저를 담당자 리스트에 넣어주면 되므로, @OneToMany의 Cascade 옵션을 Cascade = Cascade.PERSIST로 지정해주자. 속성 값설명Cascade.ALL모든 변경(저장, 병합, 삭제, 재로딩)이 관련 엔티티에 적용됩니다. Cascade.DETACH엔티티가 detach 상태로 변경될 때, 관련 엔티티도 함께 변경됩니다. Ca..

[Spring Plus] AOP의 동작 흐름 제어하기

상황AOP가 잘못 동작하고 있어요!UserAdminController 클래스의 changeUserRole() 메소드가 실행 전 동작해야해요.AdminAccessLoggingAspect 클래스에 있는 AOP가 개발 의도에 맞도록 코드를 수정해주세요. 원인 분석1. AOP 기능을 구현하기 위한 의존성이 있는지 확인한다.없으면 추가해 준다. 2. AOP 어노테이션이 After로 설정되어 있어 changeUserRole 메서드가 UserController.getUser()이라는 JoinPoint의 실행 전이 아니라 실행 후 동작한다.해결 방법해당 Aspect의 @After 어노테이션을 @Before 어노테이션으로 바꿔준다. 잘 적용되었는지 확인해 보자.UserController.getUser() 메서드를 호출하..

[Spring Plus] 컨트롤러 테스트 성공시키기

상황테스트 패키지 org.example.expert.domain.todo.controller의 todo_단건_조회_시_todo가_존재하지_않아_예외가_발생한다() 테스트가 실패하고 있다. 원인 분석then 절에 Breaking Point를 다 찍어보자.MockMvc란 스프링 프레임워크에서 제공하는 웹 애플리케이션 테스트용 라이브러리를 의미한다. 웹 애플리케이션의 다양한 컴포넌트를 테스트하기 위해 사용한다.(출처: https://adjh54.tistory.com/347).andExpect(status().isOk()) 부분에서 에러가 터졌다. 테스트 코드에서는 200을 예상했지만 실제로는 400이 확인됐다. 존재하지 않는 데이터를 잘못 호출한 사용자발 에러이므로 400대 에러가 발생하는 게 정상인데, 이 ..

[Spring Plus] JWT 인증 필드 추가

상황문제 요약기획자의 긴급 요청이 왔어요! 아래의 요구사항에 맞춰 기획 요건에 대응할 수 있는 코드를 작성해주세요.User의 정보에 nickname이 필요해졌어요.User 테이블에 nickname 컬럼을 추가해주세요.nickname은 중복 가능합니다.프론트엔드 개발자가 JWT에서 유저의 닉네임을 꺼내 화면에 보여주길 원하고 있어요. 해결 방법 요약User 컬럼명에 nickname 필드 추가.생성자, dto를 비롯, 유저 정보를 활용하여 토큰을 생성 및 검증하는 모든 코드에 nickname 필드를 추가 해결 방법 상세 nickname 필드 추가, 생성자 및 static 함수에 파라미터로 추가 AuthUser.java에서 시그니처 변경 AuthService.java에서 토큰 생성 시 nickname을 넣어주..

[Spring Plus] Troubleshooting - @Transactional

문제 요약/todos API 호출 시 jakarta.servlet.ServletException 발생 문제 상세에러 로그 원문jakarta.servlet.ServletException: Request processing failed: org.springframework.orm.jpa.JpaSystemException: could not execute statement [Connection is read-only. Queries leading to data modification are not allowed] [insert into todos (contents,created_at,modified_at,title,user_id,weather) values (?,?,?,?,?,?)] 문제 원인 추정 Conne..

[Spring AI] LLM, call(), stream(), 모델의 확률성

1. LLM과 호출 방법LLM 객체란, 모델과의 통신 방식을 추상화한 클래스이다. LLM 객체를 호출하는 메서드는 call(), stream() 두 가지가 있다. 2. Call()call()은 짧은 응답이나 배치 처리에 적합하다. 사용자는 대기 후 답변을 한 번에 받을 수 있다. 응답을 db에 저장할 때, 응답 결과로 다음 로직을 실행할 때(스텝 백 프롬프트)에도 call()이 유리하다. 3. Stream()stream()은 응답을 기다리지 않고 생성되는 즉시 수신한다. 때문에 실시간으로 타이핑되듯 표시된다.실시간 채팅이나 긴 응답인 경우 적합하다. 이때 응답은 청크 단위로 반환한다. 실제로 call()은 stream()을 내부에서 사용하고 모든 chunk를 모아서 반환하는 방식으로 구현되는 경우가 많다..

Spring 2026.02.26

[Spring] Java와 Redis를 연결해주는 RedisTemplate

Redis 학습 정리1장 - Redis, RedisTemplateRedis는 메모리 기반의 빠른 DB이다.Java 기반 Spring Boot 프로젝트에서 Redis를 사용하기 위해선, Java와 Redis를 연결해주는 역할이 필요하다.이를 수행해주는 것이 RedisTemplate이다.RedisTemplate은 Java와 Redis 사이의 변환기라고 할 수 있다.Java 명령어를 Redis 명령어로 상호 변환하여 통신을 가능케 한다.2장 - Redis의 데이터 저장 방식과 직렬화 도구저장 방식Redis는 모든 데이터를 key-value 형태로 저장한다.이때 데이터 타입은 전부 문자열로 저장된다.직렬화 (Java → Redis)Java 객체를 Redis에 저장하기 위해서는 문자열 형태로 파싱해주는 작업이 필..

Spring 2026.02.26