Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a cikk bemutatja, hogyan konfigurálhatja a tranzakciókezelési és elkülönítési szinteket a Django-alkalmazásokhoz a háttérrendszer és a mssql-django SQL Server használatával.
Alapértelmezett viselkedés
Alapértelmezés szerint a Django autocommit módban működik. Minden adatbázis-lekérdezés a saját tranzakciójában fut, és azonnal véglegesítése történik. Ezt a viselkedést a beállítással vagy a AUTOCOMMIT Django tranzakciókezelési API-jával módosíthatja.
AUTOCOMMIT beállítás
Állítsa a(z) AUTOCOMMIT értékét False értékre az adatbázis-konfigurációban az autocommit mód kikapcsolásához:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<your-username>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>",
"PORT": "1433",
"AUTOCOMMIT": False,
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
Note
Az automatikus kiküldés letiltása azt jelenti, hogy kifejezetten véglegesítenie vagy vissza kell állítania a tranzakciókat. A legtöbb Django-alkalmazás engedélyezi az automatikus kommunikációt, és adott műveletekhez használja transaction.atomic() .
A transaction.atomic() használata
Foglalja az adatbázisműveleteket a(z) transaction.atomic() elembe, hogy azok egyetlen tranzakción belül hajtódjanak végre:
from django.db import transaction
from myapp.models import Account
def transfer_funds(from_account_id, to_account_id, amount):
with transaction.atomic():
sender = Account.objects.select_for_update().get(pk=from_account_id)
receiver = Account.objects.select_for_update().get(pk=to_account_id)
sender.balance -= amount
receiver.balance += amount
sender.save()
receiver.save()
Ha kivétel történik egy atomic() blokkon belül, a rendszer visszaállítja a teljes tranzakciót.
Beágyazott tranzakciók
A Django az SQL Server mentési pontjai révén támogatja a beágyazott atomic() blokkokat:
from django.db import transaction
with transaction.atomic():
# Outer transaction
Product.objects.create(name="Widget A", price=9.99)
try:
with transaction.atomic():
# Inner savepoint
Product.objects.create(name="Widget B", price=14.99)
raise ValueError("Simulated error")
except ValueError:
pass # Inner savepoint is rolled back, outer continues
# Widget A is committed, Widget B is not
Tranzakciós izolációs szintek
Állítsa be a tranzakciók elkülönítési szintjét az adatbázis konfigurációjában található isolation_level beállítással:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<your-username>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"isolation_level": "READ COMMITTED",
},
},
}
Támogatott elkülönítési szintek
| Elkülönítési szint | Description |
|---|---|
READ UNCOMMITTED |
Engedélyezi a piszkos olvasást. Legalacsonyabb elkülönítés, legmagasabb egyidejűség. |
READ COMMITTED |
SQL Server alapértelmezett érték. Megakadályozza a piszkos olvasásokat. |
REPEATABLE READ |
Megakadályozza a piszkos és nem ismételhető olvasásokat. |
SNAPSHOT |
A konzisztens olvasás érdekében sorverziókezelést használ blokkolás nélkül. Az adatbázisszintű pillanatkép-elkülönítés engedélyezését igényli. |
SERIALIZABLE |
A legnagyobb elszigeteltség. Megakadályozza a fantomolvasást. |
A SNAPSHOT elkülönítésének engedélyezése
Az elkülönítés használatához SNAPSHOT először engedélyezze az adatbázisban:
ALTER DATABASE [<your-database>]
SET ALLOW_SNAPSHOT_ISOLATION ON;
Ezután konfigurálja itt: settings.py:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<your-username>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"isolation_level": "SNAPSHOT",
},
},
}
Használja a(z) @transaction.atomic dekorátort
Tranzakciók alkalmazása teljes nézetfüggvényekre:
from django.db import transaction
from django.http import JsonResponse
@transaction.atomic
def create_order(request):
# All database operations in this view run in a single transaction
order = Order.objects.create(customer_id=request.user.id)
for item in request.POST.getlist("items"):
OrderItem.objects.create(order=order, product_id=item)
return JsonResponse({"order_id": order.pk})
Adatok olvasása blokkolás nélkül (NOLOCK-ekvivalens)
Gyakori kérés, hogy a SQL Servert a NOLOCK hinttel vagy READ UNCOMMITTED izolációs szinttel kérdezzék le, hogy elkerüljék a blokkolást a nagy terhelésű táblák esetén. A Django ORM-je nem hoz létre táblázatos tippeket, de két lehetősége van.
1. lehetőség: A READ UNCOMMITTED beállítása kapcsolatonként
Állítsa be az elkülönítési szintet a dedikált, csak olvasható adatbázisálneven READ UNCOMMITTED értékre, hogy az az adott kapcsolaton futó összes lekérdezésre érvényes legyen:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
"read_uncommitted": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"isolation_level": "READ UNCOMMITTED",
},
},
}
Ezután a lekérdezések átirányítása az read_uncommitted aliashoz:
# Read with NOLOCK-equivalent behavior
products = Product.objects.using("read_uncommitted").filter(active=True)
# Writes still go through the default connection
Product.objects.create(name="Widget", price=9.99)
2. lehetőség: Nyers SQL használata a NOLOCK használatával
Adott táblák célzott lekérdezéseihez használja a nyers SQL-t a NOLOCK táblamutatóval:
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT id, name, price FROM myapp_product WITH (NOLOCK) WHERE active = %s", [1])
rows = cursor.fetchall()
Caution
A(z) READ UNCOMMITTED és a(z) NOLOCK is lehetővé teszi a piszkos olvasást, ami azt jelenti, hogy a lekérdezések nem véglegesített tranzakciókból származó adatokat is visszaadhatnak. Ezeket a technikákat csak olyan jelentéskészítési vagy elemzési lekérdezésekhez használja, ahol nincs szükség abszolút konzisztenciára.
3. lehetőség: helyette használjon SNAPSHOT izolációt
SNAPSHOT az elkülönítés konzisztens olvasást biztosít blokkolás és piszkos olvasások nélkül. A legtöbb számítási feladat esetében ez az ajánlott alternatíva a NOLOCK helyett:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"isolation_level": "SNAPSHOT",
},
},
}
SNAPSHOT adatbázisszintű konfigurációt igényel. Lásd A SNAPSHOT-izoláció engedélyezése.
Sorszintű zárolás a select_for_update() használatával
A Django-t select_for_update() teljes mértékben támogatja a mssql-django háttérrendszer. SQL Server ezt a más adatbázisok által használt záradék helyett FOR UPDATE táblázatos tippek használatával valósítja meg.
Alapszintű használat
from django.db import transaction
with transaction.atomic():
product = Product.objects.select_for_update().get(pk=1)
product.stock -= 1
product.save()
A háttérrendszer a következőt hozza létre: SELECT ... FROM [myapp_product] WITH (ROWLOCK, UPDLOCK) WHERE ...
NOWAIT és SKIP LOCKED
A nowait paraméterek és skip_locked a paraméterek egyaránt támogatottak:
from django.db import transaction
# Raise DatabaseError immediately if the row is already locked
with transaction.atomic():
product = Product.objects.select_for_update(nowait=True).get(pk=1)
# Skip rows that are locked by other transactions
with transaction.atomic():
available = Product.objects.select_for_update(skip_locked=True).filter(
reserved=False
)[:10]
| Paraméter | SQL Server-táblamutató |
|---|---|
| Alapértelmezett | WITH (ROWLOCK, UPDLOCK) |
nowait=True |
WITH (NOWAIT, ROWLOCK, UPDLOCK) |
skip_locked=True |
WITH (ROWLOCK, UPDLOCK, READPAST) |
Note
A(z) select_for_update() elemet egy transaction.atomic() blokkon belül kell használni. A Django hibát jelez, ha egy tranzakción kívül hívja meg.
Különbségek a PostgreSQL-től
- A
ofparaméter (select_for_update(of=(...))) nem támogatott. A háttérrendszerNotSupportedErrorhibát dob, ha átadja. - SQL Server sorszintű
UPDLOCKzáradékok helyett táblázatszintű tippeket (FOR UPDATE) használ. Nagy versengés esetén a zárolás eszkalációja több sort vagy oldalt zárolhat, mint a cél. ASNAPSHOTelkülönítési szintet akkor használja, ha blokkolásmentes olvasásokra van szüksége a zárolt írási műveletek mellett.