본문 바로가기

spring7

포인트는 왜 안 쌓였을까 — @TransactionalEventListener 함정 파헤치기 들어가며주문 서비스를 개발하면서 이런 코드를 마주치거나 직접 작성한 경험이 있을 것이다.@TransactionalEventListener(phase = AFTER_COMMIT)void onOrderCreated(OrderCreatedEvent event) { pointRepository.save(new Point(event.userId(), event.amount()));} 커밋이 끝난 뒤에 포인트를 적립한다. 트랜잭션이 성공했을 때만 실행되니까 언뜻 완벽해 보인다. 정말 그런지 테스트로 확인해봤다 @Test void AFTER_COMMIT_시점에_Spring_TX_플래그는_아직_true지만_JPA_세션은_이미_커밋됐다() { orderService.createOrder("user-tx.. 2026. 3. 27.
[Java / Spring Boot] 브랜드에서 전화가 왔다, "우리 상품 좋아요가 한번에 수십개씩 빠져요!" - 5편 좋아요 카운트 로직을 짜다가 문제를 발견했다."약간의 오차는 괜찮다"고 판단하고 비동기로 처리했는데, 코드를 들여다보니 수십 개씩 틀어질 수 있는 구조였다.실제로 운영 중에 이런 상황이 생기면 어떻게 될까? 가상의 브랜드 담당자에게 "좋아요 수가 갑자기 수십 개씩 줄었다가 돌아와요"라는 연락을 받는다고 상상해보자. 처음엔 식은땀이 날 것 같다. "약간의 오차는 괜찮다"고 했는데, "약간의 오차"와 "수십 개씩 튀는 것"은 달랐다.원인을 찾아보자.정규화 vs 비정규화좋아요 수를 보여주는 가장 자연스러운 방법은 이거다.SELECT COUNT(*) FROM likes WHERE product_id = 1이게 정규화 방식이다. 데이터를 중복 없이 한 곳에만 저장하고, 필요할 때 계산한다.정규화:장점 → 데이터 .. 2026. 3. 6.
[Java / Spring Boot] 쿠폰 사용에 대한 처리는 어떤 락이 적절할까 - 4편 3편 마지막에 이런 질문을 던졌다.(3편: 비관적 락 vs 낙관적 락, 선택 기준은 무엇이었나 - 3편)유니크 키는 어디에 쓰는 걸까?쿠폰 로직을 구현하면서 답을 찾았다.재고 vs 쿠폰: 충돌 패턴이 다르다재고는 여러 사람이 하나를 두고 경쟁하는 문제다. 쿠폰은 다르다.재고 차감: 불특정 다수가 동시에 같은 상품에 달려듦쿠폰 발급: 동일 사용자의 중복 요청이 문제쿠폰 사용: 같은 쿠폰으로 동시에 두 번 주문 시도충돌 주체가 다르니까 전략도 달라야 한다.쿠폰 중복 발급: DB 유니크 키로 막는다애플리케이션 코드에서 이렇게 체크하면 충분할 것 같다.@Transactionalpublic void issue(Long userId, Long couponId) { boolean exists = us.. 2026. 3. 6.
[Java / Spring Boot] 비관적 락 vs 낙관적 락, 선택 기준은 무엇이었나 - 3편 2편에서 재고 차감에 비관적 락을 적용했다. 그런데 모든 상황에 비관적 락이 정답은 아니다.(2편: 스투시 반팔티를 10명이 동시에 주문했을 때 발생한 일-2편 )비관적 락은 하나씩 순차 처리라 병목현상이 생기고, 데드락 위험도 있다.충돌이 거의 없는 상황에서도 락을 걸면 비용만 크고 얻는 게 없는 상황이 된다.충돌 빈도가 다르다재고 차감: 불특정 다수가 동시에 같은 상품에 달려듦 → 충돌 빈도 높음게시글 수정: 보통 작성자 혼자 수정 → 충돌 빈도 낮음게시글 수정에 비관적 락을 걸면 어떻게 될까?작성자가 수정 버튼 클릭→ SELECT FOR UPDATE (배타 락 획득)→ 수정 폼에서 내용 입력 중... (30초)→ 저장 클릭 → 커밋 → 락 해제이 30초 동안 배타 락이 걸려있다. 다른 사람들은 .. 2026. 3. 6.
반응형