Проблемы параллелизма базы данных Django

У меня есть «один» метод в веб-API, который делает два вызова базы данных.

  1. Убедитесь, что с помощью count() определенных объектов не существует
  2. Сохраните объект, если он еще не существует

Логика здесь явно не в сохранении объекта, если он уже существует. Довольно просто. Проблема возникает, когда в таблице БД начинают появляться дублированные объекты. Затем я понял, что не могу контролировать плохие вызовы клиентов (одновременно повторяющиеся вызовы).

Таким образом, проблема возникает, когда второй вызов этого метода происходит точно между блоками кода 1) и 2) с теми же параметрами (тот же объект):

  1. Вызов 1 => count() == 0
  2. Вызов 2 => count() == 0 (это 0, потому что первый вызов не закончил обработку и сохранение объекта в этот момент)
  3. Вызов 1 => сохраняет объект
  4. Вызов 2 => сохраняет объект, потому что count() == 0

Неверный результат => в моей таблице есть две строки с одинаковыми значениями

Поэтому мне нужно не обрабатывать «Вызов 2», пока не завершится кодовый блок «Вызов 1».

Я много занимался этим. Вариантом может быть блокировка таблицы, которую я запрашиваю, до тех пор, пока метод не завершит выполнение (но это может привести к новым проблемам в уравнении).

Другие люди говорят об использовании атомарных транзакций, но я не вижу, как это может помочь, если в то же время выполняется другой вызов.

Другим возможным решением было бы использование unique_together, поэтому невозможно создать две строки с одинаковыми значениями (я начинаю думать, что это будет лучший вариант)

Я потерялся в глуши, пытаясь понять, как это исправить. Учитывая, что эту проблему трудно проверить, я подумал сначала спросить здесь. Может быть, я просто упускаю что-то очевидно простое...

Просто чтобы уточнить, вот как я узнаю, существует ли уже объект:

    # return error if the follow is already done
    current_follow_query = request.user.follows.filter(influencer=influencer)
    if current_follow_query.count() > 0:
        return Response(status=status.HTTP_204_NO_CONTENT)

    # save the actual follow object
    obj = Follow(follower=request.user, influencer=influencer)
    obj.save()

Любые идеи?


person xleon    schedule 15.08.2015    source источник
comment
Как узнать, что объект уже существует?   -  person spectras    schedule 15.08.2015
comment
Привет @spectras. Я отредактировал вопрос с образцом кода.   -  person xleon    schedule 15.08.2015
comment
Так что, по сути, вы знаете, что это один и тот же объект, потому что follow.influencer и follow.follower — это одно и то же. Тогда да, это означает, что они уникальны вместе.   -  person spectras    schedule 15.08.2015
comment
точно, просто проверив эти два свойства. Итак, вы думаете, что unique_together — правильное решение?   -  person xleon    schedule 15.08.2015
comment
Это и есть его цель, да.   -  person spectras    schedule 15.08.2015
comment
тогда попробую, спасибо!   -  person xleon    schedule 15.08.2015


Ответы (1)


Итак, поскольку вы определяете личность двумя полями influencer и follower, они должны быть уникальными. Просто сообщите об этом базе данных, используя ограничение unique_together = [('influencer', 'follower')].

Теперь для сохранения вы захотите полагаться на базу данных для выполнения этого теста: просто сохраняйте все время и обрабатывайте ошибки, когда они возникают.

from django.db import IntegrityError

try:
    obj = Follow.objects.create(follower=request.user, influencer=influencer)
except IntegrityError:
    # the object already existed!
else:
    # the object was successfully created!
person spectras    schedule 15.08.2015