Skip to content

TECH TALK 7 BAZY DANYCH TRANSAKCJE BLOKADY

pawelkisielewicz edited this page Sep 21, 2018 · 14 revisions

Autocommit – domyślne zachowanie django. Każde zapytanie jest automatycznie commitowane do bazy danych

Transakcje – lista operacji na bazie danych, które mogą zostać zatwierdzone (wykonane) jedynie wszystkie lub żadna

Typowy sposób rozwiązywania konfliktów w django to zamykanie każdego widoku w transakcje. W tym celu należy ustawić ATOMIC_REQUESTS na True. Sposób działania transakcji:

  1. Widok/blok został wykonany bez błędów- django zatwierdza (commituje) transakcję i wszystkie zawarte

  2. Widok/blok podczas wykonywania rzucił exception- django anuluje transakcję i *cofa wszystkie zmiany wprowadzane do bazy danych (rollback). Uwaga na łapanie wyjątków w transakcjach

Transakcję można rozpocząć na 2 sposoby:

Transakcja jako dekorator:

from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()

Transakcja jako context manager:

from django.db import transaction

def viewfunc(request):
    # This code executes in autocommit mode (Django's default).
    do_stuff()

    **with transaction.atomic():**
        # This code executes inside a transaction.
        do_more_stuff()

Savepoints

  • Savepoint to marker miejsca w kodzie oznaczający miejsce, do którego w przypadku błędów wykonywany jest rollback. Można dzięki temu określić punkt, „mówiąc – do tego miejsca wszystko jest ok”. Rollback wykonywany jest tylko do tego miejsca, zamiast całej transakcji
  • Są obsługiwane przez SQLite, PostgreSQL, Oracle, and MySQL
  • Używane tylko w porzypadku transakcji, w domyślnym trybie autocommit nie mają sensu
  • Użycie zagnieżdżonego bloku atomowego powoduje stworzenie savepointu na jego początku.
  • Wg dokumentacji django, lepiej korzystać z savepointów poprzez korzystanie z bloków atomowych niż tworzenie ich bezpośrednio w kodzie

Zagnieżdżanie bloków atomowych

from django.db import IntegrityError, transaction

@transaction.atomic
def viewfunc(request):
    create_parent()
    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()
add_children()

W tle django wykonuje:

  • otwarcie transakcji przy wejściu do bloku atomowego
  • tworzy savepoint przy wejściu do wewnętrznego bloku
  • zwalnia savepoint lub rollback przy wyjściu z wewnętrznego bloku. Jeżeli poprawnie, całość wykonana „tak jakby nie było savepoint”
  • commit lub rollback całej, zewnętrznej transakcji

TransactionManagementError – rzucany przy próbie wywołań zapytań na bazie danych, gdy baza „uszkodzona” (przed rollback). W przykładzie handle_exception jest wywoływane już po rollback, baza jest „naprawiona”

Blokowanie bazy i wierszy

entries = Entry.objects.select_for_update().filter(author=request.user) Blokuje wszystkie zwracane rekordy do końca transakcji. Tylko zapytania od procesu, który założył blokadę są realizowane przez bazę danych.

select_for_update(nowait=False, skip_locked=False)

  • nowait = True – gdy wiersz zablokowany przez inną transakcję zgłasza błąd
  • nowait = False – gdy wiersz zablokowany przez inną transakcję czeka
  • skip_locked = True – pomija zablokowane wiersze

Select_for_update, delete (funkcje czekające na zwolnienie blokady) przy restarcie (po zwolnieniu blokady przez inny proces) wywołują jeszcze raz WHERE (SQL) i sprawdza, czy warunek filtrowania nadal jest spełniony. Jeżeli rekord został zmieniony i warunek WHERE nie jest już spełniony opełniony rekord nie jest pobierany i blokowany

Clone this wiki locally