get_or_create 메소드 설명
장고의 get_or_create 함수는 특정 kwargs로 데이터베이스 객체를 탐색하고 이를 불러오거나 존재하지 않는 경우 새롭게 생성하는 간편한 메소드입니다.
메소드 실행 결과 (object, created) 튜플이 반환됩니다. object는 불러온 객체이거나 생성된 객체이며, created는 불리언 값입니다.
이는 중복된 객체가 생성되는 것을 방지하고, 다음과 같은 로직을 한번에 처리할 수 있는 메소드입니다.
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
여기서 인식해야 하는 개념은 위의 요청이 동시에 발생할 시 동일한 파라미터로 Person을 저장하려는 시도가 이뤄지는 race conditon이 발생할 수 있다는 것입니다. get_or_create()를 사용하면 기본적으로 이러한 race condition을 방지할 수 있습니다.
obj, created = Person.objects.get_or_create(
first_name='John',
last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)},
)
레이스 컨디션 문제
앞서 get_or_create를 사용하면 race condition을 방지할 수 있다고 정리했습니다. 그러나 여기에는 데이터베이스 단에서 unique 또는 unique_together가 처리되어 있어야 한다는 전제가 있습니다. 그렇지 않은 경우, 메소드를 동시에 호출하면 동일한 파라미터를 가진 열이 중복해서 생성될 수 있습니다.
보다 정확하게는 unique 처리가 되지 않은 객체에서 하나의 스레드(탐색이 완료되고 아무런 결과가 리턴되지 않은 상황)를 통해 코드의 일부를 실행하는 중에 다른 스레드에서 객체가 생성될 경우 IntegrityError가 리턴되지 않아 두 개의 객체가 생성될 수 있습니다. 결론적으로 데이터베이스에는 두 개의 객체가 생성되는 의도치 않은 문제가 발생합니다.
따라서 데이터베이스 레벨에서 unique 제약이 추가되지 않은 객체에서는 get_or_create를 사용하지 않는 것이 좋습니다. 반대로, 이러한 제약이 추가되어 있다면 다수의 스레드를 통해 발생하는 race condition을 마주하지 않을 것이기 때문에 get_or_create를 사용하는 것이 더 좋을 수 있습니다.
참고 자료:
https://youngminz.netlify.app/posts/get-or-create-deadlock
https://adriennedomingus.medium.com/the-perils-of-get-or-create-race-conditions-485fc8fb2068
https://docs.djangoproject.com/en/4.0/ref/models/querysets/#get-or-create
'Django' 카테고리의 다른 글
| 장고 SECRET_KEY 관리 방법: 환경 변수와 로컬 파일 설정 (0) | 2022.03.13 |
|---|---|
| 장고 개발 환경에 따라 settings.py 분리하는 방법 (0) | 2022.03.13 |
| 장고 Q를 활용한 필터링, 정렬, 검색 방법 (0) | 2022.02.20 |
| 장고에서 HTTP GET, POST 요청 처리하는 방법 (0) | 2022.02.20 |
| 장고 ORM과 쿼리셋의 개념 (0) | 2022.02.07 |
