JPA 4

[N+1 삽질] 무조건 fetch join, @BatchSize가 정답은 아니다 (feat. 집계 쿼리 최적화)

필자는 현재 스마트폰 역경매 플랫폼 bidr(비더)를 개발 중이다. (5월 런칭 목표) bidr의 견적 목록 화면에는 각 견적마다 '입찰 5개·최저 8만원' 같은 정보가 표시된다. 구매자 입장에서 내 견적에 입찰이 얼마나 몰렸는지, 가장 저렴한 입찰가가 얼마인지 한눈에 볼 수 있어야 하기 때문이다. 그런데 이걸 구현하다가 전형적인 함정(?)을 밟았다. 문제 발견 — 견적 20개를 조회했는데 쿼리가 41번?처음 구현은, 견적 목록을 불러온 뒤 각 견적마다 입찰 수량 최저가를 개별로 조회하면 된다고 생각해서 아주 단순하게 구현했다. 그런데 기능 구현을 마치고 로컬에서 테스트하다가 콘솔을 무심코 봤는데 뭔가 이상했다. 견적 목록 조회 한 번에 로그가 너무 많이 찍히는 거였다..!Hibernate: selec..

Project/phonebid 2026.05.03

계약하기 버튼, 두 번 누르면 어떻게 될까 ㅡ 비관적 락 적용기

필자는 현재 스마트폰 역경매 플랫폼 bidr(비더)를 개발 중이다. (5월 런칭 목표) bidr에서 계약이 만들어지는 흐름은 이렇다. 구매자가 견적을 올리면 여러 판매자가 입찰을 넣고, 구매자가 마음에 드는 입찰을 선택하면 계약이 체결된다. 간단한 구조다. 문제 인식 — 이 패턴, 어디서 많이 봤는데과거에 이커머스 프로젝트 개발 중 재고 차감 기능을 구현한 적이 있다. 여러 사용자가 동시에 같은 상품을 주문할 때 재고가 0 아래로 내려가는 걸 막아야 하는 상황이었다. 그때 낙관적 락과 Redis 분산락을 직접 써보면서 동시성 문제를 어떻게 다루는지 익히게 되었다. 그 경험이 있어서인지, bidr에서 계약 생성 기능을 구현하다가 코드를 보는데 뭔가 익숙하고 찝찝한(?) 느낌이 드는것이었다..! '구매자가 ..

Project/phonebid 2026.04.29

[리팩토링] 알림 발송 로직을 동기에서 이벤트 기반 비동기로 개선하기 (feat. @TransactionalEventListener)

필자는 현재 스마트폰 역경매 플랫폼 bidr(비더)를 개발 중이다. (5월 런칭 목표) bidr는 구매자가 원하는 스마트폰 사양과 희망 가격 등의 견적을 올리면, 판매자들이 역으로 입찰을 넣는 구조다. 구매자 입장에선 여러 판매자의 견적을 한 번에 받아볼 수 있고, 판매자 입장에선 구매 의사가 확실한 고객에게 직접 제안할 수 있다. 이 구조에서 알림은 꽤 중요한 역할을 한다. 구매자가 견적을 등록하면 승인된 판매자 전원에게 카카오 알림톡으로 새 견적이 올라왔다는 알림이 발송되고, 구매자가 마음에 드는 입찰을 선택해 계약이 체결되면 구매자와 판매자 양쪽 모두에게 알림이 발송된다. 판매자가 빠르게 인지하고 입찰에 참여해야 서비스가 돌아가고, 계약 체결 순간에도 양쪽이 즉각적으로 인지해야 이후 결제와 배송 흐..

Project/phonebid 2026.04.23

[Spring/JPA] refresh token 통합 테스트 중 데이터 불일치 문제 삽질기 (@Modifying의 flushAutomatically 옵션)

1. 문제 상황: "분명히 지웠는데 왜 남아있지?"최근 진행 중인 사이드 프로젝트의 access, refresh token 인증 로직을 검증하기 위해 통합 테스트 코드를 작성하고 있었다. 로그인, 토큰 갱신, 로그아웃으로 이어지는 전체 플로우를 테스트하던 중, 로그아웃 시 DB에서 Refresh Token이 삭제되지 않는 문제가 생겼다.// 문제의 테스트 코드 일부@Test@DisplayName("로그아웃 -> RefreshToken 삭제 확인")void logout_ShouldDeleteRefreshToken() throws Exception { // 1. 로그인하여 토큰 생성 userService.login(loginRequest); // 2. 로그아웃 수행 (내부적으로 de..

Project/phonebid 2026.01.27