Метод select_for_update

Метод select_for_update применяется к QuerySet и возвращает новый QuerySet, строки которого будут заблокированы до конца транзакции. Это необходимо в ситуациях, когда несколько пользователей или процессов могут одновременно изменять одни и те же данные. Метод поддерживает параметры nowait и skip_locked для управления поведением при конфликтах блокировок.

Синтаксис

pythonModel.objects.select_for_update(nowait=False, skip_locked=False, of=(), no_key=False)

Пример

Заблокируем запись пользователя для обновления баланса внутри транзакции:

pythonfrom django.db import transaction
from myapp.models import User

with transaction.atomic():
  user = User.objects.select_for_update().get(id=1)
  user.balance += 100
  user.save()

Результат выполнения кода:

python"Balance updated successfully"

Пример

Используем параметр nowait чтобы не ждать освобождения заблокированной строки:

pythonfrom django.db import transaction
from myapp.models import Order

try:
  with transaction.atomic():
    order = Order.objects.select_for_update(nowait=True).get(id=5)
    order.status = 'processed'
    order.save()
except Exception as e:
  print(f"Order is locked: {e}")

Результат выполнения кода:

python"Order is locked: could not obtain lock"

Пример

Применяем блокировку к конкретным таблицам с помощью параметра of:

pythonfrom django.db import transaction
from myapp.models import Article, Category

with transaction.atomic():
  articles = Article.objects.select_for_update(
    of=('self', 'category')
  ).filter(status='draft')
  for article in articles:
    article.status = 'published'
    article.save()

Результат выполнения кода:

python"Articles updated with locks on related categories"

Смотрите также

  • метод filter,
    который фильтрует записи в QuerySet
  • метод get,
    который получает одну запись из базы данных
  • метод update,
    который обновляет записи в базе данных
  • метод atomic,
    который обеспечивает атомарность транзакций