--- kind: CONCEPT slug: messaging-outbox-jdbc-postgresql-c05 title: 동시성 제어가 전부 데이터베이스에 있다 topic: state-machines-and-ownership project: clean-architecture-backend-template status: 게시 전 sourceRevision: 21234e38cdb9a926cbc92bb97a2aee2e4a7d2916 rootTreeNode: concept:messaging-outbox-jdbc-postgresql-c05 evidenceCapturedOn: 2026-09-01 assets: - key: messaging-outbox-jdbc-postgresql-c05 file: ../../../final/evidence/rendered/messaging-outbox-jdbc-postgresql-c05.svg - key: messaging-outbox-jdbc-postgresql-c05-diagram file: ../../../final/assets/diagrams/messaging-outbox-jdbc-postgresql-c05.svg evidence: - ../../../final/evidence/raw/messaging-outbox-jdbc-postgresql-c05.txt source: - 원본 분석 절은 final/document.md#a19-messaging-outbox-jdbc-postgresql#L486 이다. module: messaging-outbox-jdbc-postgresql --- # 동시성 제어가 전부 데이터베이스에 있다 두 가지 커넥션 획득 방식이 공존하고, Java 쪽에는 락이 없다. ## 본문 **두 가지 커넥션 획득 방식이 공존한다.** ## 커넥션을 얻는 두 방식 :::evidence key="messaging-outbox-jdbc-postgresql-c05-diagram" alt="커넥션 획득에서 릴레이와 저널 두 상자로 화살표가 나가고 화살표에 독립 커넥션과 호출자 트랜잭션이 붙은 구조" caption="커넥션을 얻는 두 방식" zoom="false" ::: 릴레이 연산이 비즈니스 트랜잭션에 합류하면 안 되므로 `withConnection` 의 선택은 타당하다. 다만 그 판단이 주석으로 남아 있지 않고, 같은 리프의 저널은 반대 방식을 쓴다. §17 P3. ## OutboxRelayWorker 참조 위치 :::evidence key="messaging-outbox-jdbc-postgresql-c05" alt="코드베이스에서 OutboxRelayWorker 를 검색한 출력 17줄. 이 기록이 세는 참조가 그 출력에 그대로 보인다." caption="OutboxRelayWorker 코드베이스 검색 — 17줄 · exit 0" zoom="true" ::: ## 동시성 원시 요소가 전부 DB에 있다 `FOR UPDATE SKIP LOCKED`(청구), 서버측 토큰 증가, 펜싱 술어, `ON CONFLICT DO NOTHING`, 복합 기본키. Java 쪽에 락이 없다. ## 수명주기 `OutboxRelayWorker` 는 데몬 스레드 1개, `setExecuteExistingDelayedTasksAfterShutdownPolicy(false)`, `start()` 멱등, `stop(deadline)` 드레인 후 실패 시 `shutdownNow()`. 셋 다 근거 주석이 있다(`:79-88`, `:92`, `:121-122`).