ExpressionWrapper
ExpressionWrapper surrounds another expression and provides access to properties, such as output_field, that may not be available on other expressions. ExpressionWrapper is necessary when using arithmetic on F() expressions with different types as described in Using F() with annotations.
from django.db.models import DateTimeField, ExpressionWrapper, F
Ticket.objects.annotate(
expires=ExpressionWrapper(
F("active_at") + F("duration"), output_field=DateTimeField()
)
)
property로 선언되어 있는 경우는 사용 불가능함
CheckConstraint
- foreignkey referenced 안됨
select_for_update
https://velog.io/@combi_jihoon/Django-selectforupdate
Parameters
skip_locked- True로 설정하면 락이 걸린 rows는 넘어가고 락이 걸리지 않은 rows를 찾는다.
nowait- True인 경우 락이 걸린 트랜잭션이 끝날 때까지 기다리지 않고 바로 DatabaseError를 뱉어 낸다.
- False인 경우 해당 row에 락이 걸린 트랜잭션이 끝날 때까지 기다렸다가 끝나면 작업을 진행한다.
추가 옵션
of- 기본적으로
select_for_update()는 조회하는 모든 쿼리에 락을 잡는다. 따라서 select시 참조하는 모든 모델에 락을 잡는다. 그런데 만약 이러한 상황을 원하지 않는다면of옵션을 이용해 원하는 objects를 지정해 지정된 objects만 락을 잡도록 설정할 수 있다. - self로 지정할 경우 자기 자신만 조회하도록 한다.
- 기본적으로
주의 사항
-
transaction.atomic() 블럭 안에서
select_for_update()를 사용해야 한다.- 그렇지 않으면
select_for_update()는 작동하지 않는다. - 이 블럭 안에 있으면 트랜잭션 블럭이 끝나기 전까지 블럭 안에서 조회한 쿼리에 락이 잡히게 된다. 따라서, 다른 트랜잭션은 이 트랜잭션을 획득하거나 변화를 줄 수 없다.
- 그렇지 않으면
-
skip_locked옵션과nowait옵션은 상호 배타적인 관계로, 만약 두 옵션을 모두 사용하게 되면 ValueError가 발생 한다. -
select_for_update()는 null을 참조하는 경우에는 사용할 수 없다.- 따라서, 이런 경우 exclude를 이용해 None인 경우를 제외하고 사용해야 한다.
Person.objects.select_related('hometown').select_for_update().exclude(hometown=None)
- 따라서, 이런 경우 exclude를 이용해 None인 경우를 제외하고 사용해야 한다.
-
select_for_update()는 eager loading을 한다.- 개발 하면서 알게 된 내용으로,
select_for_update()사용시 where 조건을 걸어 특정 유저 혹은 id에 대한 쿼리를 실행하지 않으면 해당 테이블 전체에 락을 잡아 앱의 성능이 매우 느려지는 이슈가 발생한다. - 아마도
select_for_update()는 기존의select쿼리와 달리 db를 바로 조회하는 것 같다. - 따라서, 아래와 같이 사용해야 한다.
- 개발 하면서 알게 된 내용으로,
https://youngminz.netlify.app/posts/get-or-create-deadlock
참고
SELECT FOR UPDATE는 행 수준 잠금을 획득한다 SELECT FOR UPDATE는 Read-Modify-Write 패턴에서만 필요하다 django orm은 thread-safe 하다