2017-04-28 14 views
5

Hãy tưởng tượng bạn có một bảng đơn giản với công việc mục:Nhận tới công việc mục trong Django với PostgreSQL

|ID |OWNER|... 
+---+-----+--- 
|123|  |... 
|456|  |... 
|789|  |... 

Chúng tôi muốn cung cấp một API http để có được những công việc mục tiếp theo mà không có chủ sở hữu chưa.

Chúng tôi sử dụng PostgreSQL.

Chúng tôi truy cập bảng bằng Django-ORM.

Tôi đoán có một số điều kiện chủng tộc nếu API được nhiều người dùng truy cập đồng thời.

Làm thế nào tôi có thể đảm bảo với các công cụ đã cho (PostgreSQL, Django) rằng tất cả các điều kiện cuộc đua được giải quyết (đó là một lỗi lớn nếu một mục công việc được trao cho hai người dùng nhiều hơn).

Trả lời

2

Với Django 1.11, select_for_update bắt đầu hỗ trợ skip_locked. Điều này có nghĩa là bạn có thể lưu trên save() cuộc gọi vì bạn không phải chỉ định cuộc gọi đó cho chủ sở hữu ngay lập tức.

Ví dụ, xây dựng trên câu trả lời @ user73657 của:

with transaction.atomic(): 
    work_item = WorkItem.objects.select_for_update().filter(owner__isnull=True).first() 
    work_item.owner = request.user 
    work_item.save(update_fields=['owner']) 

# process work_item 

bạn có thể làm:

with transaction.atomic(): 
    work_item = WorkItem.objects.select_for_update(skip_locked=True).filter(owner__isnull=True).first() 
    work_item.owner = request.user 
    # process work_item, edit other fields 
    work_item.save() 

Với skip_locked=True, giao dịch sẽ bỏ qua hàng bị khóa, và do đó là non-blocking. Là phần thưởng, bạn chỉ cần lưu vào db sau khi.

+1

wow, 'SKIP LOCKED' có vẻ tốt. Tôi tìm thấy bài đăng này: https://blog.2ndquadrant.com/what-is-select-skip-locked-for-in-postgresql-9-5/ giải thích chi tiết. – guettli

1

Với select_for_update:

with transaction.atomic(): 
    work_item = WorkItem.objects.select_for_update().filter(owner__isnull=True).first() 
    work_item.owner = request.user 
    work_item.save(update_fields=['owner']) 

# process work_item 

https://docs.djangoproject.com/en/1.11/ref/models/querysets/#select-for-update

select_for_update sẽ đảm bảo rằng chỉ có một kết nối có thể cập nhật các hàng kết hợp đến khi giao dịch đã kết thúc.

Các vấn đề liên quan