想象一下您有一个带有工作项目的简单表:
|ID |OWNER|...
+---+-----+---
|123| |...
|456| |...
|789| |...
我们想提供HTTP API,以获取尚未拥有所有者的下一个工作项目。
我们使用postgresql。
我们使用django-orm访问表。
我想如果许多用户同时获得API,则有几个种族条件。
我如何确保给定工具(PostgreSQL,django(都解决了所有种族条件(如果给出两个矿石的用户,这是一个主要错误(。
带有django 1.11,select_for_update开始支持 skip_locked
。这意味着您可以保存save()
调用,因为您不必立即将其分配给所有者。
例如,在 @user73657的答案上构建:
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
您可以做:
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()
使用skip_locked=True
,交易跳过了锁定的行,因此是非障碍物。作为奖励,您只需要保存到db 。
with 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-pordate
select_for_update
将确保只有一个连接可以更新匹配行,直到交易结束为止。