Tag: Spring
이 태그가 달린 글들 "Spring"
-
@Transactional(readOnly = true) 한 줄이 응답시간을 132배 줄인 이야기 — JPA Dirty Checking 의 정체 해부
Updated:JPA dirty checking 비용을 1만 row UPDATE 6 시나리오로 분해. 비교의 *기준* 을 분리해서 읽어야 한다 — S1(일반) vs S2(readOnly SELECT) ≈ 132× 는 *readOnly 가 빠진 메서드가 부담하는 비용*, S4(@DynamicUpdate) vs S6(raw JDBC) ≈ 68× 는 *@DynamicUpdate 만으로는 dirty checking dominant 비용을 못 줄인다* 는 의미, S4 vs S5(bulk JPQL) ≈ 50× 는 *모델 자체를 dirty checking 에서 bulk 로 바꿨을 때* 효과, S5 vs S6 ≈ 1.32× 는 JPA 추상화 오버헤드 30% 수준. @DynamicUpdate 는 변경 컬럼 조합마다 SQL string 이 달라져 batch_update 효과를 약화시킬 수 있고 Query Plan Cache 압박을 일으킬 수 있어 *국지적 도구*. loadedState / FlushMode MANUAL / SPR-16956 / bytecode enhancement 까지 Hibernate 6 내부 구조와 함께, 단정 표현은 톤다운한 결론으로 정리한 v2 [실측 — Java/Spring Stage 2, EXP-13].
-
JPA 낙관락 + retry stampede 의 함정 — @Version 만으론 부족한 6 시나리오
100 worker 가 같은 룰의 priority 를 +1 합니다. @Version 없으면 priority < 100 (Lost Update). @Version 적용하면 OptimisticLockException 만 던지고 처리는 호출자 책임 — 일부만 성공. @Retryable(3) 백오프 0 으로 retry 면 **동시에 retry 가 몰려서** 다시 충돌 (retry stampede). exponential + full jitter 가 retry 를 분산시켜 priority=100 도달. 그리고 측정 도중 만난 자기 Lost Update — 같은 트랜잭션 안에서 SELECT 두 번이 다른 객체 (JDBC) vs 같은 인스턴스 (JPA 1차 캐시 ==). 분산 환경 Lost Update 와는 완전히 별개의 함정. @Transactional + @Retryable AOP 순서, exponential backoff + jitter 의 이론적 근거 (AWS Architecture Blog) 까지 풀었습니다.
-
[JPA + Spring Mastery 08] 트랜잭션 분리 패턴 — Saga / Outbox / REQUIRES_NEW, 학술 기원부터 EXP-09b 9 시나리오 실측까지
트랜잭션 안에서 외부 API 호출하지 마라 - 격언은 들어봤지만 어떻게 풀어야 하는지는 잘 다뤄지지 않습니다. 본 글은 PROPAGATION 7종의 정확한 의미부터 2PC (XA) 의 한계, Garcia-Molina 의 1987년 Sagas 논문, Pat Helland 의 CIDR 2005 Data on the Outside, Vogels 의 ACM Queue 2008 Eventually Consistent 까지 학술 기원을 짚고, 토스 SLASH24 SAGA, 29CM/리디 Outbox 한국 운영 사례를 거쳐, EXP-09b 9 시나리오 실측 매트릭스 - 패턴 A/B/C × OFF/DB_FAIL/EXT_FAIL - 로 검증한 기록입니다. 결제 도메인은 Saga, 알림은 Outbox, 캐시류만 단순 분리 - 이 매핑의 학술 + 운영 + 실측 3박자.
-
MySQL 크레딧 차감 락 4종 비교 — 비관락 180ms / 100% 정확, 그리고 측정 도중 발견한 self-invocation 함정
잔액 100 인 계정에서 100 worker 가 동시에 1씩 차감하는 흔한 시나리오. 4 락 (낙관/비관/MySQL GET_LOCK/Redisson) 의 결과가 모두 다릅니다 — 비관락 180ms / 100% / 잔액 0, 낙관락 549ms (contention 시 재시도 폭증), GET_LOCK 5015ms (advisory lock 의 cost), Redisson 53/100 (단일 인스턴스 한계). 그리고 측정 도중 발견한 self-invocation 함정 — successes=100 인데 잔액 그대로 유지된 case. JPA / Spring 의 진짜 함정은 logic 이 아니라 AOP proxy 우회였습니다. GET_LOCK 의 connection-bound 함정 4 시나리오까지 직접 시연한 기록.