Files
document-haness/docs/clean-architecture-backend-template/tech-log-studio/owner-safe-state-machines/case/case-native-claim-did-not-bump-the-version.md
T
DongHyeonkaandClaude Fable 5.1 b25357c48a docs(clean-architecture-backend-template): fold analysis into final and re-select one topic
- analysis/·source-index·state.json 을 final/document.md 제2부·제3부로 접었다. SSOT 는 하나다
- 파일럿 — commit-ambiguity-as-a-result 를 새 기준으로 재선별. 후보 14 → 글감 5
  (PROMOTE 5 · MERGE_INTO 3 · KEEP_IN_SSOT 4 · 보류 2). 기록 5건을 다시 썼고 그림 1개를
  techviz 로 만들었다
- 재선별이 잡은 것: 제1부 §6.2·§11.1 이 자기 §13.2 와 어긋나 있었다(레인을 안 돌렸다 vs
  돌렸다) — 정정. 이미 답이 나와 있던 Question 을 HEAD 재실행 질문으로 다시 세웠다.
  Concept 이 인용한 코드가 SSOT 에 없어 뺐다
- candidateScope·sourceRepository 기록. 나머지 43개 주제는 재선별 대기(PENDING 905)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 12:39:20 +09:00

4.1 KiB

kind, slug, title, topic, project, status, sourceRevision, rootTreeNode, evidenceCapturedOn, assets, evidence, source
kind slug title topic project status sourceRevision rootTreeNode evidenceCapturedOn assets evidence source
CASE native-claim-did-not-bump-the-version native claim이 @Version을 올리지 않아 충돌을 보고하지 않는 낙관적 잠금이 됐다 owner-safe-state-machines clean-architecture-backend-template 게시 전 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 case:native-claim-did-not-bump-the-version 2026-09-01
key file
native-claim-did-not-bump-the-version ../../../final/evidence/rendered/native-claim-did-not-bump-the-version.svg
../../../final/evidence/raw/native-claim-did-not-bump-the-version.txt
원본 분석 절은 final/document.md#4-1 · final/document.md#a05 §11.2 이다.

native claim이 @Version을 올리지 않아 충돌을 보고하지 않는 낙관적 잠금이 됐다

네이티브 SQL 로 청구하면서 JPA 버전 컬럼을 올리지 않았다. 청구 전에 로드된 관리 엔티티가 옛 버전을 그대로 들고 있어서, 그 플러시가 성공하면서 리스와 상태를 청구 이전 값으로 덮었다.

관계

  • CAS 튜플과 update count가 답이 되는 구조 네이티브 청구가 쓰는 구조다.
  • Atomic 타입의 존재는 원자성의 증거가 아니다 잠금 장치가 있다는 것과 그것이 충돌을 보고한다는 것이 다르다는 점에서 같은 계열이다.

문제

수신자 전달 청구는 네이티브 SQL 로 이뤄진다. 리스 소유자와 리스 만료와 펜스를 설정하고 상태를 전달 중으로 바꾼다.

같은 테이블에 JPA 엔티티가 매핑되어 있고 그 엔티티에는 버전 컬럼이 있다.

결론

네이티브 문장이 버전 컬럼을 함께 올리지 않으면 낙관적 잠금이 무력해진다.

문장 안의 주석이 그 이유를 정확히 적는다. 이것이 JPA 의 버전 컬럼이고 네이티브 쓰기가 그것을 전진시킨다는 것이다. 이것이 없으면 청구 전에 로드된 관리 엔티티가 여전히 옛 버전을 들고 있고, 그 플러시가 성공하면서 리스와 상태를 청구 이전 값으로 덮는다. 충돌이 없다고 보고하는 낙관적 잠금이 되는 것이다.

문제의 성격이 특이하다. 낙관적 잠금은 있고 동작하며 예외를 던지지 않는다. 던지지 않는 이유가 네이티브 문장이 버전이 바뀌었다고 알려 주지 않았기 때문이다.

그래서 증상은 잠금 실패가 아니라 조용한 덮어쓰기다. 청구가 성공했고 다른 트랜잭션의 플러시가 그것을 되돌린다.

수정은 네이티브 문장의 SET 절에 버전 증가를 넣는 것이다. 같은 문장이 펜스도 함께 올린다.

검증 환경

OpenJDK : 21.0.12 데이터베이스 : PostgreSQL 확인 방식 : 문장과 그 주석 확인 소스 수정 : x

재현 조건

  1. 수신자 청구 SQL 의 SET 절을 읽는다.
  2. 버전 컬럼 증가 줄과 그 위 주석을 확인한다.
  3. 같은 문장이 펜스를 올리는지 확인한다.
  4. 같은 테이블에 매핑된 엔티티의 버전 컬럼을 확인한다.

본문

claim이 native UPDATE인데 JPA @Version 컬럼을 올리지 않으면, claim 전에 로드된 managed 엔티티가 여전히 옛 version을 들고 있다.

native UPDATE 와 managed 엔티티

:::evidence key="native-claim-did-not-bump-the-version" alt="분석 문서 final/document.md 에서 이 기록의 근거 절을 그대로 잘라낸 18줄. 코드베이스를 측정한 것이 아니라 원본 판정이 무엇을 적었는지를 보여 준다." caption="final/document.md 발췌 — 18줄" zoom="true" :::

충돌을 보고하지 않는 낙관적 잠금이 된다

그 flush가 성공하면서 lease와 state를 pre-claim 값으로 덮어쓴다. native statement가 충돌이 있었다고 말해주지 않았기 때문이다.

수정은 한 줄이고 주석이 붙어 있다

statement에 version = d.version + 1을 넣는다.

확인하지 못한 것

청구 전에 로드한 엔티티를 플러시해 덮어쓰기를 재현하지 않았다. 이 기록은 문장과 그 주석에 근거한다.

컨테이너 레인 미실행