Как я могу обрабатывать несколько запросов одновременно в Django?

#python #django #sqlite #django-models

Вопрос:

В настоящее время я пишу API, в котором пользователь может переводить деньги со своего аккаунта на телефон, но я сталкиваюсь с проблемой, которая заключается в том, что пользователь может позвонить в API несколько раз одновременно и попросить перевести деньги. Обычно баланс его счета был бы неправильным после звонков, поэтому я много искал и выяснил, что могу использовать атомарные транзакции и блокировать базу данных. Теперь, если пользователь использует API, например, дважды, один из них работает правильно, но другой получает django.db.utils.OperationalError: database is locked ошибку. Есть идеи, как я могу правильно обращаться с ними обоими? (Я мог бы использоватьпока и подождите, пока база данных не будет разблокирована, но я предпочел бы этого не делать)

models.py

 @transaction.atomic()
    def withdraw(self, amount, phone, username):
        property = transferLog.objects.filter(username=username).order_by('-time').select_for_update()[0]
        if property.property >= int(amount):
            self.username = username
            self.property = property.property - int(amount)
            self._from = username
            self._to = phone
            self.amount = int(amount)
            self.time = str(datetime.datetime.now())
            self.save()
            return {'result': 'success', 'message': 'transfer complete', 'remaining': self.property}
        else:
            return {'result': 'error', 'message': 'not enough money'}
 

Комментарии:

1. Вероятно, вам следует перейти с SQLite на другого поставщика баз данных, например PostgreSQL. SQLite не поддерживает очень высокий уровень параллелизма,

2. Да, я изменил базу данных, и это сработало. Спасибо!

Ответ №1:

Я предполагаю, что вы используете базу данных SQLite. Он не допускает одновременной записи, т. е. более одной операции записи в данный момент времени.

У вас есть варианты:

  1. Либо переключитесь на другую базу данных
  2. Или увеличьте параметр базы timeout данных в настройках

Пример:

 # settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'db.sqlite3',
        'OPTIONS': {
            'timeout': 60, # 1 minute
        }
    }
}
 

Это не масштабируемое решение. Предположим, что у вас есть много процессов, ожидающих доступа на запись, вы все еще можете получить OperationalError , если какие-либо процессы все еще ждут через 60 секунд.

Комментарии:

1. Я увеличил время ожидания. Ошибка исчезла, но баланс не изменился. Я думаю, что мне следует перейти на PostgreSQL.

2. @Mfr Трудно сказать. Вы пытались отладить код? Работает ли он так, как ожидалось? Но да, если ваш проект требует одновременной записи, то лучше отказаться от SQLite.

3. да, я отлаживаю его часами 🙂 Вы правы, SQLite мне не подходит. Все равно спасибо!