멱등성
"같은 요청을 여러 번 반복해도 결과는 한 번만 수행된 것과 같아야 한다."
PUT /products/123/stock
{
"stockQuantity": 10
}
- 이 요청은 몇 번을 보내든 stockQuantity는 항상 10으로 유지된다.
- 이처럼 같은 요청을 여러 번 보내도 시스템의 상태가 바뀌지 않으면 → 그 API는 멱등하다고 할 수 있다.
RESTful API에서 멱등성
- REST에서는 각 HTTP 메서드가 갖는 멱등성 여부를 명확하게 정의하고 있다.
- GET : 조회만 수행. 몇 번 요청해도 동일한 응답
- POST : 새로운 리소스 생성. 매번 다른 결과 발생
- PUT : 리소스를 "설정"함. 같은 데이터로 여러 번 보내도 결과 동일
- DELETE : 삭제는 여러 번 해도 동일한 상태 유지
=> 이 중에서도 특히 PUT 메서드는 멱등성의 대표적인 예라고 할 수 있다.
Patch?
- 실무에서는 보통 Patch를 사용하지 않고, 대신 Put 메서드를 Patch처럼 사용
- 수정하려는 내용만 받은 뒤, null이 아닌 경우만 업데이트하는 식으로 사용한다.
PUT 메서드에서 멱등성이 중요한 이유
재고 관리
PUT /products/123/stock
{
"stockQuantity": 6
}
- 이 요청을 몇 번 보내든 재고 수량은 바뀌지 않으며, 같은 상태를 유지한다.
→ 따라서 이 API는 멱등성을 지키는 API입니다.
- 이러한 특성은 요청이 중복되었을 때 서버의 상태가 꼬이지 않도록 보장해준다.
- 클라이언트가 타임아웃으로 재요청했는데,
- 서버가 두 번 처리하지 않고 한 번만 적용되도록 할 수 있음
- 예를 들어, 만약 재고 감소 처리를 현재 값에서 -1을 해주는 식으로 처리한다면,
request만 들어가고 response가 전달이 안 된 경우, 클라이언트가 request를 한 번 더 보냈을 때,
-1을 하라는 요청이 두 번 들어가 결과적으로 -2가 되는 경우가 발생한다.

=> 현재값 -1이 아닌, stockQuantity: 6 이렇게 멱등성을 지켜서 PUT 메서드를 사용하면 이런 일을 방지할 수 있다.
번외: 재고 관리에서 낙관적 락(Optimistic Lock)이 중요한 이유
- 재고 관리는 단순히 숫자만 변경하는 작업이 아니기 때문에,
판매자 측 재고 수정 요청과 실제 구매 요청이 동시에 발생할 수 있는 경쟁 상황이 자주 발생한다.

=> 이런 일을 방지하기 위해, 낙관적 락(Optimistic Lock)을 활용할 수 있다!
낙관적 락이란?
- 각 재고 데이터에 version 값을 함께 저장하고, 클라이언트는 수정 요청 시 version도 함께 전달!
- 서버는 version이 일치할 때만 업데이트를 수행하고, 누군가 먼저 수정한 경우에는 409 Conflict 오류를 반환.
PUT /products/123/stock
{
"stockQuantity": 6,
"version": 1
}
충돌 응답:
{
"status": 409,
"message": "다른 사용자가 이미 이 상품을 수정했습니다.",
"currentVersion": 2
}
-
낙관적 락을 통해 클라이언트는 최신 데이터를 다시 받아와 재시도할 수 있고,
중요한 재고 변경 로직의 정합성과 안정성을 유지할 수 있다.

-
오른쪽이 먼저 실행되어, 재고의 버전이 V2로 바뀌었다면, 왼쪽에서는 conflict가 일어남
-
그럼 다시 최신 V2값을 가져와서 그걸 기준으로 다시 재고 업데이트!
(Version의 경우 어차피 하나만 허용하므로 멱등성을 지키지 않고 +1해줘도 됨)
-
클라이언트 쪽에서는 250개에서 20개를 살거니까, 재고의 최신값을 서버에서 불러와서 -20을 해서 230을 요청으로 보내주는 것 (-20을 요청하는게 아닌, 230개를 요청!)
비관적 락 vs 비관적 락**
비관적 락 (Pessimistic Lock)
- “이거 충돌 날 수도 있으니까, 아예 막아놓고 나 혼자 쓸게.”
- 리소스를 사용하는 동안 다른 트랜잭션이 접근하지 못하게 막음
- DB 수준에서는 SELECT ... FOR UPDATE 같은 방식으로 구현
- 특징
- 충돌(데이터 경합)이 자주 발생하는 환경에 적합
- 동시성은 떨어지지만, 데이터 무결성은 확실하게 보장
- 병목이나 대기시간이 생길 수 있음 (줄 세우기 방식)
낙관적 락 (Optimistic Lock)
- “충돌은 잘 안 날 거야. 일단 처리하고, 나중에 검증하자.”
- 트랜잭션을 마치기 직전에 버전 검사 등을 통해 충돌을 감지
- 보통 version 필드를 통해 동시성 제어
- 특징
- 충돌이 드물게 발생하는 환경에 적합
- 락을 걸지 않아서 성능은 좋지만, 충돌 시 재시도 필요
- 실무에서는 JPA @Version 등으로 사용
결론
- 충돌 가능성이 높다면 → 비관적 락
- 충돌 가능성이 낮다면 → 낙관적 락
→ 트래픽/동시성/업데이트 빈도 등을 고려해 선택해야 함!