Позвольте мне объяснить мою конкретную ситуацию:
Бизнес может выбрать район, в котором он находится, эта опция сохраняется в БД, при сохранении этих объектов подается сигнал. Метод прослушивает этот сигнал и должен только один раз обновить всех других пользователей, которые также следуют этому соседству. В этом методе выполняется проверка, пытающаяся проверить, следует ли любому другому пользователю уже следовать этому бизнесу, для каждого пользователя, который не следует этому бизнесу, но следует по этому соседству, в БД будет создано следующее отношение. Все должно быть хорошо, если пользователь уже следит за этим бизнесом, то никакого отношения не установлено ...
Но что радует, так это то, что иногда две или более из этих транзакций происходят одновременно, и все они, конечно, проверяют, следует ли пользователю следовать этому бизнесу, поскольку ни одна из них не может видеть последующую связь между пользователем и бизнес, множественные последующие отношения теперь установлены.
Я пытался убедиться, что сигнал не отправляется несколько раз, но я не уверен, почему эти несколько транзакций происходят одновременно.
Хотя я нашел некоторые ответы на вопрос о блокировке строк при попытке избежать проблем с параллелизмом при обновлении, я затрудняюсь с тем, как обеспечить выполнение только одной вставки.
Является ли блокировка таблицы единственным способом, гарантирующим, что произойдет только одна вставка?
# when a business updates their neighborhood, this sets the follow relationship
def follow_biz(sender, instance, created, **kwargs):
if instance.neighborhood:
neighborhood_followers = FollowNeighborhood.objects.filter(neighborhood=instance.neighborhood)
# print 'INSTANCE Neighborhood %s ' % instance.neighborhood
for follower in neighborhood_followers:
if not Follow.objects.filter(user=follower.user, business=instance).count():
follow = Follow(business=instance, user=follower.user)
follow.save()
# a unique static string to prevent signal from being called twice
follow_biz_signal_uid = hashlib.sha224("follow_biz").hexdigest()
# signal
post_save.connect(follow_biz, sender=Business, dispatch_uid=follow_biz_signal_uid)