작성
·
17
·
수정됨
0
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요!
- 먼저 유사한 질문이 있었는지 검색해보세요.
- 서로 예의를 지키며 존중하는 문화를 만들어가요.
- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.
final Stock stock = stockRepository.getByProductId(productId);
stock.decrease(quantity);
stockRepository.save(stock)
public void decrease(final Long quantity) {
if (this.quantity - quantity < 0) {
throw new RuntimeException("재고 부족");
}
this.quantity -= quantity;
}
락을 건 이유는 decrease 로직에서 quantity를 줄이고 다시 저장했기 때문이라 생각했습니다. stock 상태가 코드레벨에서 변하기 때문에 발생하기 때문입니다.
다만 코드레벨에서 변경하지 않고 디비에서 직접 변경한다면(update stock quantity=quantity-1 과 같이) update 자체가 배타락이기 때문에 굳이 락을 걸지 않아도 된다고 판단하였습니다.
그래서 단일 연산으로 해결할 수 없는 상황은 quantity 필드 뿐만 아니라 다른 필드에도 영향이 미칠 때라 생각했습니다. stock 필드에 soft delete 필드 delYn을 추가하고,
코드 상에서 만약 재고가 0이면 delYn=True 로 바꾼다 이런 경우일 것 같은데 제가 생각한게 맞을까요?
단일 연산으로도 정합성을 유지할 수 있는데 왜 stock을 다시 저장하는지 모르겠습니다
답변 1
0
안녕하세요, 인프런 AI 인턴입니다.
gelab님께서 말씀하신 것처럼, 데이터베이스의 UPDATE
문을 사용하여 단일 연산을 수행하면, 데이터베이스 레벨에서 락을 걸어주기 때문에 동시성 문제를 부분적으로 해결할 수 있습니다. 이는 데이터를 직접적으로 조작하여 트랜잭션의 격리를 통해 동시성을 관리하는 방식입니다.
실제로 UPDATE stock SET quantity = quantity - :quantity WHERE product_id = :productId
와 같은 쿼리는 데이터베이스에서의 단일 연산으로, 다수의 트랜잭션이 동시에 같은 데이터를 업데이트 하려고 할 때 자동으로 잠금을 이용하여 동시성 문제를 방지합니다.
하지만, 단일 쿼리가 아닌 경우, 예를 들어 여러 필드의 변경이 필요하거나, 비즈니스 로직이 복잡한 경우, 트랜잭션의 일관성을 위해 객체 상태를 영속 컨텍스트에서 관리한 후 저장해야 할 필요가 있습니다.
또한, 아래와 같은 경우에도 코드에서 객체 상태를 변경 후 저장해야 합니다:
1. 복잡한 비즈니스 로직: 데이터베이스의 단일 연산으로 처리하기 어려운 복잡한 조건 및 비즈니스 로직이 필요한 경우.
2. 다른 필드와의 연관성 및 상태 변경: 업데이트 시 다른 필드나 연관된 엔티티의 상태에도 영향을 미쳐야 하는 경우. 예를 들어, 재고가 0이 될 때 delYn
필드를 true
로 설정해야 하는 경우.
관련된 질문들에서 유사한 고민을 다룬 예가 있어, 참고해볼 만한 링크를 제공드립니다:
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.