Today I Learned
상품 주문 API를 단일 주문에서 다중 주문으로 바꾸면서 유효성 검사에 대한 고민이 있었다.
문제 상황
- 한개의 상품이라도 유효성 검사를 통과하지 못 할 경우(예 : 재고부족)
그 상품은 db에 저장이 되지 않지만 같이 주문건으로 들어온 order는 저장이 되고 있었음
만약 3만원 이상 무료배송인 경우가 있지만 재고부족으로 한 개의 상품이 주문이 안되고
나머지 주문건만 처리가 된다면 어지러운 상황이 발생할 것 같기 때문에
이 다중주문건에서 하나라도 유효성 검사를 통과하지 못한다면 모두 롤백시키고
모두 유효성검사를 통과한다면 모든 주문이 저장되게 하고 싶었다. .
시도
def post(self, request):
orders = request.data.get('orders', [])
valid_orders = []
for order_data in orders:
product_id = order_data.get('product')
product = get_object_or_404(ShopProduct, id=product_id)
serializer = OrderProductSerializer(data=order_data)
if serializer.is_valid():
valid_orders.append((serializer, product))
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
if len(valid_orders) == len(orders):
order_list = []
for serializer, product in valid_orders:
serializer.save(product=product)
order_list.append(serializer.data)
ShopOrder.objects.bulk_create(order_list)
return Response(order_list, status=status.HTTP_201_CREATED)
처음에는 단순히 valid에서 통과하면 append 시키고, len을 이용해 valid_orders와 orders의 값이 같다면 모든 주문의 유효성 검사가 통과한것이니 bulk_create로 처리하려 했지만
OrderProductSerializer의 create 메서드에서 유효성 검사가 통과된 주문건에 대한 저장을 하는 상태여서 소용이 없었다.
해결
def post(self, request):
orders = request.data.get('orders', [])
valid_orders = []
with transaction.atomic():
for order_data in orders:
product_id = order_data.get('product')
product = get_object_or_404(ShopProduct, id=product_id)
serializer = OrderProductSerializer(data=order_data)
if serializer.is_valid():
valid_orders.append((serializer, product))
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
order_list = []
for serializer, product in valid_orders:
serializer.save(product=product)
order_list.append(serializer.data)
return Response(order_list, status=status.HTTP_201_CREATED)
Django에서는 transaction.atomic() 데코레이터를 사용하여 트랜잭션을 처리
with transaction.atomic(): 문을 사용하여 시작, 유효성 검사 및 주문 저장 작업은 이 트랜잭션 범위 내에서 수행
트랜잭션을 사용하면 모든 주문에 대한 유효성 검사를 수행하는 동안 발생하는 DB작업은 트랜잭션에 포함되어있다가 유효성 검사를 통과하지 못했다면 다같이 롤백되고 모든 주문이 검사를 통과하였다면 함께 저장된다!
트랜잭션(Transaction)?
1) 여러 DB작업을 하나의 논리적 단위로 묶는 기능
2) 다중 주문에 대한 유효성 검사와 같은 작업을 원자적(atomic)으로 처리
=> 여기서 원자적, 원자성이란 트랜잭션 ACID특징 중 하나에 속하는 특성
트랜잭션 ACID 특성이란?
- Atomicity (원자성): 트랜잭션은"All or Nothing" 원칙을 따른다. 모든 작업이 완전히 수행되거나 전혀 수행되지 않아야 함
- Consistency (일관성): 트랜잭션 수행 전후에 데이터베이스는 일관된 상태여야할 것
- Isolation (고립성): 한 트랜잭션이 실행되는 동안 중간 결과가 다른 트랜잭션에 노출되지 않고 접근할 수 없어야함
- Durability (영구성): 트랜잭션이 성공적으로 완료되면 해당 변경 사항은 데이터베이스에 영구적으로 유지되어야 한다.
=> 완료 전에 컴퓨터의 전원이 꺼진다면 데이터는 Atomicity 원칙을 따라서 작업을 수행하기 이전 상태로 돌아간다.
위 예시코드에서도 ACID 특성을 기반으로 한 트랜잭션을 활용하여 주문 처리를 안전하고 일관된 상태로 유지하여 데이터 일관성과 안전성을 확보할 수 있다. ACID 특성을 기반으로 한 트랜잭션은 데이터베이스 시스템의 신뢰성을 높여준다!
'내일배움캠프 > 내일배움캠프 TIL' 카테고리의 다른 글
내일배움 캠프 TIL 80일차 - seattr(), getattr(), hasattr() (0) | 2023.07.03 |
---|---|
내일배움 캠프 TIL 78일차 - 젠킨스로 CI/CD 배포 환경 구축하기 02 (0) | 2023.07.03 |
내일배움 캠프 TIL 77일차 - 젠킨스로 CI/CD 배포 환경 구축하기 01 (0) | 2023.07.03 |
내일배움캠프 TIL 76일차 - KPT 중간 발표 회고록 (0) | 2023.06.26 |
내일배움캠프 TIL 75일차 (0) | 2023.06.25 |
Today I Learned
상품 주문 API를 단일 주문에서 다중 주문으로 바꾸면서 유효성 검사에 대한 고민이 있었다.
문제 상황
- 한개의 상품이라도 유효성 검사를 통과하지 못 할 경우(예 : 재고부족)
그 상품은 db에 저장이 되지 않지만 같이 주문건으로 들어온 order는 저장이 되고 있었음
만약 3만원 이상 무료배송인 경우가 있지만 재고부족으로 한 개의 상품이 주문이 안되고
나머지 주문건만 처리가 된다면 어지러운 상황이 발생할 것 같기 때문에
이 다중주문건에서 하나라도 유효성 검사를 통과하지 못한다면 모두 롤백시키고
모두 유효성검사를 통과한다면 모든 주문이 저장되게 하고 싶었다. .
시도
def post(self, request):
orders = request.data.get('orders', [])
valid_orders = []
for order_data in orders:
product_id = order_data.get('product')
product = get_object_or_404(ShopProduct, id=product_id)
serializer = OrderProductSerializer(data=order_data)
if serializer.is_valid():
valid_orders.append((serializer, product))
else:
print(serializer.errors)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
if len(valid_orders) == len(orders):
order_list = []
for serializer, product in valid_orders:
serializer.save(product=product)
order_list.append(serializer.data)
ShopOrder.objects.bulk_create(order_list)
return Response(order_list, status=status.HTTP_201_CREATED)
처음에는 단순히 valid에서 통과하면 append 시키고, len을 이용해 valid_orders와 orders의 값이 같다면 모든 주문의 유효성 검사가 통과한것이니 bulk_create로 처리하려 했지만
OrderProductSerializer의 create 메서드에서 유효성 검사가 통과된 주문건에 대한 저장을 하는 상태여서 소용이 없었다.
해결
def post(self, request):
orders = request.data.get('orders', [])
valid_orders = []
with transaction.atomic():
for order_data in orders:
product_id = order_data.get('product')
product = get_object_or_404(ShopProduct, id=product_id)
serializer = OrderProductSerializer(data=order_data)
if serializer.is_valid():
valid_orders.append((serializer, product))
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
order_list = []
for serializer, product in valid_orders:
serializer.save(product=product)
order_list.append(serializer.data)
return Response(order_list, status=status.HTTP_201_CREATED)
Django에서는 transaction.atomic() 데코레이터를 사용하여 트랜잭션을 처리
with transaction.atomic(): 문을 사용하여 시작, 유효성 검사 및 주문 저장 작업은 이 트랜잭션 범위 내에서 수행
트랜잭션을 사용하면 모든 주문에 대한 유효성 검사를 수행하는 동안 발생하는 DB작업은 트랜잭션에 포함되어있다가 유효성 검사를 통과하지 못했다면 다같이 롤백되고 모든 주문이 검사를 통과하였다면 함께 저장된다!
트랜잭션(Transaction)?
1) 여러 DB작업을 하나의 논리적 단위로 묶는 기능
2) 다중 주문에 대한 유효성 검사와 같은 작업을 원자적(atomic)으로 처리
=> 여기서 원자적, 원자성이란 트랜잭션 ACID특징 중 하나에 속하는 특성
트랜잭션 ACID 특성이란?
- Atomicity (원자성): 트랜잭션은"All or Nothing" 원칙을 따른다. 모든 작업이 완전히 수행되거나 전혀 수행되지 않아야 함
- Consistency (일관성): 트랜잭션 수행 전후에 데이터베이스는 일관된 상태여야할 것
- Isolation (고립성): 한 트랜잭션이 실행되는 동안 중간 결과가 다른 트랜잭션에 노출되지 않고 접근할 수 없어야함
- Durability (영구성): 트랜잭션이 성공적으로 완료되면 해당 변경 사항은 데이터베이스에 영구적으로 유지되어야 한다.
=> 완료 전에 컴퓨터의 전원이 꺼진다면 데이터는 Atomicity 원칙을 따라서 작업을 수행하기 이전 상태로 돌아간다.
위 예시코드에서도 ACID 특성을 기반으로 한 트랜잭션을 활용하여 주문 처리를 안전하고 일관된 상태로 유지하여 데이터 일관성과 안전성을 확보할 수 있다. ACID 특성을 기반으로 한 트랜잭션은 데이터베이스 시스템의 신뢰성을 높여준다!
'내일배움캠프 > 내일배움캠프 TIL' 카테고리의 다른 글
내일배움 캠프 TIL 80일차 - seattr(), getattr(), hasattr() (0) | 2023.07.03 |
---|---|
내일배움 캠프 TIL 78일차 - 젠킨스로 CI/CD 배포 환경 구축하기 02 (0) | 2023.07.03 |
내일배움 캠프 TIL 77일차 - 젠킨스로 CI/CD 배포 환경 구축하기 01 (0) | 2023.07.03 |
내일배움캠프 TIL 76일차 - KPT 중간 발표 회고록 (0) | 2023.06.26 |
내일배움캠프 TIL 75일차 (0) | 2023.06.25 |